diff options
author | Pete Zaitcev <zaitcev@redhat.com> | 2006-03-06 19:37:51 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2006-03-27 11:19:33 -0500 |
commit | 512a80916b8d04529c0915534c63529144f74e10 (patch) | |
tree | 34531295df7a1aa990e268bf6b29bf0f16c507ef /drivers/net | |
parent | 367f899ac3b52cf4611cd291ec2bfbf774b15bc7 (diff) |
[PATCH] bcm43xx: fix DMA TX skb freeing in case of fragmented packets.
It seems to me that the today's wireless-2.6 git contains bcm43xx which
does not free txb's correctly, if I understand it right.
Consider a situation where a txb with two skb's is sent down.
The dma_tx_fragment will save the pointer to meta->txb of the first
fragment. If fragments are freed in order, ieee80211_txb_free frees both
skb's when the first fragment is processed. This may result in reuse
of the second skb's memory.
This danger is rather remote, but it seems to me that the patch
below not only fixes the problem, but also makes the code simpler,
which is good, right?
Signed-off-by: Michael Buesch <mbuesch@freenet.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 44 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 4 |
2 files changed, 8 insertions, 40 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index e20fbaf29e0b..0cd292847954 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c | |||
@@ -170,19 +170,6 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring, | |||
170 | addr, len, DMA_FROM_DEVICE); | 170 | addr, len, DMA_FROM_DEVICE); |
171 | } | 171 | } |
172 | 172 | ||
173 | static inline | ||
174 | void mark_skb_mustfree(struct sk_buff *skb, | ||
175 | char mustfree) | ||
176 | { | ||
177 | skb->cb[0] = mustfree; | ||
178 | } | ||
179 | |||
180 | static inline | ||
181 | int skb_mustfree(struct sk_buff *skb) | ||
182 | { | ||
183 | return (skb->cb[0] != 0); | ||
184 | } | ||
185 | |||
186 | /* Unmap and free a descriptor buffer. */ | 173 | /* Unmap and free a descriptor buffer. */ |
187 | static inline | 174 | static inline |
188 | void free_descriptor_buffer(struct bcm43xx_dmaring *ring, | 175 | void free_descriptor_buffer(struct bcm43xx_dmaring *ring, |
@@ -191,17 +178,11 @@ void free_descriptor_buffer(struct bcm43xx_dmaring *ring, | |||
191 | int irq_context) | 178 | int irq_context) |
192 | { | 179 | { |
193 | assert(meta->skb); | 180 | assert(meta->skb); |
194 | if (skb_mustfree(meta->skb)) { | 181 | if (irq_context) |
195 | if (irq_context) | 182 | dev_kfree_skb_irq(meta->skb); |
196 | dev_kfree_skb_irq(meta->skb); | 183 | else |
197 | else | 184 | dev_kfree_skb(meta->skb); |
198 | dev_kfree_skb(meta->skb); | ||
199 | } | ||
200 | meta->skb = NULL; | 185 | meta->skb = NULL; |
201 | if (meta->txb) { | ||
202 | ieee80211_txb_free(meta->txb); | ||
203 | meta->txb = NULL; | ||
204 | } | ||
205 | } | 186 | } |
206 | 187 | ||
207 | static int alloc_ringmemory(struct bcm43xx_dmaring *ring) | 188 | static int alloc_ringmemory(struct bcm43xx_dmaring *ring) |
@@ -334,7 +315,6 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, | |||
334 | meta->skb = skb; | 315 | meta->skb = skb; |
335 | meta->dmaaddr = dmaaddr; | 316 | meta->dmaaddr = dmaaddr; |
336 | skb->dev = ring->bcm->net_dev; | 317 | skb->dev = ring->bcm->net_dev; |
337 | mark_skb_mustfree(skb, 1); | ||
338 | desc_addr = (u32)(dmaaddr + ring->memoffset); | 318 | desc_addr = (u32)(dmaaddr + ring->memoffset); |
339 | desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK & | 319 | desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK & |
340 | (u32)(ring->rx_buffersize - ring->frameoffset)); | 320 | (u32)(ring->rx_buffersize - ring->frameoffset)); |
@@ -457,7 +437,6 @@ static void free_all_descbuffers(struct bcm43xx_dmaring *ring) | |||
457 | 437 | ||
458 | if (!meta->skb) { | 438 | if (!meta->skb) { |
459 | assert(ring->tx); | 439 | assert(ring->tx); |
460 | assert(!meta->txb); | ||
461 | continue; | 440 | continue; |
462 | } | 441 | } |
463 | if (ring->tx) { | 442 | if (ring->tx) { |
@@ -726,7 +705,6 @@ static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, | |||
726 | 705 | ||
727 | static int dma_tx_fragment(struct bcm43xx_dmaring *ring, | 706 | static int dma_tx_fragment(struct bcm43xx_dmaring *ring, |
728 | struct sk_buff *skb, | 707 | struct sk_buff *skb, |
729 | struct ieee80211_txb *txb, | ||
730 | u8 cur_frag) | 708 | u8 cur_frag) |
731 | { | 709 | { |
732 | int slot; | 710 | int slot; |
@@ -741,11 +719,6 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring, | |||
741 | desc = ring->vbase + slot; | 719 | desc = ring->vbase + slot; |
742 | meta = ring->meta + slot; | 720 | meta = ring->meta + slot; |
743 | 721 | ||
744 | if (cur_frag == 0) { | ||
745 | /* Save the txb pointer for freeing in xmitstatus IRQ */ | ||
746 | meta->txb = txb; | ||
747 | } | ||
748 | |||
749 | /* Add a device specific TX header. */ | 722 | /* Add a device specific TX header. */ |
750 | assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); | 723 | assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); |
751 | /* Reserve enough headroom for the device tx header. */ | 724 | /* Reserve enough headroom for the device tx header. */ |
@@ -810,13 +783,12 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, | |||
810 | 783 | ||
811 | for (i = 0; i < txb->nr_frags; i++) { | 784 | for (i = 0; i < txb->nr_frags; i++) { |
812 | skb = txb->fragments[i]; | 785 | skb = txb->fragments[i]; |
813 | /* We do not free the skb, as it is freed as | 786 | /* Take skb from ieee80211_txb_free */ |
814 | * part of the txb freeing. | 787 | txb->fragments[i] = NULL; |
815 | */ | 788 | dma_tx_fragment(ring, skb, i); |
816 | mark_skb_mustfree(skb, 0); | ||
817 | dma_tx_fragment(ring, skb, txb, i); | ||
818 | //TODO: handle failure of dma_tx_fragment | 789 | //TODO: handle failure of dma_tx_fragment |
819 | } | 790 | } |
791 | ieee80211_txb_free(txb); | ||
820 | 792 | ||
821 | return 0; | 793 | return 0; |
822 | } | 794 | } |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h index 88ad34dff2f2..cab8e2ba4c7e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h | |||
@@ -119,10 +119,6 @@ struct bcm43xx_dmadesc_meta { | |||
119 | struct sk_buff *skb; | 119 | struct sk_buff *skb; |
120 | /* DMA base bus-address of the descriptor buffer. */ | 120 | /* DMA base bus-address of the descriptor buffer. */ |
121 | dma_addr_t dmaaddr; | 121 | dma_addr_t dmaaddr; |
122 | /* Pointer to our txb (can be NULL). | ||
123 | * This should be freed in completion IRQ. | ||
124 | */ | ||
125 | struct ieee80211_txb *txb; | ||
126 | }; | 122 | }; |
127 | 123 | ||
128 | struct bcm43xx_dmaring { | 124 | struct bcm43xx_dmaring { |