aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-04-20 17:36:56 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-04-22 16:57:18 -0400
commit1ecf9fc1317f8df91eb1d74360f408558d657478 (patch)
tree3709c5b51fa28847a891b9a19bba693fe38f95a9 /drivers/net
parent9b3bf06abad70db820c74c90118ea49358549d22 (diff)
iwlwifi: improve scan support
This modifies iwlwifi to * no longer build its own probe request, but use mac80211's * therefore, support arbitrary scan IEs (up to the max len) * support multiple scan SSIDs * support passive scanning Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c187
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c48
6 files changed, 73 insertions, 177 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 411a5d2d9148..7b84d5246b36 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -2474,6 +2474,7 @@ struct iwl_ssid_ie {
2474#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF) 2474#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF)
2475#define IWL_GOOD_CRC_TH cpu_to_le16(1) 2475#define IWL_GOOD_CRC_TH cpu_to_le16(1)
2476#define IWL_MAX_SCAN_SIZE 1024 2476#define IWL_MAX_SCAN_SIZE 1024
2477#define IWL_MAX_PROBE_REQUEST 200
2477 2478
2478/* 2479/*
2479 * REPLY_SCAN_CMD = 0x80 (command) 2480 * REPLY_SCAN_CMD = 0x80 (command)
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index f23175240289..c43c57d7a4cb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1309,8 +1309,10 @@ int iwl_setup_mac(struct iwl_priv *priv)
1309 BIT(NL80211_IFTYPE_ADHOC); 1309 BIT(NL80211_IFTYPE_ADHOC);
1310 1310
1311 hw->wiphy->custom_regulatory = true; 1311 hw->wiphy->custom_regulatory = true;
1312 hw->wiphy->max_scan_ssids = 1; 1312
1313 hw->wiphy->max_scan_ie_len = 0; /* XXX for now */ 1313 hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
1314 /* we create the 802.11 header and a zero-length SSID element */
1315 hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
1314 1316
1315 /* Default value; 4 EDCA QOS priorities */ 1317 /* Default value; 4 EDCA QOS priorities */
1316 hw->queues = 4; 1318 hw->queues = 4;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 8773d733a54e..8ab60df48d56 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -396,8 +396,8 @@ int iwl_scan_cancel(struct iwl_priv *priv);
396int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); 396int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
397int iwl_scan_initiate(struct iwl_priv *priv); 397int iwl_scan_initiate(struct iwl_priv *priv);
398int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); 398int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
399u16 iwl_fill_probe_req(struct iwl_priv *priv, enum ieee80211_band band, 399u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
400 struct ieee80211_mgmt *frame, int left); 400 const u8 *ie, int ie_len, int left);
401void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); 401void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
402u16 iwl_get_active_dwell_time(struct iwl_priv *priv, 402u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
403 enum ieee80211_band band, 403 enum ieee80211_band band,
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 0922e33a7d42..e363d9b05eeb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -889,9 +889,7 @@ struct iwl_priv {
889 unsigned long scan_start_tsf; 889 unsigned long scan_start_tsf;
890 void *scan; 890 void *scan;
891 int scan_bands; 891 int scan_bands;
892 int one_direct_scan; 892 struct cfg80211_scan_request *scan_request;
893 u8 direct_ssid_len;
894 u8 direct_ssid[IW_ESSID_MAX_SIZE];
895 u8 scan_tx_ant[IEEE80211_NUM_BANDS]; 893 u8 scan_tx_ant[IEEE80211_NUM_BANDS];
896 u8 mgmt_tx_ant; 894 u8 mgmt_tx_ant;
897 895
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)
533EXPORT_SYMBOL(iwl_bg_scan_check); 520EXPORT_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 */
540static 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
565static 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
592u16 iwl_fill_probe_req(struct iwl_priv *priv, 526u16 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
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index ed497551a860..4df9b4b5072a 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2942,9 +2942,9 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
2942 int rc = 0; 2942 int rc = 0;
2943 struct iwl3945_scan_cmd *scan; 2943 struct iwl3945_scan_cmd *scan;
2944 struct ieee80211_conf *conf = NULL; 2944 struct ieee80211_conf *conf = NULL;
2945 u8 n_probes = 2; 2945 u8 n_probes = 0;
2946 enum ieee80211_band band; 2946 enum ieee80211_band band;
2947 DECLARE_SSID_BUF(ssid); 2947 bool is_active = false;
2948 2948
2949 conf = ieee80211_get_hw_conf(priv->hw); 2949 conf = ieee80211_get_hw_conf(priv->hw);
2950 2950
@@ -3043,18 +3043,25 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
3043 scan_suspend_time, interval); 3043 scan_suspend_time, interval);
3044 } 3044 }
3045 3045
3046 /* We should add the ability for user to lock to PASSIVE ONLY */ 3046 if (priv->scan_request->n_ssids) {
3047 if (priv->one_direct_scan) { 3047 int i, p = 0;
3048 IWL_DEBUG_SCAN(priv, "Kicking off one direct scan for '%s'\n", 3048 IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
3049 print_ssid(ssid, priv->direct_ssid, 3049 for (i = 0; i < priv->scan_request->n_ssids; i++) {
3050 priv->direct_ssid_len)); 3050 /* always does wildcard anyway */
3051 scan->direct_scan[0].id = WLAN_EID_SSID; 3051 if (!priv->scan_request->ssids[i].ssid_len)
3052 scan->direct_scan[0].len = priv->direct_ssid_len; 3052 continue;
3053 memcpy(scan->direct_scan[0].ssid, 3053 scan->direct_scan[p].id = WLAN_EID_SSID;
3054 priv->direct_ssid, priv->direct_ssid_len); 3054 scan->direct_scan[p].len =
3055 n_probes++; 3055 priv->scan_request->ssids[i].ssid_len;
3056 memcpy(scan->direct_scan[p].ssid,
3057 priv->scan_request->ssids[i].ssid,
3058 priv->scan_request->ssids[i].ssid_len);
3059 n_probes++;
3060 p++;
3061 }
3062 is_active = true;
3056 } else 3063 } else
3057 IWL_DEBUG_SCAN(priv, "Kicking off one indirect scan.\n"); 3064 IWL_DEBUG_SCAN(priv, "Kicking off passive scan.\n");
3058 3065
3059 /* We don't build a direct scan probe request; the uCode will do 3066 /* We don't build a direct scan probe request; the uCode will do
3060 * that based on the direct_mask added to each channel entry */ 3067 * that based on the direct_mask added to each channel entry */
@@ -3079,9 +3086,11 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
3079 } 3086 }
3080 3087
3081 scan->tx_cmd.len = cpu_to_le16( 3088 scan->tx_cmd.len = cpu_to_le16(
3082 iwl_fill_probe_req(priv, band, 3089 iwl_fill_probe_req(priv,
3083 (struct ieee80211_mgmt *)scan->data, 3090 (struct ieee80211_mgmt *)scan->data,
3084 IWL_MAX_SCAN_SIZE - sizeof(*scan))); 3091 priv->scan_request->ie,
3092 priv->scan_request->ie_len,
3093 IWL_MAX_SCAN_SIZE - sizeof(*scan)));
3085 3094
3086 /* select Rx antennas */ 3095 /* select Rx antennas */
3087 scan->flags |= iwl3945_get_antenna_flags(priv); 3096 scan->flags |= iwl3945_get_antenna_flags(priv);
@@ -3090,8 +3099,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
3090 scan->filter_flags = RXON_FILTER_PROMISC_MSK; 3099 scan->filter_flags = RXON_FILTER_PROMISC_MSK;
3091 3100
3092 scan->channel_count = 3101 scan->channel_count =
3093 iwl3945_get_channels_for_scan(priv, band, 1, /* active */ 3102 iwl3945_get_channels_for_scan(priv, band, is_active, n_probes,
3094 n_probes,
3095 (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); 3103 (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
3096 3104
3097 if (scan->channel_count == 0) { 3105 if (scan->channel_count == 0) {
@@ -4119,7 +4127,9 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
4119 4127
4120 hw->wiphy->custom_regulatory = true; 4128 hw->wiphy->custom_regulatory = true;
4121 4129
4122 hw->wiphy->max_scan_ssids = 1; /* WILL FIX */ 4130 hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
4131 /* we create the 802.11 header and a zero-length SSID element */
4132 hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
4123 4133
4124 /* Default value; 4 EDCA QOS priorities */ 4134 /* Default value; 4 EDCA QOS priorities */
4125 hw->queues = 4; 4135 hw->queues = 4;