diff options
author | Larry Finger <Larry.Finger@lwfinger.net> | 2008-12-10 00:34:27 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-12-12 14:02:06 -0500 |
commit | c1db52b9d27ee6e15a7136e67e4a21dc916cd07f (patch) | |
tree | ecccf2807efe8e2f50e0a71b6a66751f17b8f16b /drivers/net/wireless/rtl818x | |
parent | 388cdf31db6dfc3d175786a76989266380e12c26 (diff) |
rtl8187: Use usb anchor facilities to manage urbs
When SLUB debugging is enabled in the kernel, and the boot command includes
the option "slub_debug=P", rtl8187 encounters a GPF due to a read-after-free
of a urb.
Following the example of changes in p54usb to fix the same problem, the code
has been modified to use the usb_anchor_urb() method. With this change, the
USB core handles the freeing of urb's.
This patch fixes the problem reported in Kernel Bugzilla #12185
(http://bugzilla.kernel.org/show_bug.cgi?id=12185).
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Tested-by: Hin-Tak Leung <htl10@users.sourceforge.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rtl818x')
-rw-r--r-- | drivers/net/wireless/rtl818x/rtl8187.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/rtl818x/rtl8187_dev.c | 75 |
2 files changed, 52 insertions, 25 deletions
diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h index c385407a9941..3b1e1c2aad26 100644 --- a/drivers/net/wireless/rtl818x/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187.h | |||
@@ -99,6 +99,7 @@ struct rtl8187_priv { | |||
99 | struct ieee80211_supported_band band; | 99 | struct ieee80211_supported_band band; |
100 | struct usb_device *udev; | 100 | struct usb_device *udev; |
101 | u32 rx_conf; | 101 | u32 rx_conf; |
102 | struct usb_anchor anchored; | ||
102 | u16 txpwr_base; | 103 | u16 txpwr_base; |
103 | u8 asic_rev; | 104 | u8 asic_rev; |
104 | u8 is_rtl8187b; | 105 | u8 is_rtl8187b; |
@@ -115,7 +116,6 @@ struct rtl8187_priv { | |||
115 | u8 aifsn[4]; | 116 | u8 aifsn[4]; |
116 | struct { | 117 | struct { |
117 | __le64 buf; | 118 | __le64 buf; |
118 | struct urb *urb; | ||
119 | struct sk_buff_head queue; | 119 | struct sk_buff_head queue; |
120 | } b_tx_status; | 120 | } b_tx_status; |
121 | }; | 121 | }; |
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 417a2d7b5764..74f5449b7924 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c | |||
@@ -99,7 +99,6 @@ static const struct ieee80211_channel rtl818x_channels[] = { | |||
99 | static void rtl8187_iowrite_async_cb(struct urb *urb) | 99 | static void rtl8187_iowrite_async_cb(struct urb *urb) |
100 | { | 100 | { |
101 | kfree(urb->context); | 101 | kfree(urb->context); |
102 | usb_free_urb(urb); | ||
103 | } | 102 | } |
104 | 103 | ||
105 | static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, | 104 | static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, |
@@ -136,11 +135,13 @@ static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, | |||
136 | usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), | 135 | usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), |
137 | (unsigned char *)dr, buf, len, | 136 | (unsigned char *)dr, buf, len, |
138 | rtl8187_iowrite_async_cb, buf); | 137 | rtl8187_iowrite_async_cb, buf); |
138 | usb_anchor_urb(urb, &priv->anchored); | ||
139 | rc = usb_submit_urb(urb, GFP_ATOMIC); | 139 | rc = usb_submit_urb(urb, GFP_ATOMIC); |
140 | if (rc < 0) { | 140 | if (rc < 0) { |
141 | kfree(buf); | 141 | kfree(buf); |
142 | usb_free_urb(urb); | 142 | usb_unanchor_urb(urb); |
143 | } | 143 | } |
144 | usb_free_urb(urb); | ||
144 | } | 145 | } |
145 | 146 | ||
146 | static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, | 147 | static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, |
@@ -172,7 +173,6 @@ static void rtl8187_tx_cb(struct urb *urb) | |||
172 | struct ieee80211_hw *hw = info->rate_driver_data[0]; | 173 | struct ieee80211_hw *hw = info->rate_driver_data[0]; |
173 | struct rtl8187_priv *priv = hw->priv; | 174 | struct rtl8187_priv *priv = hw->priv; |
174 | 175 | ||
175 | usb_free_urb(info->rate_driver_data[1]); | ||
176 | skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : | 176 | skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : |
177 | sizeof(struct rtl8187_tx_hdr)); | 177 | sizeof(struct rtl8187_tx_hdr)); |
178 | ieee80211_tx_info_clear_status(info); | 178 | ieee80211_tx_info_clear_status(info); |
@@ -273,11 +273,13 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
273 | 273 | ||
274 | usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep), | 274 | usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep), |
275 | buf, skb->len, rtl8187_tx_cb, skb); | 275 | buf, skb->len, rtl8187_tx_cb, skb); |
276 | usb_anchor_urb(urb, &priv->anchored); | ||
276 | rc = usb_submit_urb(urb, GFP_ATOMIC); | 277 | rc = usb_submit_urb(urb, GFP_ATOMIC); |
277 | if (rc < 0) { | 278 | if (rc < 0) { |
278 | usb_free_urb(urb); | 279 | usb_unanchor_urb(urb); |
279 | kfree_skb(skb); | 280 | kfree_skb(skb); |
280 | } | 281 | } |
282 | usb_free_urb(urb); | ||
281 | 283 | ||
282 | return 0; | 284 | return 0; |
283 | } | 285 | } |
@@ -301,14 +303,13 @@ static void rtl8187_rx_cb(struct urb *urb) | |||
301 | return; | 303 | return; |
302 | } | 304 | } |
303 | spin_unlock(&priv->rx_queue.lock); | 305 | spin_unlock(&priv->rx_queue.lock); |
306 | skb_put(skb, urb->actual_length); | ||
304 | 307 | ||
305 | if (unlikely(urb->status)) { | 308 | if (unlikely(urb->status)) { |
306 | usb_free_urb(urb); | ||
307 | dev_kfree_skb_irq(skb); | 309 | dev_kfree_skb_irq(skb); |
308 | return; | 310 | return; |
309 | } | 311 | } |
310 | 312 | ||
311 | skb_put(skb, urb->actual_length); | ||
312 | if (!priv->is_rtl8187b) { | 313 | if (!priv->is_rtl8187b) { |
313 | struct rtl8187_rx_hdr *hdr = | 314 | struct rtl8187_rx_hdr *hdr = |
314 | (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); | 315 | (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); |
@@ -361,7 +362,6 @@ static void rtl8187_rx_cb(struct urb *urb) | |||
361 | 362 | ||
362 | skb = dev_alloc_skb(RTL8187_MAX_RX); | 363 | skb = dev_alloc_skb(RTL8187_MAX_RX); |
363 | if (unlikely(!skb)) { | 364 | if (unlikely(!skb)) { |
364 | usb_free_urb(urb); | ||
365 | /* TODO check rx queue length and refill *somewhere* */ | 365 | /* TODO check rx queue length and refill *somewhere* */ |
366 | return; | 366 | return; |
367 | } | 367 | } |
@@ -373,24 +373,32 @@ static void rtl8187_rx_cb(struct urb *urb) | |||
373 | urb->context = skb; | 373 | urb->context = skb; |
374 | skb_queue_tail(&priv->rx_queue, skb); | 374 | skb_queue_tail(&priv->rx_queue, skb); |
375 | 375 | ||
376 | usb_submit_urb(urb, GFP_ATOMIC); | 376 | usb_anchor_urb(urb, &priv->anchored); |
377 | if (usb_submit_urb(urb, GFP_ATOMIC)) { | ||
378 | usb_unanchor_urb(urb); | ||
379 | skb_unlink(skb, &priv->rx_queue); | ||
380 | dev_kfree_skb_irq(skb); | ||
381 | } | ||
377 | } | 382 | } |
378 | 383 | ||
379 | static int rtl8187_init_urbs(struct ieee80211_hw *dev) | 384 | static int rtl8187_init_urbs(struct ieee80211_hw *dev) |
380 | { | 385 | { |
381 | struct rtl8187_priv *priv = dev->priv; | 386 | struct rtl8187_priv *priv = dev->priv; |
382 | struct urb *entry; | 387 | struct urb *entry = NULL; |
383 | struct sk_buff *skb; | 388 | struct sk_buff *skb; |
384 | struct rtl8187_rx_info *info; | 389 | struct rtl8187_rx_info *info; |
390 | int ret = 0; | ||
385 | 391 | ||
386 | while (skb_queue_len(&priv->rx_queue) < 8) { | 392 | while (skb_queue_len(&priv->rx_queue) < 8) { |
387 | skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL); | 393 | skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL); |
388 | if (!skb) | 394 | if (!skb) { |
389 | break; | 395 | ret = -ENOMEM; |
396 | goto err; | ||
397 | } | ||
390 | entry = usb_alloc_urb(0, GFP_KERNEL); | 398 | entry = usb_alloc_urb(0, GFP_KERNEL); |
391 | if (!entry) { | 399 | if (!entry) { |
392 | kfree_skb(skb); | 400 | ret = -ENOMEM; |
393 | break; | 401 | goto err; |
394 | } | 402 | } |
395 | usb_fill_bulk_urb(entry, priv->udev, | 403 | usb_fill_bulk_urb(entry, priv->udev, |
396 | usb_rcvbulkpipe(priv->udev, | 404 | usb_rcvbulkpipe(priv->udev, |
@@ -401,10 +409,22 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev) | |||
401 | info->urb = entry; | 409 | info->urb = entry; |
402 | info->dev = dev; | 410 | info->dev = dev; |
403 | skb_queue_tail(&priv->rx_queue, skb); | 411 | skb_queue_tail(&priv->rx_queue, skb); |
404 | usb_submit_urb(entry, GFP_KERNEL); | 412 | usb_anchor_urb(entry, &priv->anchored); |
413 | ret = usb_submit_urb(entry, GFP_KERNEL); | ||
414 | if (ret) { | ||
415 | skb_unlink(skb, &priv->rx_queue); | ||
416 | usb_unanchor_urb(entry); | ||
417 | goto err; | ||
418 | } | ||
419 | usb_free_urb(entry); | ||
405 | } | 420 | } |
421 | return ret; | ||
406 | 422 | ||
407 | return 0; | 423 | err: |
424 | usb_free_urb(entry); | ||
425 | kfree_skb(skb); | ||
426 | usb_kill_anchored_urbs(&priv->anchored); | ||
427 | return ret; | ||
408 | } | 428 | } |
409 | 429 | ||
410 | static void rtl8187b_status_cb(struct urb *urb) | 430 | static void rtl8187b_status_cb(struct urb *urb) |
@@ -414,10 +434,8 @@ static void rtl8187b_status_cb(struct urb *urb) | |||
414 | u64 val; | 434 | u64 val; |
415 | unsigned int cmd_type; | 435 | unsigned int cmd_type; |
416 | 436 | ||
417 | if (unlikely(urb->status)) { | 437 | if (unlikely(urb->status)) |
418 | usb_free_urb(urb); | ||
419 | return; | 438 | return; |
420 | } | ||
421 | 439 | ||
422 | /* | 440 | /* |
423 | * Read from status buffer: | 441 | * Read from status buffer: |
@@ -488,26 +506,32 @@ static void rtl8187b_status_cb(struct urb *urb) | |||
488 | spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags); | 506 | spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags); |
489 | } | 507 | } |
490 | 508 | ||
491 | usb_submit_urb(urb, GFP_ATOMIC); | 509 | usb_anchor_urb(urb, &priv->anchored); |
510 | if (usb_submit_urb(urb, GFP_ATOMIC)) | ||
511 | usb_unanchor_urb(urb); | ||
492 | } | 512 | } |
493 | 513 | ||
494 | static int rtl8187b_init_status_urb(struct ieee80211_hw *dev) | 514 | static int rtl8187b_init_status_urb(struct ieee80211_hw *dev) |
495 | { | 515 | { |
496 | struct rtl8187_priv *priv = dev->priv; | 516 | struct rtl8187_priv *priv = dev->priv; |
497 | struct urb *entry; | 517 | struct urb *entry; |
518 | int ret = 0; | ||
498 | 519 | ||
499 | entry = usb_alloc_urb(0, GFP_KERNEL); | 520 | entry = usb_alloc_urb(0, GFP_KERNEL); |
500 | if (!entry) | 521 | if (!entry) |
501 | return -ENOMEM; | 522 | return -ENOMEM; |
502 | priv->b_tx_status.urb = entry; | ||
503 | 523 | ||
504 | usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, 9), | 524 | usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, 9), |
505 | &priv->b_tx_status.buf, sizeof(priv->b_tx_status.buf), | 525 | &priv->b_tx_status.buf, sizeof(priv->b_tx_status.buf), |
506 | rtl8187b_status_cb, dev); | 526 | rtl8187b_status_cb, dev); |
507 | 527 | ||
508 | usb_submit_urb(entry, GFP_KERNEL); | 528 | usb_anchor_urb(entry, &priv->anchored); |
529 | ret = usb_submit_urb(entry, GFP_KERNEL); | ||
530 | if (ret) | ||
531 | usb_unanchor_urb(entry); | ||
532 | usb_free_urb(entry); | ||
509 | 533 | ||
510 | return 0; | 534 | return ret; |
511 | } | 535 | } |
512 | 536 | ||
513 | static int rtl8187_cmd_reset(struct ieee80211_hw *dev) | 537 | static int rtl8187_cmd_reset(struct ieee80211_hw *dev) |
@@ -841,6 +865,9 @@ static int rtl8187_start(struct ieee80211_hw *dev) | |||
841 | return ret; | 865 | return ret; |
842 | 866 | ||
843 | mutex_lock(&priv->conf_mutex); | 867 | mutex_lock(&priv->conf_mutex); |
868 | |||
869 | init_usb_anchor(&priv->anchored); | ||
870 | |||
844 | if (priv->is_rtl8187b) { | 871 | if (priv->is_rtl8187b) { |
845 | reg = RTL818X_RX_CONF_MGMT | | 872 | reg = RTL818X_RX_CONF_MGMT | |
846 | RTL818X_RX_CONF_DATA | | 873 | RTL818X_RX_CONF_DATA | |
@@ -936,12 +963,12 @@ static void rtl8187_stop(struct ieee80211_hw *dev) | |||
936 | 963 | ||
937 | while ((skb = skb_dequeue(&priv->rx_queue))) { | 964 | while ((skb = skb_dequeue(&priv->rx_queue))) { |
938 | info = (struct rtl8187_rx_info *)skb->cb; | 965 | info = (struct rtl8187_rx_info *)skb->cb; |
939 | usb_kill_urb(info->urb); | ||
940 | kfree_skb(skb); | 966 | kfree_skb(skb); |
941 | } | 967 | } |
942 | while ((skb = skb_dequeue(&priv->b_tx_status.queue))) | 968 | while ((skb = skb_dequeue(&priv->b_tx_status.queue))) |
943 | dev_kfree_skb_any(skb); | 969 | dev_kfree_skb_any(skb); |
944 | usb_kill_urb(priv->b_tx_status.urb); | 970 | |
971 | usb_kill_anchored_urbs(&priv->anchored); | ||
945 | mutex_unlock(&priv->conf_mutex); | 972 | mutex_unlock(&priv->conf_mutex); |
946 | } | 973 | } |
947 | 974 | ||