aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-scan.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c155
1 files changed, 141 insertions, 14 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index ceb91f969e45..fd6bafbddfca 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -314,6 +314,72 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
314} 314}
315EXPORT_SYMBOL(iwl_get_passive_dwell_time); 315EXPORT_SYMBOL(iwl_get_passive_dwell_time);
316 316
317static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
318 enum ieee80211_band band,
319 struct iwl_scan_channel *scan_ch)
320{
321 const struct ieee80211_supported_band *sband;
322 const struct iwl_channel_info *ch_info;
323 u16 passive_dwell = 0;
324 u16 active_dwell = 0;
325 int i, added = 0;
326 u16 channel = 0;
327
328 sband = iwl_get_hw_mode(priv, band);
329 if (!sband) {
330 IWL_ERR(priv, "invalid band\n");
331 return added;
332 }
333
334 active_dwell = iwl_get_active_dwell_time(priv, band, 0);
335 passive_dwell = iwl_get_passive_dwell_time(priv, band);
336
337 if (passive_dwell <= active_dwell)
338 passive_dwell = active_dwell + 1;
339
340 /* only scan single channel, good enough to reset the RF */
341 /* pick the first valid not in-use channel */
342 if (band == IEEE80211_BAND_5GHZ) {
343 for (i = 14; i < priv->channel_count; i++) {
344 if (priv->channel_info[i].channel !=
345 le16_to_cpu(priv->staging_rxon.channel)) {
346 channel = priv->channel_info[i].channel;
347 ch_info = iwl_get_channel_info(priv,
348 band, channel);
349 if (is_channel_valid(ch_info))
350 break;
351 }
352 }
353 } else {
354 for (i = 0; i < 14; i++) {
355 if (priv->channel_info[i].channel !=
356 le16_to_cpu(priv->staging_rxon.channel)) {
357 channel =
358 priv->channel_info[i].channel;
359 ch_info = iwl_get_channel_info(priv,
360 band, channel);
361 if (is_channel_valid(ch_info))
362 break;
363 }
364 }
365 }
366 if (channel) {
367 scan_ch->channel = cpu_to_le16(channel);
368 scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
369 scan_ch->active_dwell = cpu_to_le16(active_dwell);
370 scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
371 /* Set txpower levels to defaults */
372 scan_ch->dsp_atten = 110;
373 if (band == IEEE80211_BAND_5GHZ)
374 scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
375 else
376 scan_ch->tx_gain = ((1 << 5) | (5 << 3));
377 added++;
378 } else
379 IWL_ERR(priv, "no valid channel found\n");
380 return added;
381}
382
317static int iwl_get_channels_for_scan(struct iwl_priv *priv, 383static int iwl_get_channels_for_scan(struct iwl_priv *priv,
318 enum ieee80211_band band, 384 enum ieee80211_band band,
319 u8 is_active, u8 n_probes, 385 u8 is_active, u8 n_probes,
@@ -421,6 +487,7 @@ static int iwl_scan_initiate(struct iwl_priv *priv)
421 487
422 IWL_DEBUG_INFO(priv, "Starting scan...\n"); 488 IWL_DEBUG_INFO(priv, "Starting scan...\n");
423 set_bit(STATUS_SCANNING, &priv->status); 489 set_bit(STATUS_SCANNING, &priv->status);
490 priv->is_internal_short_scan = false;
424 priv->scan_start = jiffies; 491 priv->scan_start = jiffies;
425 priv->scan_pass_start = priv->scan_start; 492 priv->scan_pass_start = priv->scan_start;
426 493
@@ -488,6 +555,45 @@ out_unlock:
488} 555}
489EXPORT_SYMBOL(iwl_mac_hw_scan); 556EXPORT_SYMBOL(iwl_mac_hw_scan);
490 557
558/*
559 * internal short scan, this function should only been called while associated.
560 * It will reset and tune the radio to prevent possible RF related problem
561 */
562int iwl_internal_short_hw_scan(struct iwl_priv *priv)
563{
564 int ret = 0;
565
566 if (!iwl_is_ready_rf(priv)) {
567 ret = -EIO;
568 IWL_DEBUG_SCAN(priv, "not ready or exit pending\n");
569 goto out;
570 }
571 if (test_bit(STATUS_SCANNING, &priv->status)) {
572 IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
573 ret = -EAGAIN;
574 goto out;
575 }
576 if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
577 IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
578 ret = -EAGAIN;
579 goto out;
580 }
581 priv->scan_bands = 0;
582 if (priv->band == IEEE80211_BAND_5GHZ)
583 priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
584 else
585 priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
586
587 IWL_DEBUG_SCAN(priv, "Start internal short scan...\n");
588 set_bit(STATUS_SCANNING, &priv->status);
589 priv->is_internal_short_scan = true;
590 queue_work(priv->workqueue, &priv->request_scan);
591
592out:
593 return ret;
594}
595EXPORT_SYMBOL(iwl_internal_short_hw_scan);
596
491#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) 597#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
492 598
493void iwl_bg_scan_check(struct work_struct *data) 599void iwl_bg_scan_check(struct work_struct *data)
@@ -551,7 +657,8 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
551 if (WARN_ON(left < ie_len)) 657 if (WARN_ON(left < ie_len))
552 return len; 658 return len;
553 659
554 memcpy(pos, ies, ie_len); 660 if (ies)
661 memcpy(pos, ies, ie_len);
555 len += ie_len; 662 len += ie_len;
556 left -= ie_len; 663 left -= ie_len;
557 664
@@ -654,7 +761,6 @@ static void iwl_bg_request_scan(struct work_struct *data)
654 unsigned long flags; 761 unsigned long flags;
655 762
656 IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); 763 IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
657
658 spin_lock_irqsave(&priv->lock, flags); 764 spin_lock_irqsave(&priv->lock, flags);
659 interval = priv->beacon_int; 765 interval = priv->beacon_int;
660 spin_unlock_irqrestore(&priv->lock, flags); 766 spin_unlock_irqrestore(&priv->lock, flags);
@@ -672,7 +778,9 @@ static void iwl_bg_request_scan(struct work_struct *data)
672 scan_suspend_time, interval); 778 scan_suspend_time, interval);
673 } 779 }
674 780
675 if (priv->scan_request->n_ssids) { 781 if (priv->is_internal_short_scan) {
782 IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
783 } else if (priv->scan_request->n_ssids) {
676 int i, p = 0; 784 int i, p = 0;
677 IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); 785 IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
678 for (i = 0; i < priv->scan_request->n_ssids; i++) { 786 for (i = 0; i < priv->scan_request->n_ssids; i++) {
@@ -753,24 +861,38 @@ static void iwl_bg_request_scan(struct work_struct *data)
753 rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; 861 rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
754 rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; 862 rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
755 scan->rx_chain = cpu_to_le16(rx_chain); 863 scan->rx_chain = cpu_to_le16(rx_chain);
756 cmd_len = iwl_fill_probe_req(priv, 864 if (!priv->is_internal_short_scan) {
757 (struct ieee80211_mgmt *)scan->data, 865 cmd_len = iwl_fill_probe_req(priv,
758 priv->scan_request->ie, 866 (struct ieee80211_mgmt *)scan->data,
759 priv->scan_request->ie_len, 867 priv->scan_request->ie,
760 IWL_MAX_SCAN_SIZE - sizeof(*scan)); 868 priv->scan_request->ie_len,
869 IWL_MAX_SCAN_SIZE - sizeof(*scan));
870 } else {
871 cmd_len = iwl_fill_probe_req(priv,
872 (struct ieee80211_mgmt *)scan->data,
873 NULL, 0,
874 IWL_MAX_SCAN_SIZE - sizeof(*scan));
761 875
876 }
762 scan->tx_cmd.len = cpu_to_le16(cmd_len); 877 scan->tx_cmd.len = cpu_to_le16(cmd_len);
763
764 if (iwl_is_monitor_mode(priv)) 878 if (iwl_is_monitor_mode(priv))
765 scan->filter_flags = RXON_FILTER_PROMISC_MSK; 879 scan->filter_flags = RXON_FILTER_PROMISC_MSK;
766 880
767 scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | 881 scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
768 RXON_FILTER_BCON_AWARE_MSK); 882 RXON_FILTER_BCON_AWARE_MSK);
769 883
770 scan->channel_count = 884 if (priv->is_internal_short_scan) {
771 iwl_get_channels_for_scan(priv, band, is_active, n_probes, 885 scan->channel_count =
772 (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); 886 iwl_get_single_channel_for_scan(priv, band,
773 887 (void *)&scan->data[le16_to_cpu(
888 scan->tx_cmd.len)]);
889 } else {
890 scan->channel_count =
891 iwl_get_channels_for_scan(priv, band,
892 is_active, n_probes,
893 (void *)&scan->data[le16_to_cpu(
894 scan->tx_cmd.len)]);
895 }
774 if (scan->channel_count == 0) { 896 if (scan->channel_count == 0) {
775 IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); 897 IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
776 goto done; 898 goto done;
@@ -831,7 +953,12 @@ void iwl_bg_scan_completed(struct work_struct *work)
831 953
832 cancel_delayed_work(&priv->scan_check); 954 cancel_delayed_work(&priv->scan_check);
833 955
834 ieee80211_scan_completed(priv->hw, false); 956 if (!priv->is_internal_short_scan)
957 ieee80211_scan_completed(priv->hw, false);
958 else {
959 priv->is_internal_short_scan = false;
960 IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
961 }
835 962
836 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 963 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
837 return; 964 return;