aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2008-11-11 18:01:37 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-11-25 16:32:54 -0500
commit0e3de99846489424c2cba952e0a52c269f01009a (patch)
tree2af7bc7b61f28e9defae8b5886a959060affb357 /drivers/net/wireless/rt2x00
parent0f829b1d6f499447052f98098e41fd6a091eadd0 (diff)
rt2x00: Fix TX failure path
The callback function write_tx_data() can only fail when our ENTRY_OWNER_DEVICE_DATA flag on a queue entry failed to determine the entry was not available and it is in fact still owned by the hardware. This means that if that function fails the queue must be stopped in mac80211. When rt2x00queue_get_queue() returns NULL in the TX path, it means mac80211 has passed us an invalid queue, although this should be impossible, it shouldn't hurt if we send mac80211 a signal to stop the queue either. Both issues can simply be resolved by removing their manual failure handler and making them use the failure path provided in rt2x00mac_tx(). Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c3
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c14
2 files changed, 7 insertions, 10 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 48636b0dd895..4c0395729066 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -132,8 +132,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
132 ERROR(rt2x00dev, 132 ERROR(rt2x00dev,
133 "Attempt to send packet over invalid queue %d.\n" 133 "Attempt to send packet over invalid queue %d.\n"
134 "Please file bug report to %s.\n", qid, DRV_PROJECT); 134 "Please file bug report to %s.\n", qid, DRV_PROJECT);
135 dev_kfree_skb_any(skb); 135 goto exit_fail;
136 return NETDEV_TX_OK;
137 } 136 }
138 137
139 /* 138 /*
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index d7752dbd2023..b8de9d2750e4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -386,7 +386,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
386 u8 rate_idx, rate_flags; 386 u8 rate_idx, rate_flags;
387 387
388 if (unlikely(rt2x00queue_full(queue))) 388 if (unlikely(rt2x00queue_full(queue)))
389 return -EINVAL; 389 return -ENOBUFS;
390 390
391 if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { 391 if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) {
392 ERROR(queue->rt2x00dev, 392 ERROR(queue->rt2x00dev,
@@ -415,7 +415,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
415 tx_info = IEEE80211_SKB_CB(skb); 415 tx_info = IEEE80211_SKB_CB(skb);
416 rate_idx = tx_info->control.rates[0].idx; 416 rate_idx = tx_info->control.rates[0].idx;
417 rate_flags = tx_info->control.rates[0].flags; 417 rate_flags = tx_info->control.rates[0].flags;
418 skbdesc = get_skb_frame_desc(entry->skb); 418 skbdesc = get_skb_frame_desc(skb);
419 memset(skbdesc, 0, sizeof(*skbdesc)); 419 memset(skbdesc, 0, sizeof(*skbdesc));
420 skbdesc->entry = entry; 420 skbdesc->entry = entry;
421 skbdesc->tx_rate_idx = rate_idx; 421 skbdesc->tx_rate_idx = rate_idx;
@@ -427,20 +427,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
427 * the frame so we can provide it to the driver seperately. 427 * the frame so we can provide it to the driver seperately.
428 */ 428 */
429 if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && 429 if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
430 !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { 430 !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags))
431 rt2x00crypto_tx_remove_iv(skb, iv_len); 431 rt2x00crypto_tx_remove_iv(skb, iv_len);
432 }
433 432
434 /* 433 /*
435 * It could be possible that the queue was corrupted and this 434 * It could be possible that the queue was corrupted and this
436 * call failed. Just drop the frame, we cannot rollback and pass 435 * call failed. Since we always return NETDEV_TX_OK to mac80211,
437 * the frame to mac80211 because the skb->cb has now been tainted. 436 * this frame will simply be dropped.
438 */ 437 */
439 if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { 438 if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
440 clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); 439 clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
441 dev_kfree_skb_any(entry->skb);
442 entry->skb = NULL; 440 entry->skb = NULL;
443 return 0; 441 return -EIO;
444 } 442 }
445 443
446 if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) 444 if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))