summaryrefslogtreecommitdiffstats
path: root/iwlwifi-fix-internal-scan-race.patch
diff options
context:
space:
mode:
Diffstat (limited to 'iwlwifi-fix-internal-scan-race.patch')
-rw-r--r--iwlwifi-fix-internal-scan-race.patch123
1 files changed, 123 insertions, 0 deletions
diff --git a/iwlwifi-fix-internal-scan-race.patch b/iwlwifi-fix-internal-scan-race.patch
new file mode 100644
index 0000000..18b3156
--- /dev/null
+++ b/iwlwifi-fix-internal-scan-race.patch
@@ -0,0 +1,123 @@
+From reinette.chatre@intel.com Thu May 13 17:49:59 2010
+Return-path: <reinette.chatre@intel.com>
+Envelope-to: linville@tuxdriver.com
+Delivery-date: Thu, 13 May 2010 17:49:59 -0400
+Received: from mga09.intel.com ([134.134.136.24])
+ by smtp.tuxdriver.com with esmtp (Exim 4.63)
+ (envelope-from <reinette.chatre@intel.com>)
+ id 1OCgI1-0007H3-Eg
+ for linville@tuxdriver.com; Thu, 13 May 2010 17:49:59 -0400
+Received: from orsmga002.jf.intel.com ([10.7.209.21])
+ by orsmga102.jf.intel.com with ESMTP; 13 May 2010 14:48:04 -0700
+X-ExtLoop1: 1
+X-IronPort-AV: E=Sophos;i="4.53,224,1272870000";
+ d="scan'208";a="517743256"
+Received: from rchatre-desk.amr.corp.intel.com.jf.intel.com (HELO localhost.localdomain) ([134.134.15.94])
+ by orsmga002.jf.intel.com with ESMTP; 13 May 2010 14:49:12 -0700
+From: Reinette Chatre <reinette.chatre@intel.com>
+To: linville@tuxdriver.com
+Cc: linux-wireless@vger.kernel.org, ipw3945-devel@lists.sourceforge.net, Reinette Chatre <reinette.chatre@intel.com>
+Subject: [PATCH 1/2] iwlwifi: fix internal scan race
+Date: Thu, 13 May 2010 14:49:44 -0700
+Message-Id: <1273787385-9248-2-git-send-email-reinette.chatre@intel.com>
+X-Mailer: git-send-email 1.6.3.3
+In-Reply-To: <1273787385-9248-1-git-send-email-reinette.chatre@intel.com>
+References: <1273787385-9248-1-git-send-email-reinette.chatre@intel.com>
+X-Spam-Score: -4.2 (----)
+X-Spam-Status: No
+Status: RO
+Content-Length: 3370
+Lines: 91
+
+From: Reinette Chatre <reinette.chatre@intel.com>
+
+It is possible for internal scan to race against itself if the device is
+not returning the scan results from first requests. What happens in this
+case is the cleanup done during the abort of the first internal scan also
+cleans up part of the new scan, causing it to access memory it shouldn't.
+
+Here are details:
+* First internal scan is triggered and scan command sent to device.
+* After seven seconds there is no scan results so the watchdog timer
+ triggers a scan abort.
+* The scan abort succeeds and a SCAN_COMPLETE_NOTIFICATION is received for
+ failed scan.
+* During processing of SCAN_COMPLETE_NOTIFICATION we clear STATUS_SCANNING
+ and queue the "scan_completed" work.
+** At this time, since the problem that caused the internal scan in first
+ place is still present, a new internal scan is triggered.
+The behavior at this point is a bit different between 2.6.34 and 2.6.35
+since 2.6.35 has a lot of this synchronized. The rest of the race
+description will thus be generalized.
+** As part of preparing for the scan "is_internal_short_scan" is set to
+true.
+* At this point the completion work for fist scan is run. As part of this
+ there is some locking missing around the "is_internal_short_scan"
+ variable and it is set to "false".
+** Now the second scan runs and it considers itself a real (not internal0
+ scan and thus causes problems with wrong memory being accessed.
+
+The fix is twofold.
+* Since "is_internal_short_scan" should be protected by mutex, fix this in
+ scan completion work so that changes to it can be serialized.
+* Do not queue a new internal scan if one is in progress.
+
+This fixes https://bugzilla.kernel.org/show_bug.cgi?id=15824
+
+Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
+---
+ drivers/net/wireless/iwlwifi/iwl-scan.c | 21 ++++++++++++++++++---
+ 1 files changed, 18 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
+index 2367286..a2c4855 100644
+--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
++++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
+@@ -560,6 +560,11 @@ static void iwl_bg_start_internal_scan(struct work_struct *work)
+
+ mutex_lock(&priv->mutex);
+
++ if (priv->is_internal_short_scan == true) {
++ IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
++ goto unlock;
++ }
++
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_SCAN(priv, "not ready or exit pending\n");
+ goto unlock;
+@@ -957,17 +962,27 @@ void iwl_bg_scan_completed(struct work_struct *work)
+ {
+ struct iwl_priv *priv =
+ container_of(work, struct iwl_priv, scan_completed);
++ bool internal = false;
+
+ IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
+
+ cancel_delayed_work(&priv->scan_check);
+
+- if (!priv->is_internal_short_scan)
+- ieee80211_scan_completed(priv->hw, false);
+- else {
++ mutex_lock(&priv->mutex);
++ if (priv->is_internal_short_scan) {
+ priv->is_internal_short_scan = false;
+ IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
++ internal = true;
+ }
++ mutex_unlock(&priv->mutex);
++
++ /*
++ * Do not hold mutex here since this will cause mac80211 to call
++ * into driver again into functions that will attempt to take
++ * mutex.
++ */
++ if (!internal)
++ ieee80211_scan_completed(priv->hw, false);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+--
+1.6.3.3
+
+
+