aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2009-11-06 12:32:44 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-11 15:23:40 -0500
commitf54a52021d7ad039c16fe5a1e094d8f0394d90ec (patch)
tree535ed64f4343f7b51acf802bc3b38501858270ab
parent2071a0084a0323697b7d6fd5a98982194bd6929f (diff)
b43: Rewrite TX bounce buffer handling
Do not mess with the original skb, but allocate an independent bouncebuffer. This protects against bad interference with mac80211's assumptions about the skb (which already caused bugs). Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/b43/dma.c48
-rw-r--r--drivers/net/wireless/b43/xmit.h19
2 files changed, 39 insertions, 28 deletions
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index de4e804bedf0..b5cd7f57055b 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -1157,18 +1157,17 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
1157} 1157}
1158 1158
1159static int dma_tx_fragment(struct b43_dmaring *ring, 1159static int dma_tx_fragment(struct b43_dmaring *ring,
1160 struct sk_buff **in_skb) 1160 struct sk_buff *skb)
1161{ 1161{
1162 struct sk_buff *skb = *in_skb;
1163 const struct b43_dma_ops *ops = ring->ops; 1162 const struct b43_dma_ops *ops = ring->ops;
1164 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1163 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1164 struct b43_private_tx_info *priv_info = b43_get_priv_tx_info(info);
1165 u8 *header; 1165 u8 *header;
1166 int slot, old_top_slot, old_used_slots; 1166 int slot, old_top_slot, old_used_slots;
1167 int err; 1167 int err;
1168 struct b43_dmadesc_generic *desc; 1168 struct b43_dmadesc_generic *desc;
1169 struct b43_dmadesc_meta *meta; 1169 struct b43_dmadesc_meta *meta;
1170 struct b43_dmadesc_meta *meta_hdr; 1170 struct b43_dmadesc_meta *meta_hdr;
1171 struct sk_buff *bounce_skb;
1172 u16 cookie; 1171 u16 cookie;
1173 size_t hdrsize = b43_txhdr_size(ring->dev); 1172 size_t hdrsize = b43_txhdr_size(ring->dev);
1174 1173
@@ -1212,34 +1211,28 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
1212 1211
1213 meta->skb = skb; 1212 meta->skb = skb;
1214 meta->is_last_fragment = 1; 1213 meta->is_last_fragment = 1;
1214 priv_info->bouncebuffer = NULL;
1215 1215
1216 meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); 1216 meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
1217 /* create a bounce buffer in zone_dma on mapping failure. */ 1217 /* create a bounce buffer in zone_dma on mapping failure. */
1218 if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { 1218 if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
1219 bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); 1219 priv_info->bouncebuffer = kmalloc(skb->len, GFP_ATOMIC | GFP_DMA);
1220 if (!bounce_skb) { 1220 if (!priv_info->bouncebuffer) {
1221 ring->current_slot = old_top_slot; 1221 ring->current_slot = old_top_slot;
1222 ring->used_slots = old_used_slots; 1222 ring->used_slots = old_used_slots;
1223 err = -ENOMEM; 1223 err = -ENOMEM;
1224 goto out_unmap_hdr; 1224 goto out_unmap_hdr;
1225 } 1225 }
1226 memcpy(priv_info->bouncebuffer, skb->data, skb->len);
1226 1227
1227 memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); 1228 meta->dmaaddr = map_descbuffer(ring, priv_info->bouncebuffer, skb->len, 1);
1228 memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb));
1229 bounce_skb->dev = skb->dev;
1230 skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb));
1231 info = IEEE80211_SKB_CB(bounce_skb);
1232
1233 dev_kfree_skb_any(skb);
1234 skb = bounce_skb;
1235 *in_skb = bounce_skb;
1236 meta->skb = skb;
1237 meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
1238 if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { 1229 if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
1230 kfree(priv_info->bouncebuffer);
1231 priv_info->bouncebuffer = NULL;
1239 ring->current_slot = old_top_slot; 1232 ring->current_slot = old_top_slot;
1240 ring->used_slots = old_used_slots; 1233 ring->used_slots = old_used_slots;
1241 err = -EIO; 1234 err = -EIO;
1242 goto out_free_bounce; 1235 goto out_unmap_hdr;
1243 } 1236 }
1244 } 1237 }
1245 1238
@@ -1256,8 +1249,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
1256 ops->poke_tx(ring, next_slot(ring, slot)); 1249 ops->poke_tx(ring, next_slot(ring, slot));
1257 return 0; 1250 return 0;
1258 1251
1259out_free_bounce:
1260 dev_kfree_skb_any(skb);
1261out_unmap_hdr: 1252out_unmap_hdr:
1262 unmap_descbuffer(ring, meta_hdr->dmaaddr, 1253 unmap_descbuffer(ring, meta_hdr->dmaaddr,
1263 hdrsize, 1); 1254 hdrsize, 1);
@@ -1362,11 +1353,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
1362 * static, so we don't need to store it per frame. */ 1353 * static, so we don't need to store it per frame. */
1363 ring->queue_prio = skb_get_queue_mapping(skb); 1354 ring->queue_prio = skb_get_queue_mapping(skb);
1364 1355
1365 /* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing 1356 err = dma_tx_fragment(ring, skb);
1366 * into the skb data or cb now. */
1367 hdr = NULL;
1368 info = NULL;
1369 err = dma_tx_fragment(ring, &skb);
1370 if (unlikely(err == -ENOKEY)) { 1357 if (unlikely(err == -ENOKEY)) {
1371 /* Drop this packet, as we don't have the encryption key 1358 /* Drop this packet, as we don't have the encryption key
1372 * anymore and must not transmit it unencrypted. */ 1359 * anymore and must not transmit it unencrypted. */
@@ -1413,12 +1400,17 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
1413 B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); 1400 B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
1414 desc = ops->idx2desc(ring, slot, &meta); 1401 desc = ops->idx2desc(ring, slot, &meta);
1415 1402
1416 if (meta->skb) 1403 if (meta->skb) {
1417 unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1404 struct b43_private_tx_info *priv_info =
1418 1); 1405 b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
1419 else 1406
1407 unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
1408 kfree(priv_info->bouncebuffer);
1409 priv_info->bouncebuffer = NULL;
1410 } else {
1420 unmap_descbuffer(ring, meta->dmaaddr, 1411 unmap_descbuffer(ring, meta->dmaaddr,
1421 b43_txhdr_size(dev), 1); 1412 b43_txhdr_size(dev), 1);
1413 }
1422 1414
1423 if (meta->is_last_fragment) { 1415 if (meta->is_last_fragment) {
1424 struct ieee80211_tx_info *info; 1416 struct ieee80211_tx_info *info;
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index 3530de871873..d23ff9fe0c9e 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -2,6 +2,8 @@
2#define B43_XMIT_H_ 2#define B43_XMIT_H_
3 3
4#include "main.h" 4#include "main.h"
5#include <net/mac80211.h>
6
5 7
6#define _b43_declare_plcp_hdr(size) \ 8#define _b43_declare_plcp_hdr(size) \
7 struct b43_plcp_hdr##size { \ 9 struct b43_plcp_hdr##size { \
@@ -332,4 +334,21 @@ static inline u8 b43_kidx_to_raw(struct b43_wldev *dev, u8 firmware_kidx)
332 return raw_kidx; 334 return raw_kidx;
333} 335}
334 336
337/* struct b43_private_tx_info - TX info private to b43.
338 * The structure is placed in (struct ieee80211_tx_info *)->rate_driver_data
339 *
340 * @bouncebuffer: DMA Bouncebuffer (if used)
341 */
342struct b43_private_tx_info {
343 void *bouncebuffer;
344};
345
346static inline struct b43_private_tx_info *
347b43_get_priv_tx_info(struct ieee80211_tx_info *info)
348{
349 BUILD_BUG_ON(sizeof(struct b43_private_tx_info) >
350 sizeof(info->rate_driver_data));
351 return (struct b43_private_tx_info *)info->rate_driver_data;
352}
353
335#endif /* B43_XMIT_H_ */ 354#endif /* B43_XMIT_H_ */