aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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) {