aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Spinadel <david.spinadel@intel.com>2014-02-05 08:21:13 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-06-25 03:10:42 -0400
commitc56ef6725068c0ce499e517409c0da226ef51b08 (patch)
tree75133e7a2b9df5b2d6a2766e6fee024ba6fd17af
parentee10f2c779b28c1d6e87ac3e1bbb1aa8b62fa891 (diff)
mac80211: support more than one band in scan request
Some drivers (such as iwlmvm) can handle multiple bands in a single HW scan request. Add a HW flag to indicate that the driver support this. To hold the required data, create a separate structure for HW scan request that holds cfg scan request and data about different parts of the scan IEs. As this changes the mac80211 API, update all drivers using it to use the correct new function type/argument. Signed-off-by: David Spinadel <david.spinadel@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--drivers/net/wireless/at76c50x-usb.c3
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c3
-rw-r--r--drivers/net/wireless/cw1200/scan.c3
-rw-r--r--drivers/net/wireless/cw1200/scan.h2
-rw-r--r--drivers/net/wireless/iwlegacy/common.c3
-rw-r--r--drivers/net/wireless/iwlegacy/common.h2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c3
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c3
-rw-r--r--drivers/net/wireless/ti/wl1251/main.c3
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c3
-rw-r--r--include/net/mac80211.h39
-rw-r--r--net/mac80211/driver-ops.h2
-rw-r--r--net/mac80211/ieee80211_i.h9
-rw-r--r--net/mac80211/scan.c85
-rw-r--r--net/mac80211/util.c105
16 files changed, 198 insertions, 73 deletions
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index d48776e4f343..334c2ece855a 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1955,8 +1955,9 @@ static void at76_dwork_hw_scan(struct work_struct *work)
1955 1955
1956static int at76_hw_scan(struct ieee80211_hw *hw, 1956static int at76_hw_scan(struct ieee80211_hw *hw,
1957 struct ieee80211_vif *vif, 1957 struct ieee80211_vif *vif,
1958 struct cfg80211_scan_request *req) 1958 struct ieee80211_scan_request *hw_req)
1959{ 1959{
1960 struct cfg80211_scan_request *req = &hw_req->req;
1960 struct at76_priv *priv = hw->priv; 1961 struct at76_priv *priv = hw->priv;
1961 struct at76_req_scan scan; 1962 struct at76_req_scan scan;
1962 u8 *ssid = NULL; 1963 u8 *ssid = NULL;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index a21080028c54..b8314a534972 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3137,10 +3137,11 @@ exit:
3137 3137
3138static int ath10k_hw_scan(struct ieee80211_hw *hw, 3138static int ath10k_hw_scan(struct ieee80211_hw *hw,
3139 struct ieee80211_vif *vif, 3139 struct ieee80211_vif *vif,
3140 struct cfg80211_scan_request *req) 3140 struct ieee80211_scan_request *hw_req)
3141{ 3141{
3142 struct ath10k *ar = hw->priv; 3142 struct ath10k *ar = hw->priv;
3143 struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); 3143 struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
3144 struct cfg80211_scan_request *req = &hw_req->req;
3144 struct wmi_start_scan_arg arg; 3145 struct wmi_start_scan_arg arg;
3145 int ret = 0; 3146 int ret = 0;
3146 int i; 3147 int i;
diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c
index 9afcd4ce3368..b2fb6c632092 100644
--- a/drivers/net/wireless/cw1200/scan.c
+++ b/drivers/net/wireless/cw1200/scan.c
@@ -53,9 +53,10 @@ static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan)
53 53
54int cw1200_hw_scan(struct ieee80211_hw *hw, 54int cw1200_hw_scan(struct ieee80211_hw *hw,
55 struct ieee80211_vif *vif, 55 struct ieee80211_vif *vif,
56 struct cfg80211_scan_request *req) 56 struct ieee80211_scan_request *hw_req)
57{ 57{
58 struct cw1200_common *priv = hw->priv; 58 struct cw1200_common *priv = hw->priv;
59 struct cfg80211_scan_request *req = &hw_req->req;
59 struct wsm_template_frame frame = { 60 struct wsm_template_frame frame = {
60 .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, 61 .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST,
61 }; 62 };
diff --git a/drivers/net/wireless/cw1200/scan.h b/drivers/net/wireless/cw1200/scan.h
index 5a8296ccfa82..cc75459e5784 100644
--- a/drivers/net/wireless/cw1200/scan.h
+++ b/drivers/net/wireless/cw1200/scan.h
@@ -41,7 +41,7 @@ struct cw1200_scan {
41 41
42int cw1200_hw_scan(struct ieee80211_hw *hw, 42int cw1200_hw_scan(struct ieee80211_hw *hw,
43 struct ieee80211_vif *vif, 43 struct ieee80211_vif *vif,
44 struct cfg80211_scan_request *req); 44 struct ieee80211_scan_request *hw_req);
45void cw1200_scan_work(struct work_struct *work); 45void cw1200_scan_work(struct work_struct *work);
46void cw1200_scan_timeout(struct work_struct *work); 46void cw1200_scan_timeout(struct work_struct *work);
47void cw1200_clear_recent_scan_work(struct work_struct *work); 47void cw1200_clear_recent_scan_work(struct work_struct *work);
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c
index ecc674627e6e..03de7467aecf 100644
--- a/drivers/net/wireless/iwlegacy/common.c
+++ b/drivers/net/wireless/iwlegacy/common.c
@@ -1572,8 +1572,9 @@ il_scan_initiate(struct il_priv *il, struct ieee80211_vif *vif)
1572 1572
1573int 1573int
1574il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1574il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1575 struct cfg80211_scan_request *req) 1575 struct ieee80211_scan_request *hw_req)
1576{ 1576{
1577 struct cfg80211_scan_request *req = &hw_req->req;
1577 struct il_priv *il = hw->priv; 1578 struct il_priv *il = hw->priv;
1578 int ret; 1579 int ret;
1579 1580
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h
index ea5c0f863c4e..5b972798bdff 100644
--- a/drivers/net/wireless/iwlegacy/common.h
+++ b/drivers/net/wireless/iwlegacy/common.h
@@ -1787,7 +1787,7 @@ int il_scan_cancel(struct il_priv *il);
1787int il_scan_cancel_timeout(struct il_priv *il, unsigned long ms); 1787int il_scan_cancel_timeout(struct il_priv *il, unsigned long ms);
1788void il_force_scan_end(struct il_priv *il); 1788void il_force_scan_end(struct il_priv *il);
1789int il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1789int il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1790 struct cfg80211_scan_request *req); 1790 struct ieee80211_scan_request *hw_req);
1791void il_internal_short_hw_scan(struct il_priv *il); 1791void il_internal_short_hw_scan(struct il_priv *il);
1792int il_force_reset(struct il_priv *il, bool external); 1792int il_force_reset(struct il_priv *il, bool external);
1793u16 il_fill_probe_req(struct il_priv *il, struct ieee80211_mgmt *frame, 1793u16 il_fill_probe_req(struct il_priv *il, struct ieee80211_mgmt *frame,
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 29af7b51e370..afb98f4fdaf3 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -1495,9 +1495,10 @@ static int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
1495 1495
1496static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, 1496static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
1497 struct ieee80211_vif *vif, 1497 struct ieee80211_vif *vif,
1498 struct cfg80211_scan_request *req) 1498 struct ieee80211_scan_request *hw_req)
1499{ 1499{
1500 struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); 1500 struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
1501 struct cfg80211_scan_request *req = &hw_req->req;
1501 int ret; 1502 int ret;
1502 1503
1503 IWL_DEBUG_MAC80211(priv, "enter\n"); 1504 IWL_DEBUG_MAC80211(priv, "enter\n");
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 7215f5980186..4dc2e05f49ce 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -1537,9 +1537,10 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
1537 1537
1538static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, 1538static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
1539 struct ieee80211_vif *vif, 1539 struct ieee80211_vif *vif,
1540 struct cfg80211_scan_request *req) 1540 struct ieee80211_scan_request *hw_req)
1541{ 1541{
1542 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 1542 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1543 struct cfg80211_scan_request *req = &hw_req->req;
1543 int ret; 1544 int ret;
1544 1545
1545 if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS) 1546 if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS)
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 06a0722164da..eba51460a5de 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1736,9 +1736,10 @@ static void hw_scan_work(struct work_struct *work)
1736 1736
1737static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, 1737static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
1738 struct ieee80211_vif *vif, 1738 struct ieee80211_vif *vif,
1739 struct cfg80211_scan_request *req) 1739 struct ieee80211_scan_request *hw_req)
1740{ 1740{
1741 struct mac80211_hwsim_data *hwsim = hw->priv; 1741 struct mac80211_hwsim_data *hwsim = hw->priv;
1742 struct cfg80211_scan_request *req = &hw_req->req;
1742 1743
1743 mutex_lock(&hwsim->mutex); 1744 mutex_lock(&hwsim->mutex);
1744 if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { 1745 if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) {
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 4e782f18ae34..38234851457e 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -991,8 +991,9 @@ out:
991 991
992static int wl1251_op_hw_scan(struct ieee80211_hw *hw, 992static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
993 struct ieee80211_vif *vif, 993 struct ieee80211_vif *vif,
994 struct cfg80211_scan_request *req) 994 struct ieee80211_scan_request *hw_req)
995{ 995{
996 struct cfg80211_scan_request *req = &hw_req->req;
996 struct wl1251 *wl = hw->priv; 997 struct wl1251 *wl = hw->priv;
997 struct sk_buff *skb; 998 struct sk_buff *skb;
998 size_t ssid_len = 0; 999 size_t ssid_len = 0;
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 3d6028e62750..e5ffb8b91dd4 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -3540,8 +3540,9 @@ out:
3540 3540
3541static int wl1271_op_hw_scan(struct ieee80211_hw *hw, 3541static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
3542 struct ieee80211_vif *vif, 3542 struct ieee80211_vif *vif,
3543 struct cfg80211_scan_request *req) 3543 struct ieee80211_scan_request *hw_req)
3544{ 3544{
3545 struct cfg80211_scan_request *req = &hw_req->req;
3545 struct wl1271 *wl = hw->priv; 3546 struct wl1271 *wl = hw->priv;
3546 int ret; 3547 int ret;
3547 u8 *ssid = NULL; 3548 u8 *ssid = NULL;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 18c2bdbaf988..9536ee3e22a9 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -768,6 +768,26 @@ struct ieee80211_sched_scan_ies {
768 size_t len[IEEE80211_NUM_BANDS]; 768 size_t len[IEEE80211_NUM_BANDS];
769}; 769};
770 770
771/**
772 * struct ieee80211_scan_ies - descriptors for different blocks of IEs
773 *
774 * This structure is used to point to different blocks of IEs in HW scan.
775 * These blocks contain the IEs passed by userspace and the ones generated
776 * by mac80211.
777 *
778 * @ies: pointers to band specific IEs.
779 * @len: lengths of band_specific IEs.
780 * @common_ies: IEs for all bands (especially vendor specific ones)
781 * @common_ie_len: length of the common_ies
782 */
783struct ieee80211_scan_ies {
784 const u8 *ies[IEEE80211_NUM_BANDS];
785 size_t len[IEEE80211_NUM_BANDS];
786 const u8 *common_ies;
787 size_t common_ie_len;
788};
789
790
771static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) 791static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb)
772{ 792{
773 return (struct ieee80211_tx_info *)skb->cb; 793 return (struct ieee80211_tx_info *)skb->cb;
@@ -1606,6 +1626,9 @@ struct ieee80211_tx_control {
1606 * on single-channel hardware. It can also be used as an 1626 * on single-channel hardware. It can also be used as an
1607 * optimization in certain channel switch cases with 1627 * optimization in certain channel switch cases with
1608 * multi-channel. 1628 * multi-channel.
1629 *
1630 * @IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS: The HW supports scanning on all bands
1631 * in one command, mac80211 doesn't have to run separate scans per band.
1609 */ 1632 */
1610enum ieee80211_hw_flags { 1633enum ieee80211_hw_flags {
1611 IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, 1634 IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
@@ -1638,6 +1661,7 @@ enum ieee80211_hw_flags {
1638 IEEE80211_HW_SUPPORTS_HT_CCK_RATES = 1<<27, 1661 IEEE80211_HW_SUPPORTS_HT_CCK_RATES = 1<<27,
1639 IEEE80211_HW_CHANCTX_STA_CSA = 1<<28, 1662 IEEE80211_HW_CHANCTX_STA_CSA = 1<<28,
1640 IEEE80211_HW_CHANGE_RUNNING_CHANCTX = 1<<29, 1663 IEEE80211_HW_CHANGE_RUNNING_CHANCTX = 1<<29,
1664 IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS = 1<<30,
1641}; 1665};
1642 1666
1643/** 1667/**
@@ -1764,6 +1788,19 @@ struct ieee80211_hw {
1764}; 1788};
1765 1789
1766/** 1790/**
1791 * struct ieee80211_scan_request - hw scan request
1792 *
1793 * @ies: pointers different parts of IEs (in req.ie)
1794 * @req: cfg80211 request.
1795 */
1796struct ieee80211_scan_request {
1797 struct ieee80211_scan_ies ies;
1798
1799 /* Keep last */
1800 struct cfg80211_scan_request req;
1801};
1802
1803/**
1767 * wiphy_to_ieee80211_hw - return a mac80211 driver hw struct from a wiphy 1804 * wiphy_to_ieee80211_hw - return a mac80211 driver hw struct from a wiphy
1768 * 1805 *
1769 * @wiphy: the &struct wiphy which we want to query 1806 * @wiphy: the &struct wiphy which we want to query
@@ -2874,7 +2911,7 @@ struct ieee80211_ops {
2874 void (*set_default_unicast_key)(struct ieee80211_hw *hw, 2911 void (*set_default_unicast_key)(struct ieee80211_hw *hw,
2875 struct ieee80211_vif *vif, int idx); 2912 struct ieee80211_vif *vif, int idx);
2876 int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 2913 int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
2877 struct cfg80211_scan_request *req); 2914 struct ieee80211_scan_request *req);
2878 void (*cancel_hw_scan)(struct ieee80211_hw *hw, 2915 void (*cancel_hw_scan)(struct ieee80211_hw *hw,
2879 struct ieee80211_vif *vif); 2916 struct ieee80211_vif *vif);
2880 int (*sched_scan_start)(struct ieee80211_hw *hw, 2917 int (*sched_scan_start)(struct ieee80211_hw *hw,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 2265bd7a44ba..faa0d90f6e80 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -314,7 +314,7 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
314 314
315static inline int drv_hw_scan(struct ieee80211_local *local, 315static inline int drv_hw_scan(struct ieee80211_local *local,
316 struct ieee80211_sub_if_data *sdata, 316 struct ieee80211_sub_if_data *sdata,
317 struct cfg80211_scan_request *req) 317 struct ieee80211_scan_request *req)
318{ 318{
319 int ret; 319 int ret;
320 320
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6c8089429892..f88bd1659cde 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1152,7 +1152,8 @@ struct ieee80211_local {
1152 unsigned long scanning; 1152 unsigned long scanning;
1153 struct cfg80211_ssid scan_ssid; 1153 struct cfg80211_ssid scan_ssid;
1154 struct cfg80211_scan_request *int_scan_req; 1154 struct cfg80211_scan_request *int_scan_req;
1155 struct cfg80211_scan_request *scan_req, *hw_scan_req; 1155 struct cfg80211_scan_request *scan_req;
1156 struct ieee80211_scan_request *hw_scan_req;
1156 struct cfg80211_chan_def scan_chandef; 1157 struct cfg80211_chan_def scan_chandef;
1157 enum ieee80211_band hw_scan_band; 1158 enum ieee80211_band hw_scan_band;
1158 int scan_channel_idx; 1159 int scan_channel_idx;
@@ -1756,8 +1757,10 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
1756 const u8 *bssid, u16 stype, u16 reason, 1757 const u8 *bssid, u16 stype, u16 reason,
1757 bool send_frame, u8 *frame_buf); 1758 bool send_frame, u8 *frame_buf);
1758int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, 1759int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1759 size_t buffer_len, const u8 *ie, size_t ie_len, 1760 size_t buffer_len,
1760 enum ieee80211_band band, u32 rate_mask, 1761 struct ieee80211_scan_ies *ie_desc,
1762 const u8 *ie, size_t ie_len,
1763 u8 bands_used, u32 *rate_masks,
1761 struct cfg80211_chan_def *chandef); 1764 struct cfg80211_chan_def *chandef);
1762struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, 1765struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
1763 u8 *dst, u32 ratemask, 1766 u8 *dst, u32 ratemask,
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index f40661eb75b5..116959e070d0 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -235,38 +235,51 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
235{ 235{
236 struct cfg80211_scan_request *req = local->scan_req; 236 struct cfg80211_scan_request *req = local->scan_req;
237 struct cfg80211_chan_def chandef; 237 struct cfg80211_chan_def chandef;
238 enum ieee80211_band band; 238 u8 bands_used = 0;
239 int i, ielen, n_chans; 239 int i, ielen, n_chans;
240 240
241 if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) 241 if (test_bit(SCAN_HW_CANCELLED, &local->scanning))
242 return false; 242 return false;
243 243
244 do { 244 if (local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) {
245 if (local->hw_scan_band == IEEE80211_NUM_BANDS)
246 return false;
247
248 band = local->hw_scan_band;
249 n_chans = 0;
250 for (i = 0; i < req->n_channels; i++) { 245 for (i = 0; i < req->n_channels; i++) {
251 if (req->channels[i]->band == band) { 246 local->hw_scan_req->req.channels[i] = req->channels[i];
252 local->hw_scan_req->channels[n_chans] = 247 bands_used |= BIT(req->channels[i]->band);
248 }
249
250 n_chans = req->n_channels;
251 } else {
252 do {
253 if (local->hw_scan_band == IEEE80211_NUM_BANDS)
254 return false;
255
256 n_chans = 0;
257
258 for (i = 0; i < req->n_channels; i++) {
259 if (req->channels[i]->band !=
260 local->hw_scan_band)
261 continue;
262 local->hw_scan_req->req.channels[n_chans] =
253 req->channels[i]; 263 req->channels[i];
254 n_chans++; 264 n_chans++;
265 bands_used |= BIT(req->channels[i]->band);
255 } 266 }
256 }
257 267
258 local->hw_scan_band++; 268 local->hw_scan_band++;
259 } while (!n_chans); 269 } while (!n_chans);
270 }
260 271
261 local->hw_scan_req->n_channels = n_chans; 272 local->hw_scan_req->req.n_channels = n_chans;
262 ieee80211_prepare_scan_chandef(&chandef, req->scan_width); 273 ieee80211_prepare_scan_chandef(&chandef, req->scan_width);
263 274
264 ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, 275 ielen = ieee80211_build_preq_ies(local,
276 (u8 *)local->hw_scan_req->req.ie,
265 local->hw_scan_ies_bufsize, 277 local->hw_scan_ies_bufsize,
266 req->ie, req->ie_len, band, 278 &local->hw_scan_req->ies,
267 req->rates[band], &chandef); 279 req->ie, req->ie_len,
268 local->hw_scan_req->ie_len = ielen; 280 bands_used, req->rates, &chandef);
269 local->hw_scan_req->no_cck = req->no_cck; 281 local->hw_scan_req->req.ie_len = ielen;
282 local->hw_scan_req->req.no_cck = req->no_cck;
270 283
271 return true; 284 return true;
272} 285}
@@ -291,7 +304,9 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
291 if (WARN_ON(!local->scan_req)) 304 if (WARN_ON(!local->scan_req))
292 return; 305 return;
293 306
294 if (hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { 307 if (hw_scan && !aborted &&
308 !(local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) &&
309 ieee80211_prep_hw_scan(local)) {
295 int rc; 310 int rc;
296 311
297 rc = drv_hw_scan(local, 312 rc = drv_hw_scan(local,
@@ -473,6 +488,21 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
473 u8 *ies; 488 u8 *ies;
474 489
475 local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len; 490 local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len;
491
492 if (local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) {
493 int i, n_bands = 0;
494 u8 bands_counted = 0;
495
496 for (i = 0; i < req->n_channels; i++) {
497 if (bands_counted & BIT(req->channels[i]->band))
498 continue;
499 bands_counted |= BIT(req->channels[i]->band);
500 n_bands++;
501 }
502
503 local->hw_scan_ies_bufsize *= n_bands;
504 }
505
476 local->hw_scan_req = kmalloc( 506 local->hw_scan_req = kmalloc(
477 sizeof(*local->hw_scan_req) + 507 sizeof(*local->hw_scan_req) +
478 req->n_channels * sizeof(req->channels[0]) + 508 req->n_channels * sizeof(req->channels[0]) +
@@ -480,13 +510,13 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
480 if (!local->hw_scan_req) 510 if (!local->hw_scan_req)
481 return -ENOMEM; 511 return -ENOMEM;
482 512
483 local->hw_scan_req->ssids = req->ssids; 513 local->hw_scan_req->req.ssids = req->ssids;
484 local->hw_scan_req->n_ssids = req->n_ssids; 514 local->hw_scan_req->req.n_ssids = req->n_ssids;
485 ies = (u8 *)local->hw_scan_req + 515 ies = (u8 *)local->hw_scan_req +
486 sizeof(*local->hw_scan_req) + 516 sizeof(*local->hw_scan_req) +
487 req->n_channels * sizeof(req->channels[0]); 517 req->n_channels * sizeof(req->channels[0]);
488 local->hw_scan_req->ie = ies; 518 local->hw_scan_req->req.ie = ies;
489 local->hw_scan_req->flags = req->flags; 519 local->hw_scan_req->req.flags = req->flags;
490 520
491 local->hw_scan_band = 0; 521 local->hw_scan_band = 0;
492 522
@@ -976,6 +1006,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
976 struct ieee80211_sched_scan_ies sched_scan_ies = {}; 1006 struct ieee80211_sched_scan_ies sched_scan_ies = {};
977 struct cfg80211_chan_def chandef; 1007 struct cfg80211_chan_def chandef;
978 int ret, i, iebufsz; 1008 int ret, i, iebufsz;
1009 struct ieee80211_scan_ies dummy_ie_desc;
979 1010
980 iebufsz = local->scan_ies_len + req->ie_len; 1011 iebufsz = local->scan_ies_len + req->ie_len;
981 1012
@@ -985,6 +1016,8 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
985 return -ENOTSUPP; 1016 return -ENOTSUPP;
986 1017
987 for (i = 0; i < IEEE80211_NUM_BANDS; i++) { 1018 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
1019 u32 rate_masks[IEEE80211_NUM_BANDS] = {};
1020
988 if (!local->hw.wiphy->bands[i]) 1021 if (!local->hw.wiphy->bands[i])
989 continue; 1022 continue;
990 1023
@@ -995,11 +1028,13 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
995 } 1028 }
996 1029
997 ieee80211_prepare_scan_chandef(&chandef, req->scan_width); 1030 ieee80211_prepare_scan_chandef(&chandef, req->scan_width);
1031 rate_masks[i] = (u32) -1;
998 1032
999 sched_scan_ies.len[i] = 1033 sched_scan_ies.len[i] =
1000 ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], 1034 ieee80211_build_preq_ies(local, sched_scan_ies.ie[i],
1001 iebufsz, req->ie, req->ie_len, 1035 iebufsz, &dummy_ie_desc,
1002 i, (u32) -1, &chandef); 1036 req->ie, req->ie_len, BIT(i),
1037 rate_masks, &chandef);
1003 } 1038 }
1004 1039
1005 ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); 1040 ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 42d448d765b4..e31458201278 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1219,14 +1219,17 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
1219 } 1219 }
1220} 1220}
1221 1221
1222int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, 1222static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
1223 size_t buffer_len, const u8 *ie, size_t ie_len, 1223 u8 *buffer, size_t buffer_len,
1224 enum ieee80211_band band, u32 rate_mask, 1224 const u8 *ie, size_t ie_len,
1225 struct cfg80211_chan_def *chandef) 1225 enum ieee80211_band band,
1226 u32 rate_mask,
1227 struct cfg80211_chan_def *chandef,
1228 size_t *offset)
1226{ 1229{
1227 struct ieee80211_supported_band *sband; 1230 struct ieee80211_supported_band *sband;
1228 u8 *pos = buffer, *end = buffer + buffer_len; 1231 u8 *pos = buffer, *end = buffer + buffer_len;
1229 size_t offset = 0, noffset; 1232 size_t noffset;
1230 int supp_rates_len, i; 1233 int supp_rates_len, i;
1231 u8 rates[32]; 1234 u8 rates[32];
1232 int num_rates; 1235 int num_rates;
@@ -1234,6 +1237,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1234 int shift; 1237 int shift;
1235 u32 rate_flags; 1238 u32 rate_flags;
1236 1239
1240 *offset = 0;
1241
1237 sband = local->hw.wiphy->bands[band]; 1242 sband = local->hw.wiphy->bands[band];
1238 if (WARN_ON_ONCE(!sband)) 1243 if (WARN_ON_ONCE(!sband))
1239 return 0; 1244 return 0;
@@ -1272,12 +1277,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1272 noffset = ieee80211_ie_split(ie, ie_len, 1277 noffset = ieee80211_ie_split(ie, ie_len,
1273 before_extrates, 1278 before_extrates,
1274 ARRAY_SIZE(before_extrates), 1279 ARRAY_SIZE(before_extrates),
1275 offset); 1280 *offset);
1276 if (end - pos < noffset - offset) 1281 if (end - pos < noffset - *offset)
1277 goto out_err; 1282 goto out_err;
1278 memcpy(pos, ie + offset, noffset - offset); 1283 memcpy(pos, ie + *offset, noffset - *offset);
1279 pos += noffset - offset; 1284 pos += noffset - *offset;
1280 offset = noffset; 1285 *offset = noffset;
1281 } 1286 }
1282 1287
1283 ext_rates_len = num_rates - supp_rates_len; 1288 ext_rates_len = num_rates - supp_rates_len;
@@ -1311,12 +1316,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1311 }; 1316 };
1312 noffset = ieee80211_ie_split(ie, ie_len, 1317 noffset = ieee80211_ie_split(ie, ie_len,
1313 before_ht, ARRAY_SIZE(before_ht), 1318 before_ht, ARRAY_SIZE(before_ht),
1314 offset); 1319 *offset);
1315 if (end - pos < noffset - offset) 1320 if (end - pos < noffset - *offset)
1316 goto out_err; 1321 goto out_err;
1317 memcpy(pos, ie + offset, noffset - offset); 1322 memcpy(pos, ie + *offset, noffset - *offset);
1318 pos += noffset - offset; 1323 pos += noffset - *offset;
1319 offset = noffset; 1324 *offset = noffset;
1320 } 1325 }
1321 1326
1322 if (sband->ht_cap.ht_supported) { 1327 if (sband->ht_cap.ht_supported) {
@@ -1351,12 +1356,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1351 }; 1356 };
1352 noffset = ieee80211_ie_split(ie, ie_len, 1357 noffset = ieee80211_ie_split(ie, ie_len,
1353 before_vht, ARRAY_SIZE(before_vht), 1358 before_vht, ARRAY_SIZE(before_vht),
1354 offset); 1359 *offset);
1355 if (end - pos < noffset - offset) 1360 if (end - pos < noffset - *offset)
1356 goto out_err; 1361 goto out_err;
1357 memcpy(pos, ie + offset, noffset - offset); 1362 memcpy(pos, ie + *offset, noffset - *offset);
1358 pos += noffset - offset; 1363 pos += noffset - *offset;
1359 offset = noffset; 1364 *offset = noffset;
1360 } 1365 }
1361 1366
1362 if (sband->vht_cap.vht_supported) { 1367 if (sband->vht_cap.vht_supported) {
@@ -1366,21 +1371,54 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1366 sband->vht_cap.cap); 1371 sband->vht_cap.cap);
1367 } 1372 }
1368 1373
1369 /* add any remaining custom IEs */
1370 if (ie && ie_len) {
1371 noffset = ie_len;
1372 if (end - pos < noffset - offset)
1373 goto out_err;
1374 memcpy(pos, ie + offset, noffset - offset);
1375 pos += noffset - offset;
1376 }
1377
1378 return pos - buffer; 1374 return pos - buffer;
1379 out_err: 1375 out_err:
1380 WARN_ONCE(1, "not enough space for preq IEs\n"); 1376 WARN_ONCE(1, "not enough space for preq IEs\n");
1381 return pos - buffer; 1377 return pos - buffer;
1382} 1378}
1383 1379
1380int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1381 size_t buffer_len,
1382 struct ieee80211_scan_ies *ie_desc,
1383 const u8 *ie, size_t ie_len,
1384 u8 bands_used, u32 *rate_masks,
1385 struct cfg80211_chan_def *chandef)
1386{
1387 size_t pos = 0, old_pos = 0, custom_ie_offset = 0;
1388 int i;
1389
1390 memset(ie_desc, 0, sizeof(*ie_desc));
1391
1392 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
1393 if (bands_used & BIT(i)) {
1394 pos += ieee80211_build_preq_ies_band(local,
1395 buffer + pos,
1396 buffer_len - pos,
1397 ie, ie_len, i,
1398 rate_masks[i],
1399 chandef,
1400 &custom_ie_offset);
1401 ie_desc->ies[i] = buffer + old_pos;
1402 ie_desc->len[i] = pos - old_pos;
1403 old_pos = pos;
1404 }
1405 }
1406
1407 /* add any remaining custom IEs */
1408 if (ie && ie_len) {
1409 if (WARN_ONCE(buffer_len - pos < ie_len - custom_ie_offset,
1410 "not enough space for preq custom IEs\n"))
1411 return pos;
1412 memcpy(buffer + pos, ie + custom_ie_offset,
1413 ie_len - custom_ie_offset);
1414 ie_desc->common_ies = buffer + pos;
1415 ie_desc->common_ie_len = ie_len - custom_ie_offset;
1416 pos += ie_len - custom_ie_offset;
1417 }
1418
1419 return pos;
1420};
1421
1384struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, 1422struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
1385 u8 *dst, u32 ratemask, 1423 u8 *dst, u32 ratemask,
1386 struct ieee80211_channel *chan, 1424 struct ieee80211_channel *chan,
@@ -1393,6 +1431,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
1393 struct sk_buff *skb; 1431 struct sk_buff *skb;
1394 struct ieee80211_mgmt *mgmt; 1432 struct ieee80211_mgmt *mgmt;
1395 int ies_len; 1433 int ies_len;
1434 u32 rate_masks[IEEE80211_NUM_BANDS] = {};
1435 struct ieee80211_scan_ies dummy_ie_desc;
1396 1436
1397 /* 1437 /*
1398 * Do not send DS Channel parameter for directed probe requests 1438 * Do not send DS Channel parameter for directed probe requests
@@ -1410,10 +1450,11 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
1410 if (!skb) 1450 if (!skb)
1411 return NULL; 1451 return NULL;
1412 1452
1453 rate_masks[chan->band] = ratemask;
1413 ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), 1454 ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb),
1414 skb_tailroom(skb), 1455 skb_tailroom(skb), &dummy_ie_desc,
1415 ie, ie_len, chan->band, 1456 ie, ie_len, BIT(chan->band),
1416 ratemask, &chandef); 1457 rate_masks, &chandef);
1417 skb_put(skb, ies_len); 1458 skb_put(skb, ies_len);
1418 1459
1419 if (dst) { 1460 if (dst) {