iwlwifi: queue user-initiated scan when doing internal scan
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / iwl-scan.c
index 107e173..b8bcd48 100644 (file)
@@ -333,7 +333,8 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
                goto out_unlock;
        }
 
-       if (test_bit(STATUS_SCANNING, &priv->status)) {
+       if (test_bit(STATUS_SCANNING, &priv->status) &&
+           !priv->is_internal_short_scan) {
                IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
                ret = -EAGAIN;
                goto out_unlock;
@@ -348,8 +349,16 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
        /* mac80211 will only ask for one band at a time */
        priv->scan_band = req->channels[0]->band;
        priv->scan_request = req;
+       priv->scan_vif = vif;
 
-       ret = iwl_scan_initiate(priv, vif);
+       /*
+        * If an internal scan is in progress, just set
+        * up the scan_request as per above.
+        */
+       if (priv->is_internal_short_scan)
+               ret = 0;
+       else
+               ret = iwl_scan_initiate(priv, vif);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
@@ -376,6 +385,11 @@ 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;
@@ -433,7 +447,7 @@ EXPORT_SYMBOL(iwl_bg_scan_check);
  */
 
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
-                      const u8 *ies, int ie_len, int left)
+                      const u8 *ta, const u8 *ies, int ie_len, int left)
 {
        int len = 0;
        u8 *pos = NULL;
@@ -446,7 +460,7 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
 
        frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
        memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
-       memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
+       memcpy(frame->sa, ta, ETH_ALEN);
        memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
        frame->seq_ctrl = 0;
 
@@ -497,26 +511,41 @@ 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;
+       } else {
+               priv->scan_request = NULL;
+               priv->scan_vif = NULL;
        }
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
+               goto out;
+
+       if (internal && priv->scan_request)
+               iwl_scan_initiate(priv, priv->scan_vif);
 
        /* Since setting the TXPOWER may have been deferred while
         * performing the scan, fire one off */
-       mutex_lock(&priv->mutex);
        iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
+ out:
        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);
 }
 EXPORT_SYMBOL(iwl_bg_scan_completed);