aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPete Zaitcev <zaitcev@redhat.com>2006-03-06 19:37:51 -0500
committerJohn W. Linville <linville@tuxdriver.com>2006-03-27 11:19:33 -0500
commit512a80916b8d04529c0915534c63529144f74e10 (patch)
tree34531295df7a1aa990e268bf6b29bf0f16c507ef /drivers
parent367f899ac3b52cf4611cd291ec2bfbf774b15bc7 (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')
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_dma.c44
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_dma.h4
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
173static inline
174void mark_skb_mustfree(struct sk_buff *skb,
175 char mustfree)
176{
177 skb->cb[0] = mustfree;
178}
179
180static inline
181int 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. */
187static inline 174static inline
188void free_descriptor_buffer(struct bcm43xx_dmaring *ring, 175void 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
207static int alloc_ringmemory(struct bcm43xx_dmaring *ring) 188static 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
727static int dma_tx_fragment(struct bcm43xx_dmaring *ring, 706static 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
128struct bcm43xx_dmaring { 124struct bcm43xx_dmaring {