Commit 9a3f4511 authored by Michael Buesch's avatar Michael Buesch Committed by John W. Linville

b43: Fix DMA TX bounce buffer copying

b43 allocates a bouncebuffer, if the supplied TX skb is in an invalid
memory range for DMA.
However, this is broken in that it fails to copy over some metadata to the
new skb.

This patch fixes three problems:
* Failure to adjust the ieee80211_tx_info pointer to the new buffer.
  This results in a kmemcheck warning.
* Failure to copy the skb cb, which contains ieee80211_tx_info, to the new skb.
  This results in breakage of various TX-status postprocessing (Rate control).
* Failure to transfer the queue mapping.
  This results in the wrong queue being stopped on saturation and can result in queue overflow.
Signed-off-by: default avatarMichael Buesch <mb@bu3sch.de>
Tested-by: default avatarChristian Casteyde <casteyde.christian@free.fr>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent f446d10f
...@@ -1157,8 +1157,9 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) ...@@ -1157,8 +1157,9 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
} }
static int dma_tx_fragment(struct b43_dmaring *ring, static int dma_tx_fragment(struct b43_dmaring *ring,
struct sk_buff *skb) struct sk_buff **in_skb)
{ {
struct sk_buff *skb = *in_skb;
const struct b43_dma_ops *ops = ring->ops; const struct b43_dma_ops *ops = ring->ops;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 *header; u8 *header;
...@@ -1224,8 +1225,14 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ...@@ -1224,8 +1225,14 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
} }
memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb));
bounce_skb->dev = skb->dev;
skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb));
info = IEEE80211_SKB_CB(bounce_skb);
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
skb = bounce_skb; skb = bounce_skb;
*in_skb = bounce_skb;
meta->skb = skb; meta->skb = skb;
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
...@@ -1355,7 +1362,11 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) ...@@ -1355,7 +1362,11 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
* static, so we don't need to store it per frame. */ * static, so we don't need to store it per frame. */
ring->queue_prio = skb_get_queue_mapping(skb); ring->queue_prio = skb_get_queue_mapping(skb);
err = dma_tx_fragment(ring, skb); /* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing
* into the skb data or cb now. */
hdr = NULL;
info = NULL;
err = dma_tx_fragment(ring, &skb);
if (unlikely(err == -ENOKEY)) { if (unlikely(err == -ENOKEY)) {
/* Drop this packet, as we don't have the encryption key /* Drop this packet, as we don't have the encryption key
* anymore and must not transmit it unencrypted. */ * anymore and must not transmit it unencrypted. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment