diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-scan.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-scan.c | 187 |
1 files changed, 36 insertions, 151 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 23644cf884f1..9edcf8c76b20 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -448,13 +448,6 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, | |||
448 | unsigned long flags; | 448 | unsigned long flags; |
449 | struct iwl_priv *priv = hw->priv; | 449 | struct iwl_priv *priv = hw->priv; |
450 | int ret; | 450 | int ret; |
451 | u8 *ssid = NULL; | ||
452 | size_t ssid_len = 0; | ||
453 | |||
454 | if (req->n_ssids) { | ||
455 | ssid = req->ssids[0].ssid; | ||
456 | ssid_len = req->ssids[0].ssid_len; | ||
457 | } | ||
458 | 451 | ||
459 | IWL_DEBUG_MAC80211(priv, "enter\n"); | 452 | IWL_DEBUG_MAC80211(priv, "enter\n"); |
460 | 453 | ||
@@ -488,13 +481,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, | |||
488 | goto out_unlock; | 481 | goto out_unlock; |
489 | } | 482 | } |
490 | 483 | ||
491 | if (ssid_len) { | 484 | priv->scan_request = req; |
492 | priv->one_direct_scan = 1; | ||
493 | priv->direct_ssid_len = ssid_len; | ||
494 | memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); | ||
495 | } else { | ||
496 | priv->one_direct_scan = 0; | ||
497 | } | ||
498 | 485 | ||
499 | ret = iwl_scan_initiate(priv); | 486 | ret = iwl_scan_initiate(priv); |
500 | 487 | ||
@@ -533,73 +520,14 @@ void iwl_bg_scan_check(struct work_struct *data) | |||
533 | EXPORT_SYMBOL(iwl_bg_scan_check); | 520 | EXPORT_SYMBOL(iwl_bg_scan_check); |
534 | 521 | ||
535 | /** | 522 | /** |
536 | * iwl_supported_rate_to_ie - fill in the supported rate in IE field | ||
537 | * | ||
538 | * return : set the bit for each supported rate insert in ie | ||
539 | */ | ||
540 | static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, | ||
541 | u16 basic_rate, int *left) | ||
542 | { | ||
543 | u16 ret_rates = 0, bit; | ||
544 | int i; | ||
545 | u8 *cnt = ie; | ||
546 | u8 *rates = ie + 1; | ||
547 | |||
548 | for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { | ||
549 | if (bit & supported_rate) { | ||
550 | ret_rates |= bit; | ||
551 | rates[*cnt] = iwl_rates[i].ieee | | ||
552 | ((bit & basic_rate) ? 0x80 : 0x00); | ||
553 | (*cnt)++; | ||
554 | (*left)--; | ||
555 | if ((*left <= 0) || | ||
556 | (*cnt >= IWL_SUPPORTED_RATES_IE_LEN)) | ||
557 | break; | ||
558 | } | ||
559 | } | ||
560 | |||
561 | return ret_rates; | ||
562 | } | ||
563 | |||
564 | |||
565 | static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, | ||
566 | u8 *pos, int *left) | ||
567 | { | ||
568 | struct ieee80211_ht_cap *ht_cap; | ||
569 | |||
570 | if (!sband || !sband->ht_cap.ht_supported) | ||
571 | return; | ||
572 | |||
573 | if (*left < sizeof(struct ieee80211_ht_cap)) | ||
574 | return; | ||
575 | |||
576 | *pos++ = sizeof(struct ieee80211_ht_cap); | ||
577 | ht_cap = (struct ieee80211_ht_cap *) pos; | ||
578 | |||
579 | ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap); | ||
580 | memcpy(&ht_cap->mcs, &sband->ht_cap.mcs, 16); | ||
581 | ht_cap->ampdu_params_info = | ||
582 | (sband->ht_cap.ampdu_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) | | ||
583 | ((sband->ht_cap.ampdu_density << 2) & | ||
584 | IEEE80211_HT_AMPDU_PARM_DENSITY); | ||
585 | *left -= sizeof(struct ieee80211_ht_cap); | ||
586 | } | ||
587 | |||
588 | /** | ||
589 | * iwl_fill_probe_req - fill in all required fields and IE for probe request | 523 | * iwl_fill_probe_req - fill in all required fields and IE for probe request |
590 | */ | 524 | */ |
591 | 525 | ||
592 | u16 iwl_fill_probe_req(struct iwl_priv *priv, | 526 | u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, |
593 | enum ieee80211_band band, | 527 | const u8 *ies, int ie_len, int left) |
594 | struct ieee80211_mgmt *frame, | ||
595 | int left) | ||
596 | { | 528 | { |
597 | int len = 0; | 529 | int len = 0; |
598 | u8 *pos = NULL; | 530 | u8 *pos = NULL; |
599 | u16 active_rates, ret_rates, cck_rates, active_rate_basic; | ||
600 | const struct ieee80211_supported_band *sband = | ||
601 | iwl_get_hw_mode(priv, band); | ||
602 | |||
603 | 531 | ||
604 | /* Make sure there is enough space for the probe request, | 532 | /* Make sure there is enough space for the probe request, |
605 | * two mandatory IEs and the data */ | 533 | * two mandatory IEs and the data */ |
@@ -627,62 +555,12 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, | |||
627 | 555 | ||
628 | len += 2; | 556 | len += 2; |
629 | 557 | ||
630 | /* fill in supported rate */ | 558 | if (WARN_ON(left < ie_len)) |
631 | left -= 2; | 559 | return len; |
632 | if (left < 0) | ||
633 | return 0; | ||
634 | |||
635 | *pos++ = WLAN_EID_SUPP_RATES; | ||
636 | *pos = 0; | ||
637 | |||
638 | /* exclude 60M rate */ | ||
639 | active_rates = priv->rates_mask; | ||
640 | active_rates &= ~IWL_RATE_60M_MASK; | ||
641 | |||
642 | active_rate_basic = active_rates & IWL_BASIC_RATES_MASK; | ||
643 | |||
644 | cck_rates = IWL_CCK_RATES_MASK & active_rates; | ||
645 | ret_rates = iwl_supported_rate_to_ie(pos, cck_rates, | ||
646 | active_rate_basic, &left); | ||
647 | active_rates &= ~ret_rates; | ||
648 | |||
649 | ret_rates = iwl_supported_rate_to_ie(pos, active_rates, | ||
650 | active_rate_basic, &left); | ||
651 | active_rates &= ~ret_rates; | ||
652 | 560 | ||
653 | len += 2 + *pos; | 561 | memcpy(pos, ies, ie_len); |
654 | pos += (*pos) + 1; | 562 | len += ie_len; |
655 | 563 | left -= ie_len; | |
656 | if (active_rates == 0) | ||
657 | goto fill_end; | ||
658 | |||
659 | /* fill in supported extended rate */ | ||
660 | /* ...next IE... */ | ||
661 | left -= 2; | ||
662 | if (left < 0) | ||
663 | return 0; | ||
664 | /* ... fill it in... */ | ||
665 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
666 | *pos = 0; | ||
667 | iwl_supported_rate_to_ie(pos, active_rates, active_rate_basic, &left); | ||
668 | if (*pos > 0) { | ||
669 | len += 2 + *pos; | ||
670 | pos += (*pos) + 1; | ||
671 | } else { | ||
672 | pos--; | ||
673 | } | ||
674 | |||
675 | fill_end: | ||
676 | |||
677 | left -= 2; | ||
678 | if (left < 0) | ||
679 | return 0; | ||
680 | |||
681 | *pos++ = WLAN_EID_HT_CAPABILITY; | ||
682 | *pos = 0; | ||
683 | iwl_ht_cap_to_ie(sband, pos, &left); | ||
684 | if (*pos > 0) | ||
685 | len += 2 + *pos; | ||
686 | 564 | ||
687 | return (u16)len; | 565 | return (u16)len; |
688 | } | 566 | } |
@@ -703,10 +581,10 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
703 | u32 rate_flags = 0; | 581 | u32 rate_flags = 0; |
704 | u16 cmd_len; | 582 | u16 cmd_len; |
705 | enum ieee80211_band band; | 583 | enum ieee80211_band band; |
706 | u8 n_probes = 2; | 584 | u8 n_probes = 0; |
707 | u8 rx_chain = priv->hw_params.valid_rx_ant; | 585 | u8 rx_chain = priv->hw_params.valid_rx_ant; |
708 | u8 rate; | 586 | u8 rate; |
709 | DECLARE_SSID_BUF(ssid); | 587 | bool is_active = false; |
710 | 588 | ||
711 | conf = ieee80211_get_hw_conf(priv->hw); | 589 | conf = ieee80211_get_hw_conf(priv->hw); |
712 | 590 | ||
@@ -796,19 +674,25 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
796 | scan_suspend_time, interval); | 674 | scan_suspend_time, interval); |
797 | } | 675 | } |
798 | 676 | ||
799 | /* We should add the ability for user to lock to PASSIVE ONLY */ | 677 | if (priv->scan_request->n_ssids) { |
800 | if (priv->one_direct_scan) { | 678 | int i, p = 0; |
801 | IWL_DEBUG_SCAN(priv, "Start direct scan for '%s'\n", | 679 | IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); |
802 | print_ssid(ssid, priv->direct_ssid, | 680 | for (i = 0; i < priv->scan_request->n_ssids; i++) { |
803 | priv->direct_ssid_len)); | 681 | /* always does wildcard anyway */ |
804 | scan->direct_scan[0].id = WLAN_EID_SSID; | 682 | if (!priv->scan_request->ssids[i].ssid_len) |
805 | scan->direct_scan[0].len = priv->direct_ssid_len; | 683 | continue; |
806 | memcpy(scan->direct_scan[0].ssid, | 684 | scan->direct_scan[p].id = WLAN_EID_SSID; |
807 | priv->direct_ssid, priv->direct_ssid_len); | 685 | scan->direct_scan[p].len = |
808 | n_probes++; | 686 | priv->scan_request->ssids[i].ssid_len; |
809 | } else { | 687 | memcpy(scan->direct_scan[p].ssid, |
810 | IWL_DEBUG_SCAN(priv, "Start indirect scan.\n"); | 688 | priv->scan_request->ssids[i].ssid, |
811 | } | 689 | priv->scan_request->ssids[i].ssid_len); |
690 | n_probes++; | ||
691 | p++; | ||
692 | } | ||
693 | is_active = true; | ||
694 | } else | ||
695 | IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); | ||
812 | 696 | ||
813 | scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; | 697 | scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; |
814 | scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id; | 698 | scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id; |
@@ -850,10 +734,11 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
850 | cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | | 734 | cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | |
851 | (rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) | | 735 | (rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) | |
852 | (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); | 736 | (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); |
853 | 737 | cmd_len = iwl_fill_probe_req(priv, | |
854 | cmd_len = iwl_fill_probe_req(priv, band, | 738 | (struct ieee80211_mgmt *)scan->data, |
855 | (struct ieee80211_mgmt *)scan->data, | 739 | priv->scan_request->ie, |
856 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); | 740 | priv->scan_request->ie_len, |
741 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); | ||
857 | 742 | ||
858 | scan->tx_cmd.len = cpu_to_le16(cmd_len); | 743 | scan->tx_cmd.len = cpu_to_le16(cmd_len); |
859 | 744 | ||
@@ -864,8 +749,7 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
864 | RXON_FILTER_BCON_AWARE_MSK); | 749 | RXON_FILTER_BCON_AWARE_MSK); |
865 | 750 | ||
866 | scan->channel_count = | 751 | scan->channel_count = |
867 | iwl_get_channels_for_scan(priv, band, 1, /* active */ | 752 | iwl_get_channels_for_scan(priv, band, is_active, n_probes, |
868 | n_probes, | ||
869 | (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); | 753 | (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); |
870 | 754 | ||
871 | if (scan->channel_count == 0) { | 755 | if (scan->channel_count == 0) { |
@@ -928,6 +812,7 @@ void iwl_bg_scan_completed(struct work_struct *work) | |||
928 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 812 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
929 | return; | 813 | return; |
930 | 814 | ||
815 | priv->scan_request = NULL; | ||
931 | ieee80211_scan_completed(priv->hw, false); | 816 | ieee80211_scan_completed(priv->hw, false); |
932 | 817 | ||
933 | /* Since setting the TXPOWER may have been deferred while | 818 | /* Since setting the TXPOWER may have been deferred while |