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

b43: Fix DMA mapping leakage

This fixes a DMA mapping leakage in the case where we reject a DMA
buffer because of its address.
Signed-off-by: default avatarMichael Buesch <mb@bu3sch.de>
Cc: Christian Casteyde <casteyde.christian@free.fr>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent c83dbf68
...@@ -560,7 +560,7 @@ static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, ...@@ -560,7 +560,7 @@ static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base,
/* Check if a DMA mapping address is invalid. */ /* Check if a DMA mapping address is invalid. */
static bool b43_dma_mapping_error(struct b43_dmaring *ring, static bool b43_dma_mapping_error(struct b43_dmaring *ring,
dma_addr_t addr, dma_addr_t addr,
size_t buffersize) size_t buffersize, bool dma_to_device)
{ {
if (unlikely(dma_mapping_error(addr))) if (unlikely(dma_mapping_error(addr)))
return 1; return 1;
...@@ -568,11 +568,11 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring, ...@@ -568,11 +568,11 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
switch (ring->type) { switch (ring->type) {
case B43_DMA_30BIT: case B43_DMA_30BIT:
if ((u64)addr + buffersize > (1ULL << 30)) if ((u64)addr + buffersize > (1ULL << 30))
return 1; goto address_error;
break; break;
case B43_DMA_32BIT: case B43_DMA_32BIT:
if ((u64)addr + buffersize > (1ULL << 32)) if ((u64)addr + buffersize > (1ULL << 32))
return 1; goto address_error;
break; break;
case B43_DMA_64BIT: case B43_DMA_64BIT:
/* Currently we can't have addresses beyond /* Currently we can't have addresses beyond
...@@ -582,6 +582,12 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring, ...@@ -582,6 +582,12 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
/* The address is OK. */ /* The address is OK. */
return 0; return 0;
address_error:
/* We can't support this address. Unmap it again. */
unmap_descbuffer(ring, addr, buffersize, dma_to_device);
return 1;
} }
static int setup_rx_descbuffer(struct b43_dmaring *ring, static int setup_rx_descbuffer(struct b43_dmaring *ring,
...@@ -599,7 +605,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, ...@@ -599,7 +605,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
if (unlikely(!skb)) if (unlikely(!skb))
return -ENOMEM; return -ENOMEM;
dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) { if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) {
/* ugh. try to realloc in zone_dma */ /* ugh. try to realloc in zone_dma */
gfp_flags |= GFP_DMA; gfp_flags |= GFP_DMA;
...@@ -612,7 +618,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, ...@@ -612,7 +618,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
ring->rx_buffersize, 0); ring->rx_buffersize, 0);
} }
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) { if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
return -EIO; return -EIO;
} }
...@@ -852,7 +858,8 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, ...@@ -852,7 +858,8 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
b43_txhdr_size(dev), b43_txhdr_size(dev),
DMA_TO_DEVICE); DMA_TO_DEVICE);
if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev))) { if (b43_dma_mapping_error(ring, dma_test,
b43_txhdr_size(dev), 1)) {
/* ugh realloc */ /* ugh realloc */
kfree(ring->txhdr_cache); kfree(ring->txhdr_cache);
ring->txhdr_cache = kcalloc(nr_slots, ring->txhdr_cache = kcalloc(nr_slots,
...@@ -867,7 +874,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, ...@@ -867,7 +874,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
DMA_TO_DEVICE); DMA_TO_DEVICE);
if (b43_dma_mapping_error(ring, dma_test, if (b43_dma_mapping_error(ring, dma_test,
b43_txhdr_size(dev))) b43_txhdr_size(dev), 1))
goto err_kfree_txhdr_cache; goto err_kfree_txhdr_cache;
} }
...@@ -1189,7 +1196,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ...@@ -1189,7 +1196,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
hdrsize, 1); hdrsize, 1);
if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize)) { if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize, 1)) {
ring->current_slot = old_top_slot; ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots; ring->used_slots = old_used_slots;
return -EIO; return -EIO;
...@@ -1208,7 +1215,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ...@@ -1208,7 +1215,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
/* create a bounce buffer in zone_dma on mapping failure. */ /* create a bounce buffer in zone_dma on mapping failure. */
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) { if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
if (!bounce_skb) { if (!bounce_skb) {
ring->current_slot = old_top_slot; ring->current_slot = old_top_slot;
...@@ -1222,7 +1229,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ...@@ -1222,7 +1229,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
skb = bounce_skb; 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)) { if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
ring->current_slot = old_top_slot; ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots; ring->used_slots = old_used_slots;
err = -EIO; err = -EIO;
......
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