diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-scan.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-scan.c | 184 |
1 files changed, 124 insertions, 60 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 3c803f6922e..23644cf884f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -46,15 +46,6 @@ #define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3) #define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2) -/* For faster active scanning, scan will move to the next channel if fewer than - * PLCP_QUIET_THRESH packets are heard on this channel within - * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell - * time if it's a quiet channel (nothing responded to our probe, and there's - * no other traffic). - * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ -#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */ -#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(10) /* msec */ - /* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. * Must be set longer than active dwell time. * For the most reliable scan, set > AP beacon interval (typically 100msec). */ @@ -63,7 +54,6 @@ #define IWL_PASSIVE_DWELL_BASE (100) #define IWL_CHANNEL_TUNE_TIME 5 -#define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1)))) /** @@ -80,12 +70,12 @@ int iwl_scan_cancel(struct iwl_priv *priv) if (test_bit(STATUS_SCANNING, &priv->status)) { if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_SCAN("Queuing scan abort.\n"); + IWL_DEBUG_SCAN(priv, "Queuing scan abort.\n"); set_bit(STATUS_SCAN_ABORTING, &priv->status); queue_work(priv->workqueue, &priv->abort_scan); } else - IWL_DEBUG_SCAN("Scan abort already in progress.\n"); + IWL_DEBUG_SCAN(priv, "Scan abort already in progress.\n"); return test_bit(STATUS_SCANNING, &priv->status); } @@ -119,7 +109,7 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) } EXPORT_SYMBOL(iwl_scan_cancel_timeout); -static int iwl_send_scan_abort(struct iwl_priv *priv) +int iwl_send_scan_abort(struct iwl_priv *priv) { int ret = 0; struct iwl_rx_packet *res; @@ -150,7 +140,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) * can occur if we send the scan abort before we * the microcode has notified us that a scan is * completed. */ - IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status); + IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", res->u.status); clear_bit(STATUS_SCAN_ABORTING, &priv->status); clear_bit(STATUS_SCAN_HW, &priv->status); } @@ -160,7 +150,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) return ret; } - +EXPORT_SYMBOL(iwl_send_scan_abort); /* Service response to REPLY_SCAN_CMD (0x80) */ static void iwl_rx_reply_scan(struct iwl_priv *priv, @@ -171,7 +161,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv, struct iwl_scanreq_notification *notif = (struct iwl_scanreq_notification *)pkt->u.raw; - IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status); + IWL_DEBUG_RX(priv, "Scan request status = 0x%x\n", notif->status); #endif } @@ -183,7 +173,7 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv, struct iwl_scanstart_notification *notif = (struct iwl_scanstart_notification *)pkt->u.raw; priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); - IWL_DEBUG_SCAN("Scan start: " + IWL_DEBUG_SCAN(priv, "Scan start: " "%d [802.11%s] " "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", notif->channel, @@ -202,7 +192,7 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv, struct iwl_scanresults_notification *notif = (struct iwl_scanresults_notification *)pkt->u.raw; - IWL_DEBUG_SCAN("Scan ch.res: " + IWL_DEBUG_SCAN(priv, "Scan ch.res: " "%d [802.11%s] " "(TSF: 0x%08X:%08X) - %d " "elapsed=%lu usec (%dms since last)\n", @@ -228,7 +218,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; - IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", + IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", scan_notif->scanned_channels, scan_notif->tsf_low, scan_notif->tsf_high, scan_notif->status); @@ -240,7 +230,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, /* The scan completion notification came in, so kill that timer... */ cancel_delayed_work(&priv->scan_check); - IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n", + IWL_DEBUG_INFO(priv, "Scan pass on %sGHz took %dms\n", (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ? "2.4" : "5.2", jiffies_to_msecs(elapsed_jiffies @@ -258,7 +248,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, * then we reset the scan state machine and terminate, * re-queuing another scan if one has been requested */ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_INFO("Aborted scan completed.\n"); + IWL_DEBUG_INFO(priv, "Aborted scan completed.\n"); clear_bit(STATUS_SCAN_ABORTING, &priv->status); } else { /* If there are more bands on this scan pass reschedule */ @@ -268,11 +258,11 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, priv->last_scan_jiffies = jiffies; priv->next_scan_jiffies = 0; - IWL_DEBUG_INFO("Setting scan to off\n"); + IWL_DEBUG_INFO(priv, "Setting scan to off\n"); clear_bit(STATUS_SCANNING, &priv->status); - IWL_DEBUG_INFO("Scan took %dms\n", + IWL_DEBUG_INFO(priv, "Scan took %dms\n", jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies))); queue_work(priv->workqueue, &priv->scan_completed); @@ -296,9 +286,9 @@ void iwl_setup_rx_scan_handlers(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_setup_rx_scan_handlers); -static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, - enum ieee80211_band band, - u8 n_probes) +inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, + enum ieee80211_band band, + u8 n_probes) { if (band == IEEE80211_BAND_5GHZ) return IWL_ACTIVE_DWELL_TIME_52 + @@ -307,9 +297,10 @@ static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, return IWL_ACTIVE_DWELL_TIME_24 + IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1); } +EXPORT_SYMBOL(iwl_get_active_dwell_time); -static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, - enum ieee80211_band band) +u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, + enum ieee80211_band band) { u16 passive = (band == IEEE80211_BAND_2GHZ) ? IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : @@ -327,6 +318,7 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, return passive; } +EXPORT_SYMBOL(iwl_get_passive_dwell_time); static int iwl_get_channels_for_scan(struct iwl_priv *priv, enum ieee80211_band band, @@ -363,7 +355,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, ch_info = iwl_get_channel_info(priv, band, channel); if (!is_channel_valid(ch_info)) { - IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n", + IWL_DEBUG_SCAN(priv, "Channel %d is INVALID for this band.\n", channel); continue; } @@ -392,7 +384,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, else scan_ch->tx_gain = ((1 << 5) | (5 << 3)); - IWL_DEBUG_SCAN("Scanning ch=%d prob=0x%X [%s %d]\n", + IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n", channel, le32_to_cpu(scan_ch->type), (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ? "ACTIVE" : "PASSIVE", @@ -403,7 +395,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, added++; } - IWL_DEBUG_SCAN("total channels to scan %d \n", added); + IWL_DEBUG_SCAN(priv, "total channels to scan %d \n", added); return added; } @@ -419,21 +411,21 @@ void iwl_init_scan_params(struct iwl_priv *priv) int iwl_scan_initiate(struct iwl_priv *priv) { if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); + IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n"); return -EIO; } if (test_bit(STATUS_SCANNING, &priv->status)) { - IWL_DEBUG_SCAN("Scan already in progress.\n"); + IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); return -EAGAIN; } if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_SCAN("Scan request while abort pending\n"); + IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); return -EAGAIN; } - IWL_DEBUG_INFO("Starting scan...\n"); + IWL_DEBUG_INFO(priv, "Starting scan...\n"); if (priv->cfg->sku & IWL_SKU_G) priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ); if (priv->cfg->sku & IWL_SKU_A) @@ -448,9 +440,77 @@ int iwl_scan_initiate(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_scan_initiate); +#define IWL_DELAY_NEXT_SCAN (HZ*2) + +int iwl_mac_hw_scan(struct ieee80211_hw *hw, + struct cfg80211_scan_request *req) +{ + unsigned long flags; + struct iwl_priv *priv = hw->priv; + int ret; + u8 *ssid = NULL; + size_t ssid_len = 0; + + if (req->n_ssids) { + ssid = req->ssids[0].ssid; + ssid_len = req->ssids[0].ssid_len; + } + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + mutex_lock(&priv->mutex); + spin_lock_irqsave(&priv->lock, flags); + + if (!iwl_is_ready_rf(priv)) { + ret = -EIO; + IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n"); + goto out_unlock; + } + + /* We don't schedule scan within next_scan_jiffies period. + * Avoid scanning during possible EAPOL exchange, return + * success immediately. + */ + if (priv->next_scan_jiffies && + time_after(priv->next_scan_jiffies, jiffies)) { + IWL_DEBUG_SCAN(priv, "scan rejected: within next scan period\n"); + queue_work(priv->workqueue, &priv->scan_completed); + ret = 0; + goto out_unlock; + } + + /* if we just finished scan ask for delay */ + if (iwl_is_associated(priv) && priv->last_scan_jiffies && + time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { + IWL_DEBUG_SCAN(priv, "scan rejected: within previous scan period\n"); + queue_work(priv->workqueue, &priv->scan_completed); + ret = 0; + goto out_unlock; + } + + if (ssid_len) { + priv->one_direct_scan = 1; + priv->direct_ssid_len = ssid_len; + memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); + } else { + priv->one_direct_scan = 0; + } + + ret = iwl_scan_initiate(priv); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + +out_unlock: + spin_unlock_irqrestore(&priv->lock, flags); + mutex_unlock(&priv->mutex); + + return ret; +} +EXPORT_SYMBOL(iwl_mac_hw_scan); + #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) -static void iwl_bg_scan_check(struct work_struct *data) +void iwl_bg_scan_check(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, scan_check.work); @@ -461,7 +521,7 @@ static void iwl_bg_scan_check(struct work_struct *data) mutex_lock(&priv->mutex); if (test_bit(STATUS_SCANNING, &priv->status) || test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG(IWL_DL_SCAN, "Scan completion watchdog resetting " + IWL_DEBUG_SCAN(priv, "Scan completion watchdog resetting " "adapter (%dms)\n", jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG)); @@ -470,6 +530,8 @@ static void iwl_bg_scan_check(struct work_struct *data) } mutex_unlock(&priv->mutex); } +EXPORT_SYMBOL(iwl_bg_scan_check); + /** * iwl_supported_rate_to_ie - fill in the supported rate in IE field * @@ -527,10 +589,10 @@ static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, * iwl_fill_probe_req - fill in all required fields and IE for probe request */ -static u16 iwl_fill_probe_req(struct iwl_priv *priv, - enum ieee80211_band band, - struct ieee80211_mgmt *frame, - int left) +u16 iwl_fill_probe_req(struct iwl_priv *priv, + enum ieee80211_band band, + struct ieee80211_mgmt *frame, + int left) { int len = 0; u8 *pos = NULL; @@ -624,6 +686,7 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv, return (u16)len; } +EXPORT_SYMBOL(iwl_fill_probe_req); static void iwl_bg_request_scan(struct work_struct *data) { @@ -650,7 +713,7 @@ static void iwl_bg_request_scan(struct work_struct *data) mutex_lock(&priv->mutex); if (!iwl_is_ready(priv)) { - IWL_WARNING("request scan called when driver not ready.\n"); + IWL_WARN(priv, "request scan called when driver not ready.\n"); goto done; } @@ -662,34 +725,34 @@ static void iwl_bg_request_scan(struct work_struct *data) /* This should never be called or scheduled if there is currently * a scan active in the hardware. */ if (test_bit(STATUS_SCAN_HW, &priv->status)) { - IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. " + IWL_DEBUG_INFO(priv, "Multiple concurrent scan requests in parallel. " "Ignoring second request.\n"); ret = -EIO; goto done; } if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { - IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n"); + IWL_DEBUG_SCAN(priv, "Aborting scan due to device shutdown\n"); goto done; } if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_HC("Scan request while abort pending. Queuing.\n"); + IWL_DEBUG_HC(priv, "Scan request while abort pending. Queuing.\n"); goto done; } if (iwl_is_rfkill(priv)) { - IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n"); + IWL_DEBUG_HC(priv, "Aborting scan due to RF Kill activation\n"); goto done; } if (!test_bit(STATUS_READY, &priv->status)) { - IWL_DEBUG_HC("Scan request while uninitialized. Queuing.\n"); + IWL_DEBUG_HC(priv, "Scan request while uninitialized. Queuing.\n"); goto done; } if (!priv->scan_bands) { - IWL_DEBUG_HC("Aborting scan due to no requested bands\n"); + IWL_DEBUG_HC(priv, "Aborting scan due to no requested bands\n"); goto done; } @@ -714,7 +777,7 @@ static void iwl_bg_request_scan(struct work_struct *data) u32 scan_suspend_time = 100; unsigned long flags; - IWL_DEBUG_INFO("Scanning while associated...\n"); + IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); spin_lock_irqsave(&priv->lock, flags); interval = priv->beacon_int; @@ -729,13 +792,13 @@ static void iwl_bg_request_scan(struct work_struct *data) scan_suspend_time = (extra | ((suspend_time % interval) * 1024)); scan->suspend_time = cpu_to_le32(scan_suspend_time); - IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n", + IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", scan_suspend_time, interval); } /* We should add the ability for user to lock to PASSIVE ONLY */ if (priv->one_direct_scan) { - IWL_DEBUG_SCAN("Start direct scan for '%s'\n", + IWL_DEBUG_SCAN(priv, "Start direct scan for '%s'\n", print_ssid(ssid, priv->direct_ssid, priv->direct_ssid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; @@ -744,7 +807,7 @@ static void iwl_bg_request_scan(struct work_struct *data) priv->direct_ssid, priv->direct_ssid_len); n_probes++; } else { - IWL_DEBUG_SCAN("Start indirect scan.\n"); + IWL_DEBUG_SCAN(priv, "Start indirect scan.\n"); } scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; @@ -773,7 +836,7 @@ static void iwl_bg_request_scan(struct work_struct *data) if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) rx_chain = 0x6; } else { - IWL_WARNING("Invalid scan band count\n"); + IWL_WARN(priv, "Invalid scan band count\n"); goto done; } @@ -806,7 +869,7 @@ static void iwl_bg_request_scan(struct work_struct *data) (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); if (scan->channel_count == 0) { - IWL_DEBUG_SCAN("channel count %d\n", scan->channel_count); + IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); goto done; } @@ -839,7 +902,7 @@ static void iwl_bg_request_scan(struct work_struct *data) mutex_unlock(&priv->mutex); } -static void iwl_bg_abort_scan(struct work_struct *work) +void iwl_bg_abort_scan(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); @@ -853,18 +916,19 @@ static void iwl_bg_abort_scan(struct work_struct *work) mutex_unlock(&priv->mutex); } +EXPORT_SYMBOL(iwl_bg_abort_scan); -static void iwl_bg_scan_completed(struct work_struct *work) +void iwl_bg_scan_completed(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, scan_completed); - IWL_DEBUG_SCAN("SCAN complete scan\n"); + IWL_DEBUG_SCAN(priv, "SCAN complete scan\n"); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - ieee80211_scan_completed(priv->hw); + ieee80211_scan_completed(priv->hw, false); /* Since setting the TXPOWER may have been deferred while * performing the scan, fire one off */ @@ -872,7 +936,7 @@ static void iwl_bg_scan_completed(struct work_struct *work) iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); mutex_unlock(&priv->mutex); } - +EXPORT_SYMBOL(iwl_bg_scan_completed); void iwl_setup_scan_deferred_work(struct iwl_priv *priv) { |