diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-scan.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-scan.c | 214 |
1 files changed, 54 insertions, 160 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 6330b91e37ce..e26875dbe859 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -445,13 +445,6 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, | |||
445 | unsigned long flags; | 445 | unsigned long flags; |
446 | struct iwl_priv *priv = hw->priv; | 446 | struct iwl_priv *priv = hw->priv; |
447 | int ret; | 447 | int ret; |
448 | u8 *ssid = NULL; | ||
449 | size_t ssid_len = 0; | ||
450 | |||
451 | if (req->n_ssids) { | ||
452 | ssid = req->ssids[0].ssid; | ||
453 | ssid_len = req->ssids[0].ssid_len; | ||
454 | } | ||
455 | 448 | ||
456 | IWL_DEBUG_MAC80211(priv, "enter\n"); | 449 | IWL_DEBUG_MAC80211(priv, "enter\n"); |
457 | 450 | ||
@@ -485,13 +478,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, | |||
485 | goto out_unlock; | 478 | goto out_unlock; |
486 | } | 479 | } |
487 | 480 | ||
488 | if (ssid_len) { | 481 | priv->scan_request = req; |
489 | priv->one_direct_scan = 1; | ||
490 | priv->direct_ssid_len = ssid_len; | ||
491 | memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); | ||
492 | } else { | ||
493 | priv->one_direct_scan = 0; | ||
494 | } | ||
495 | 482 | ||
496 | ret = iwl_scan_initiate(priv); | 483 | ret = iwl_scan_initiate(priv); |
497 | 484 | ||
@@ -530,73 +517,14 @@ void iwl_bg_scan_check(struct work_struct *data) | |||
530 | EXPORT_SYMBOL(iwl_bg_scan_check); | 517 | EXPORT_SYMBOL(iwl_bg_scan_check); |
531 | 518 | ||
532 | /** | 519 | /** |
533 | * iwl_supported_rate_to_ie - fill in the supported rate in IE field | ||
534 | * | ||
535 | * return : set the bit for each supported rate insert in ie | ||
536 | */ | ||
537 | static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, | ||
538 | u16 basic_rate, int *left) | ||
539 | { | ||
540 | u16 ret_rates = 0, bit; | ||
541 | int i; | ||
542 | u8 *cnt = ie; | ||
543 | u8 *rates = ie + 1; | ||
544 | |||
545 | for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { | ||
546 | if (bit & supported_rate) { | ||
547 | ret_rates |= bit; | ||
548 | rates[*cnt] = iwl_rates[i].ieee | | ||
549 | ((bit & basic_rate) ? 0x80 : 0x00); | ||
550 | (*cnt)++; | ||
551 | (*left)--; | ||
552 | if ((*left <= 0) || | ||
553 | (*cnt >= IWL_SUPPORTED_RATES_IE_LEN)) | ||
554 | break; | ||
555 | } | ||
556 | } | ||
557 | |||
558 | return ret_rates; | ||
559 | } | ||
560 | |||
561 | |||
562 | static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, | ||
563 | u8 *pos, int *left) | ||
564 | { | ||
565 | struct ieee80211_ht_cap *ht_cap; | ||
566 | |||
567 | if (!sband || !sband->ht_cap.ht_supported) | ||
568 | return; | ||
569 | |||
570 | if (*left < sizeof(struct ieee80211_ht_cap)) | ||
571 | return; | ||
572 | |||
573 | *pos++ = sizeof(struct ieee80211_ht_cap); | ||
574 | ht_cap = (struct ieee80211_ht_cap *) pos; | ||
575 | |||
576 | ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap); | ||
577 | memcpy(&ht_cap->mcs, &sband->ht_cap.mcs, 16); | ||
578 | ht_cap->ampdu_params_info = | ||
579 | (sband->ht_cap.ampdu_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) | | ||
580 | ((sband->ht_cap.ampdu_density << 2) & | ||
581 | IEEE80211_HT_AMPDU_PARM_DENSITY); | ||
582 | *left -= sizeof(struct ieee80211_ht_cap); | ||
583 | } | ||
584 | |||
585 | /** | ||
586 | * iwl_fill_probe_req - fill in all required fields and IE for probe request | 520 | * iwl_fill_probe_req - fill in all required fields and IE for probe request |
587 | */ | 521 | */ |
588 | 522 | ||
589 | u16 iwl_fill_probe_req(struct iwl_priv *priv, | 523 | u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, |
590 | enum ieee80211_band band, | 524 | const u8 *ies, int ie_len, int left) |
591 | struct ieee80211_mgmt *frame, | ||
592 | int left) | ||
593 | { | 525 | { |
594 | int len = 0; | 526 | int len = 0; |
595 | u8 *pos = NULL; | 527 | u8 *pos = NULL; |
596 | u16 active_rates, ret_rates, cck_rates, active_rate_basic; | ||
597 | const struct ieee80211_supported_band *sband = | ||
598 | iwl_get_hw_mode(priv, band); | ||
599 | |||
600 | 528 | ||
601 | /* Make sure there is enough space for the probe request, | 529 | /* Make sure there is enough space for the probe request, |
602 | * two mandatory IEs and the data */ | 530 | * two mandatory IEs and the data */ |
@@ -624,62 +552,12 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, | |||
624 | 552 | ||
625 | len += 2; | 553 | len += 2; |
626 | 554 | ||
627 | /* fill in supported rate */ | 555 | if (WARN_ON(left < ie_len)) |
628 | left -= 2; | 556 | return len; |
629 | if (left < 0) | ||
630 | return 0; | ||
631 | |||
632 | *pos++ = WLAN_EID_SUPP_RATES; | ||
633 | *pos = 0; | ||
634 | |||
635 | /* exclude 60M rate */ | ||
636 | active_rates = priv->rates_mask; | ||
637 | active_rates &= ~IWL_RATE_60M_MASK; | ||
638 | |||
639 | active_rate_basic = active_rates & IWL_BASIC_RATES_MASK; | ||
640 | |||
641 | cck_rates = IWL_CCK_RATES_MASK & active_rates; | ||
642 | ret_rates = iwl_supported_rate_to_ie(pos, cck_rates, | ||
643 | active_rate_basic, &left); | ||
644 | active_rates &= ~ret_rates; | ||
645 | |||
646 | ret_rates = iwl_supported_rate_to_ie(pos, active_rates, | ||
647 | active_rate_basic, &left); | ||
648 | active_rates &= ~ret_rates; | ||
649 | |||
650 | len += 2 + *pos; | ||
651 | pos += (*pos) + 1; | ||
652 | 557 | ||
653 | if (active_rates == 0) | 558 | memcpy(pos, ies, ie_len); |
654 | goto fill_end; | 559 | len += ie_len; |
655 | 560 | left -= ie_len; | |
656 | /* fill in supported extended rate */ | ||
657 | /* ...next IE... */ | ||
658 | left -= 2; | ||
659 | if (left < 0) | ||
660 | return 0; | ||
661 | /* ... fill it in... */ | ||
662 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
663 | *pos = 0; | ||
664 | iwl_supported_rate_to_ie(pos, active_rates, active_rate_basic, &left); | ||
665 | if (*pos > 0) { | ||
666 | len += 2 + *pos; | ||
667 | pos += (*pos) + 1; | ||
668 | } else { | ||
669 | pos--; | ||
670 | } | ||
671 | |||
672 | fill_end: | ||
673 | |||
674 | left -= 2; | ||
675 | if (left < 0) | ||
676 | return 0; | ||
677 | |||
678 | *pos++ = WLAN_EID_HT_CAPABILITY; | ||
679 | *pos = 0; | ||
680 | iwl_ht_cap_to_ie(sband, pos, &left); | ||
681 | if (*pos > 0) | ||
682 | len += 2 + *pos; | ||
683 | 561 | ||
684 | return (u16)len; | 562 | return (u16)len; |
685 | } | 563 | } |
@@ -699,11 +577,13 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
699 | int ret = 0; | 577 | int ret = 0; |
700 | u32 rate_flags = 0; | 578 | u32 rate_flags = 0; |
701 | u16 cmd_len; | 579 | u16 cmd_len; |
580 | u16 rx_chain = 0; | ||
702 | enum ieee80211_band band; | 581 | enum ieee80211_band band; |
703 | u8 n_probes = 2; | 582 | u8 n_probes = 0; |
704 | u8 rx_chain = priv->hw_params.valid_rx_ant; | 583 | u8 rx_ant = priv->hw_params.valid_rx_ant; |
705 | u8 rate; | 584 | u8 rate; |
706 | DECLARE_SSID_BUF(ssid); | 585 | bool is_active = false; |
586 | int chan_mod; | ||
707 | 587 | ||
708 | conf = ieee80211_get_hw_conf(priv->hw); | 588 | conf = ieee80211_get_hw_conf(priv->hw); |
709 | 589 | ||
@@ -795,19 +675,25 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
795 | scan_suspend_time, interval); | 675 | scan_suspend_time, interval); |
796 | } | 676 | } |
797 | 677 | ||
798 | /* We should add the ability for user to lock to PASSIVE ONLY */ | 678 | if (priv->scan_request->n_ssids) { |
799 | if (priv->one_direct_scan) { | 679 | int i, p = 0; |
800 | IWL_DEBUG_SCAN(priv, "Start direct scan for '%s'\n", | 680 | IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); |
801 | print_ssid(ssid, priv->direct_ssid, | 681 | for (i = 0; i < priv->scan_request->n_ssids; i++) { |
802 | priv->direct_ssid_len)); | 682 | /* always does wildcard anyway */ |
803 | scan->direct_scan[0].id = WLAN_EID_SSID; | 683 | if (!priv->scan_request->ssids[i].ssid_len) |
804 | scan->direct_scan[0].len = priv->direct_ssid_len; | 684 | continue; |
805 | memcpy(scan->direct_scan[0].ssid, | 685 | scan->direct_scan[p].id = WLAN_EID_SSID; |
806 | priv->direct_ssid, priv->direct_ssid_len); | 686 | scan->direct_scan[p].len = |
807 | n_probes++; | 687 | priv->scan_request->ssids[i].ssid_len; |
808 | } else { | 688 | memcpy(scan->direct_scan[p].ssid, |
809 | IWL_DEBUG_SCAN(priv, "Start indirect scan.\n"); | 689 | priv->scan_request->ssids[i].ssid, |
810 | } | 690 | priv->scan_request->ssids[i].ssid_len); |
691 | n_probes++; | ||
692 | p++; | ||
693 | } | ||
694 | is_active = true; | ||
695 | } else | ||
696 | IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); | ||
811 | 697 | ||
812 | scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; | 698 | scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; |
813 | scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id; | 699 | scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id; |
@@ -817,7 +703,9 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
817 | if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { | 703 | if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { |
818 | band = IEEE80211_BAND_2GHZ; | 704 | band = IEEE80211_BAND_2GHZ; |
819 | scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; | 705 | scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; |
820 | if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) { | 706 | chan_mod = le32_to_cpu(priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_MSK) |
707 | >> RXON_FLG_CHANNEL_MODE_POS; | ||
708 | if (chan_mod == CHANNEL_MODE_PURE_40) { | ||
821 | rate = IWL_RATE_6M_PLCP; | 709 | rate = IWL_RATE_6M_PLCP; |
822 | } else { | 710 | } else { |
823 | rate = IWL_RATE_1M_PLCP; | 711 | rate = IWL_RATE_1M_PLCP; |
@@ -827,13 +715,18 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
827 | } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { | 715 | } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { |
828 | band = IEEE80211_BAND_5GHZ; | 716 | band = IEEE80211_BAND_5GHZ; |
829 | rate = IWL_RATE_6M_PLCP; | 717 | rate = IWL_RATE_6M_PLCP; |
830 | scan->good_CRC_th = IWL_GOOD_CRC_TH; | 718 | /* |
719 | * If active scaning is requested but a certain channel | ||
720 | * is marked passive, we can do active scanning if we | ||
721 | * detect transmissions. | ||
722 | */ | ||
723 | scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH : 0; | ||
831 | 724 | ||
832 | /* Force use of chains B and C (0x6) for scan Rx for 4965 | 725 | /* Force use of chains B and C (0x6) for scan Rx for 4965 |
833 | * Avoid A (0x1) because of its off-channel reception on A-band. | 726 | * Avoid A (0x1) because of its off-channel reception on A-band. |
834 | */ | 727 | */ |
835 | if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) | 728 | if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) |
836 | rx_chain = 0x6; | 729 | rx_ant = ANT_BC; |
837 | } else { | 730 | } else { |
838 | IWL_WARN(priv, "Invalid scan band count\n"); | 731 | IWL_WARN(priv, "Invalid scan band count\n"); |
839 | goto done; | 732 | goto done; |
@@ -845,26 +738,27 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
845 | scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); | 738 | scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); |
846 | 739 | ||
847 | /* MIMO is not used here, but value is required */ | 740 | /* MIMO is not used here, but value is required */ |
848 | scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK | | 741 | rx_chain |= ANT_ABC << RXON_RX_CHAIN_VALID_POS; |
849 | cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | | 742 | rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; |
850 | (rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) | | 743 | rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; |
851 | (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); | 744 | rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; |
852 | 745 | scan->rx_chain = cpu_to_le16(rx_chain); | |
853 | cmd_len = iwl_fill_probe_req(priv, band, | 746 | cmd_len = iwl_fill_probe_req(priv, |
854 | (struct ieee80211_mgmt *)scan->data, | 747 | (struct ieee80211_mgmt *)scan->data, |
855 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); | 748 | priv->scan_request->ie, |
749 | priv->scan_request->ie_len, | ||
750 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); | ||
856 | 751 | ||
857 | scan->tx_cmd.len = cpu_to_le16(cmd_len); | 752 | scan->tx_cmd.len = cpu_to_le16(cmd_len); |
858 | 753 | ||
859 | if (priv->iw_mode == NL80211_IFTYPE_MONITOR) | 754 | if (iwl_is_monitor_mode(priv)) |
860 | scan->filter_flags = RXON_FILTER_PROMISC_MSK; | 755 | scan->filter_flags = RXON_FILTER_PROMISC_MSK; |
861 | 756 | ||
862 | scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | | 757 | scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | |
863 | RXON_FILTER_BCON_AWARE_MSK); | 758 | RXON_FILTER_BCON_AWARE_MSK); |
864 | 759 | ||
865 | scan->channel_count = | 760 | scan->channel_count = |
866 | iwl_get_channels_for_scan(priv, band, 1, /* active */ | 761 | iwl_get_channels_for_scan(priv, band, is_active, n_probes, |
867 | n_probes, | ||
868 | (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); | 762 | (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); |
869 | 763 | ||
870 | if (scan->channel_count == 0) { | 764 | if (scan->channel_count == 0) { |