aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-scan.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-04-07 03:21:36 -0400
committerReinette Chatre <reinette.chatre@intel.com>2010-04-16 16:27:10 -0400
commit88be026490ed89c2ffead81a52531fbac5507e01 (patch)
tree94f8727e5027a09f24623bd4dcecbbbe1be6922a /drivers/net/wireless/iwlwifi/iwl-scan.c
parent8b9fce77737ae9983f61ec56cd53f52fb738b2c7 (diff)
iwlwifi: fix scan races
When an internal scan is started, nothing protects the is_internal_short_scan variable which can cause crashes, cf. https://bugzilla.kernel.org/show_bug.cgi?id=15667. Fix this by making the short scan request use the mutex for locking, which requires making the request go to a work struct so that it can sleep. Reported-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-scan.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c31
1 files changed, 20 insertions, 11 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index bd2f7c420563..5062f4ebb6a9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -469,6 +469,8 @@ EXPORT_SYMBOL(iwl_init_scan_params);
469 469
470static int iwl_scan_initiate(struct iwl_priv *priv) 470static int iwl_scan_initiate(struct iwl_priv *priv)
471{ 471{
472 WARN_ON(!mutex_is_locked(&priv->mutex));
473
472 IWL_DEBUG_INFO(priv, "Starting scan...\n"); 474 IWL_DEBUG_INFO(priv, "Starting scan...\n");
473 set_bit(STATUS_SCANNING, &priv->status); 475 set_bit(STATUS_SCANNING, &priv->status);
474 priv->is_internal_short_scan = false; 476 priv->is_internal_short_scan = false;
@@ -546,24 +548,31 @@ EXPORT_SYMBOL(iwl_mac_hw_scan);
546 * internal short scan, this function should only been called while associated. 548 * internal short scan, this function should only been called while associated.
547 * It will reset and tune the radio to prevent possible RF related problem 549 * It will reset and tune the radio to prevent possible RF related problem
548 */ 550 */
549int iwl_internal_short_hw_scan(struct iwl_priv *priv) 551void iwl_internal_short_hw_scan(struct iwl_priv *priv)
550{ 552{
551 int ret = 0; 553 queue_work(priv->workqueue, &priv->start_internal_scan);
554}
555
556static void iwl_bg_start_internal_scan(struct work_struct *work)
557{
558 struct iwl_priv *priv =
559 container_of(work, struct iwl_priv, start_internal_scan);
560
561 mutex_lock(&priv->mutex);
552 562
553 if (!iwl_is_ready_rf(priv)) { 563 if (!iwl_is_ready_rf(priv)) {
554 ret = -EIO;
555 IWL_DEBUG_SCAN(priv, "not ready or exit pending\n"); 564 IWL_DEBUG_SCAN(priv, "not ready or exit pending\n");
556 goto out; 565 goto unlock;
557 } 566 }
567
558 if (test_bit(STATUS_SCANNING, &priv->status)) { 568 if (test_bit(STATUS_SCANNING, &priv->status)) {
559 IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); 569 IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
560 ret = -EAGAIN; 570 goto unlock;
561 goto out;
562 } 571 }
572
563 if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { 573 if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
564 IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); 574 IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
565 ret = -EAGAIN; 575 goto unlock;
566 goto out;
567 } 576 }
568 577
569 priv->scan_bands = 0; 578 priv->scan_bands = 0;
@@ -576,9 +585,8 @@ int iwl_internal_short_hw_scan(struct iwl_priv *priv)
576 set_bit(STATUS_SCANNING, &priv->status); 585 set_bit(STATUS_SCANNING, &priv->status);
577 priv->is_internal_short_scan = true; 586 priv->is_internal_short_scan = true;
578 queue_work(priv->workqueue, &priv->request_scan); 587 queue_work(priv->workqueue, &priv->request_scan);
579 588 unlock:
580out: 589 mutex_unlock(&priv->mutex);
581 return ret;
582} 590}
583EXPORT_SYMBOL(iwl_internal_short_hw_scan); 591EXPORT_SYMBOL(iwl_internal_short_hw_scan);
584 592
@@ -964,6 +972,7 @@ void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
964 INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); 972 INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
965 INIT_WORK(&priv->request_scan, iwl_bg_request_scan); 973 INIT_WORK(&priv->request_scan, iwl_bg_request_scan);
966 INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); 974 INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
975 INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
967 INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); 976 INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
968} 977}
969EXPORT_SYMBOL(iwl_setup_scan_deferred_work); 978EXPORT_SYMBOL(iwl_setup_scan_deferred_work);