summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/cfg80211.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c2
-rw-r--r--include/net/cfg80211.h9
-rw-r--r--include/uapi/linux/nl80211.h12
-rw-r--r--net/wireless/core.c29
-rw-r--r--net/wireless/core.h11
-rw-r--r--net/wireless/nl80211.c63
-rw-r--r--net/wireless/rdev-ops.h2
-rw-r--r--net/wireless/scan.c115
-rw-r--r--net/wireless/trace.h18
13 files changed, 205 insertions, 64 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 0c118b7c362c..1906412afa70 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -3973,7 +3973,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
3973 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; 3973 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
3974 3974
3975 if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, ar->fw_capabilities)) 3975 if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, ar->fw_capabilities))
3976 ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; 3976 ar->wiphy->max_sched_scan_reqs = 1;
3977 3977
3978 if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, 3978 if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
3979 ar->fw_capabilities)) 3979 ar->fw_capabilities))
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 8c7f1ef288c6..c71173dc9965 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -6374,11 +6374,11 @@ err:
6374static void brcmf_wiphy_pno_params(struct wiphy *wiphy) 6374static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
6375{ 6375{
6376 /* scheduled scan settings */ 6376 /* scheduled scan settings */
6377 wiphy->max_sched_scan_reqs = 1;
6377 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; 6378 wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
6378 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; 6379 wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
6379 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; 6380 wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
6380 wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD; 6381 wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD;
6381 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
6382} 6382}
6383 6383
6384#ifdef CONFIG_PM 6384#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 5cdd95775ba6..8c58d47100a0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -620,7 +620,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
620 else 620 else
621 hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; 621 hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
622 622
623 hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; 623 hw->wiphy->max_sched_scan_reqs = 1;
624 hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; 624 hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
625 hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; 625 hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
626 /* we create the 802.11 header and zero length SSID IE. */ 626 /* we create the 802.11 header and zero length SSID IE. */
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index 49b4c805b7d5..9927bd5aac56 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -4297,7 +4297,6 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
4297 wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | 4297 wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
4298 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | 4298 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
4299 WIPHY_FLAG_AP_UAPSD | 4299 WIPHY_FLAG_AP_UAPSD |
4300 WIPHY_FLAG_SUPPORTS_SCHED_SCAN |
4301 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | 4300 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
4302 WIPHY_FLAG_HAS_CHANNEL_SWITCH | 4301 WIPHY_FLAG_HAS_CHANNEL_SWITCH |
4303 WIPHY_FLAG_PS_ON_BY_DEFAULT; 4302 WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -4316,6 +4315,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
4316 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | 4315 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
4317 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; 4316 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
4318 4317
4318 wiphy->max_sched_scan_reqs = 1;
4319 wiphy->max_sched_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH; 4319 wiphy->max_sched_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH;
4320 wiphy->max_sched_scan_ie_len = MWIFIEX_MAX_VSIE_LEN; 4320 wiphy->max_sched_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
4321 wiphy->max_match_sets = MWIFIEX_MAX_SSID_LIST_LENGTH; 4321 wiphy->max_match_sets = MWIFIEX_MAX_SSID_LIST_LENGTH;
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index a21fda910529..382ec15ec1af 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -6128,6 +6128,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
6128 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - 6128 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
6129 sizeof(struct ieee80211_header); 6129 sizeof(struct ieee80211_header);
6130 6130
6131 wl->hw->wiphy->max_sched_scan_reqs = 1;
6131 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - 6132 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
6132 sizeof(struct ieee80211_header); 6133 sizeof(struct ieee80211_header);
6133 6134
@@ -6135,7 +6136,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
6135 6136
6136 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD | 6137 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD |
6137 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | 6138 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
6138 WIPHY_FLAG_SUPPORTS_SCHED_SCAN |
6139 WIPHY_FLAG_HAS_CHANNEL_SWITCH; 6139 WIPHY_FLAG_HAS_CHANNEL_SWITCH;
6140 6140
6141 wl->hw->wiphy->features |= NL80211_FEATURE_AP_SCAN; 6141 wl->hw->wiphy->features |= NL80211_FEATURE_AP_SCAN;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index af958938b3b1..43c0f389c273 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1678,6 +1678,8 @@ struct cfg80211_bss_select_adjust {
1678 * @rcu_head: RCU callback used to free the struct 1678 * @rcu_head: RCU callback used to free the struct
1679 * @owner_nlportid: netlink portid of owner (if this should is a request 1679 * @owner_nlportid: netlink portid of owner (if this should is a request
1680 * owned by a particular socket) 1680 * owned by a particular socket)
1681 * @nl_owner_dead: netlink owner socket was closed - this request be freed
1682 * @list: for keeping list of requests.
1681 * @delay: delay in seconds to use before starting the first scan 1683 * @delay: delay in seconds to use before starting the first scan
1682 * cycle. The driver may ignore this parameter and start 1684 * cycle. The driver may ignore this parameter and start
1683 * immediately (or at any other time), if this feature is not 1685 * immediately (or at any other time), if this feature is not
@@ -1722,6 +1724,8 @@ struct cfg80211_sched_scan_request {
1722 unsigned long scan_start; 1724 unsigned long scan_start;
1723 struct rcu_head rcu_head; 1725 struct rcu_head rcu_head;
1724 u32 owner_nlportid; 1726 u32 owner_nlportid;
1727 bool nl_owner_dead;
1728 struct list_head list;
1725 1729
1726 /* keep last */ 1730 /* keep last */
1727 struct ieee80211_channel *channels[0]; 1731 struct ieee80211_channel *channels[0];
@@ -3213,7 +3217,7 @@ enum wiphy_flags {
3213 WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7), 3217 WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7),
3214 WIPHY_FLAG_IBSS_RSN = BIT(8), 3218 WIPHY_FLAG_IBSS_RSN = BIT(8),
3215 WIPHY_FLAG_MESH_AUTH = BIT(10), 3219 WIPHY_FLAG_MESH_AUTH = BIT(10),
3216 WIPHY_FLAG_SUPPORTS_SCHED_SCAN = BIT(11), 3220 /* use hole at 11 */
3217 /* use hole at 12 */ 3221 /* use hole at 12 */
3218 WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13), 3222 WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13),
3219 WIPHY_FLAG_AP_UAPSD = BIT(14), 3223 WIPHY_FLAG_AP_UAPSD = BIT(14),
@@ -3551,6 +3555,8 @@ struct wiphy_iftype_ext_capab {
3551 * this variable determines its size 3555 * this variable determines its size
3552 * @max_scan_ssids: maximum number of SSIDs the device can scan for in 3556 * @max_scan_ssids: maximum number of SSIDs the device can scan for in
3553 * any given scan 3557 * any given scan
3558 * @max_sched_scan_reqs: maximum number of scheduled scan requests that
3559 * the device can run concurrently.
3554 * @max_sched_scan_ssids: maximum number of SSIDs the device can scan 3560 * @max_sched_scan_ssids: maximum number of SSIDs the device can scan
3555 * for in any given scheduled scan 3561 * for in any given scheduled scan
3556 * @max_match_sets: maximum number of match sets the device can handle 3562 * @max_match_sets: maximum number of match sets the device can handle
@@ -3687,6 +3693,7 @@ struct wiphy {
3687 3693
3688 int bss_priv_size; 3694 int bss_priv_size;
3689 u8 max_scan_ssids; 3695 u8 max_scan_ssids;
3696 u8 max_sched_scan_reqs;
3690 u8 max_sched_scan_ssids; 3697 u8 max_sched_scan_ssids;
3691 u8 max_match_sets; 3698 u8 max_match_sets;
3692 u16 max_scan_ie_len; 3699 u16 max_scan_ie_len;
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 6095a6c4c412..f34127d241e5 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -387,7 +387,9 @@
387 * are used. Extra IEs can also be passed from the userspace by 387 * are used. Extra IEs can also be passed from the userspace by
388 * using the %NL80211_ATTR_IE attribute. The first cycle of the 388 * using the %NL80211_ATTR_IE attribute. The first cycle of the
389 * scheduled scan can be delayed by %NL80211_ATTR_SCHED_SCAN_DELAY 389 * scheduled scan can be delayed by %NL80211_ATTR_SCHED_SCAN_DELAY
390 * is supplied. 390 * is supplied. If the device supports multiple concurrent scheduled
391 * scans, it will allow such when the caller provides the flag attribute
392 * %NL80211_ATTR_SCHED_SCAN_MULTI to indicate user-space support for it.
391 * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT if 393 * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT if
392 * scheduled scan is not running. The caller may assume that as soon 394 * scheduled scan is not running. The caller may assume that as soon
393 * as the call returns, it is safe to start a new scheduled scan again. 395 * as the call returns, it is safe to start a new scheduled scan again.
@@ -2081,6 +2083,11 @@ enum nl80211_commands {
2081 * @NL80211_ATTR_PMK: PMK for the PMKSA identified by %NL80211_ATTR_PMKID. 2083 * @NL80211_ATTR_PMK: PMK for the PMKSA identified by %NL80211_ATTR_PMKID.
2082 * This is used with @NL80211_CMD_SET_PMKSA. 2084 * This is used with @NL80211_CMD_SET_PMKSA.
2083 * 2085 *
2086 * @NL80211_ATTR_SCHED_SCAN_MULTI: flag attribute which user-space shall use to
2087 * indicate that it supports multiple active scheduled scan requests.
2088 * @NL80211_ATTR_SCHED_SCAN_MAX_REQS: indicates maximum number of scheduled
2089 * scan request that may be active for the device (u32).
2090 *
2084 * @NUM_NL80211_ATTR: total number of nl80211_attrs available 2091 * @NUM_NL80211_ATTR: total number of nl80211_attrs available
2085 * @NL80211_ATTR_MAX: highest attribute number currently defined 2092 * @NL80211_ATTR_MAX: highest attribute number currently defined
2086 * @__NL80211_ATTR_AFTER_LAST: internal use 2093 * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2500,6 +2507,9 @@ enum nl80211_attrs {
2500 2507
2501 NL80211_ATTR_PMK, 2508 NL80211_ATTR_PMK,
2502 2509
2510 NL80211_ATTR_SCHED_SCAN_MULTI,
2511 NL80211_ATTR_SCHED_SCAN_MAX_REQS,
2512
2503 /* add attributes here, update the policy in nl80211.c */ 2513 /* add attributes here, update the policy in nl80211.c */
2504 2514
2505 __NL80211_ATTR_AFTER_LAST, 2515 __NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 4ea28de3a636..a3c0c48afb85 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -330,14 +330,16 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work)
330static void cfg80211_sched_scan_stop_wk(struct work_struct *work) 330static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
331{ 331{
332 struct cfg80211_registered_device *rdev; 332 struct cfg80211_registered_device *rdev;
333 struct cfg80211_sched_scan_request *req, *tmp;
333 334
334 rdev = container_of(work, struct cfg80211_registered_device, 335 rdev = container_of(work, struct cfg80211_registered_device,
335 sched_scan_stop_wk); 336 sched_scan_stop_wk);
336 337
337 rtnl_lock(); 338 rtnl_lock();
338 339 list_for_each_entry_safe(req, tmp, &rdev->sched_scan_req_list, list) {
339 __cfg80211_stop_sched_scan(rdev, false); 340 if (req->nl_owner_dead)
340 341 cfg80211_stop_sched_scan_req(rdev, req, false);
342 }
341 rtnl_unlock(); 343 rtnl_unlock();
342} 344}
343 345
@@ -452,6 +454,7 @@ use_default_name:
452 spin_lock_init(&rdev->beacon_registrations_lock); 454 spin_lock_init(&rdev->beacon_registrations_lock);
453 spin_lock_init(&rdev->bss_lock); 455 spin_lock_init(&rdev->bss_lock);
454 INIT_LIST_HEAD(&rdev->bss_list); 456 INIT_LIST_HEAD(&rdev->bss_list);
457 INIT_LIST_HEAD(&rdev->sched_scan_req_list);
455 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); 458 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
456 INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); 459 INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results);
457 INIT_LIST_HEAD(&rdev->mlme_unreg); 460 INIT_LIST_HEAD(&rdev->mlme_unreg);
@@ -1028,7 +1031,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
1028 struct wireless_dev *wdev) 1031 struct wireless_dev *wdev)
1029{ 1032{
1030 struct net_device *dev = wdev->netdev; 1033 struct net_device *dev = wdev->netdev;
1031 struct cfg80211_sched_scan_request *sched_scan_req; 1034 struct cfg80211_sched_scan_request *pos, *tmp;
1032 1035
1033 ASSERT_RTNL(); 1036 ASSERT_RTNL();
1034 ASSERT_WDEV_LOCK(wdev); 1037 ASSERT_WDEV_LOCK(wdev);
@@ -1039,9 +1042,11 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
1039 break; 1042 break;
1040 case NL80211_IFTYPE_P2P_CLIENT: 1043 case NL80211_IFTYPE_P2P_CLIENT:
1041 case NL80211_IFTYPE_STATION: 1044 case NL80211_IFTYPE_STATION:
1042 sched_scan_req = rtnl_dereference(rdev->sched_scan_req); 1045 list_for_each_entry_safe(pos, tmp, &rdev->sched_scan_req_list,
1043 if (sched_scan_req && dev == sched_scan_req->dev) 1046 list) {
1044 __cfg80211_stop_sched_scan(rdev, false); 1047 if (dev == pos->dev)
1048 cfg80211_stop_sched_scan_req(rdev, pos, false);
1049 }
1045 1050
1046#ifdef CONFIG_CFG80211_WEXT 1051#ifdef CONFIG_CFG80211_WEXT
1047 kfree(wdev->wext.ie); 1052 kfree(wdev->wext.ie);
@@ -1116,7 +1121,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
1116 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 1121 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
1117 struct wireless_dev *wdev = dev->ieee80211_ptr; 1122 struct wireless_dev *wdev = dev->ieee80211_ptr;
1118 struct cfg80211_registered_device *rdev; 1123 struct cfg80211_registered_device *rdev;
1119 struct cfg80211_sched_scan_request *sched_scan_req; 1124 struct cfg80211_sched_scan_request *pos, *tmp;
1120 1125
1121 if (!wdev) 1126 if (!wdev)
1122 return NOTIFY_DONE; 1127 return NOTIFY_DONE;
@@ -1193,10 +1198,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
1193 ___cfg80211_scan_done(rdev, false); 1198 ___cfg80211_scan_done(rdev, false);
1194 } 1199 }
1195 1200
1196 sched_scan_req = rtnl_dereference(rdev->sched_scan_req); 1201 list_for_each_entry_safe(pos, tmp,
1197 if (WARN_ON(sched_scan_req && 1202 &rdev->sched_scan_req_list, list) {
1198 sched_scan_req->dev == wdev->netdev)) { 1203 if (WARN_ON(pos && pos->dev == wdev->netdev))
1199 __cfg80211_stop_sched_scan(rdev, false); 1204 cfg80211_stop_sched_scan_req(rdev, pos, false);
1200 } 1205 }
1201 1206
1202 rdev->opencount--; 1207 rdev->opencount--;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index f9b748e3425a..06eaf96053a8 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -74,7 +74,7 @@ struct cfg80211_registered_device {
74 u32 bss_entries; 74 u32 bss_entries;
75 struct cfg80211_scan_request *scan_req; /* protected by RTNL */ 75 struct cfg80211_scan_request *scan_req; /* protected by RTNL */
76 struct sk_buff *scan_msg; 76 struct sk_buff *scan_msg;
77 struct cfg80211_sched_scan_request __rcu *sched_scan_req; 77 struct list_head sched_scan_req_list;
78 unsigned long suspend_at; 78 unsigned long suspend_at;
79 struct work_struct scan_done_wk; 79 struct work_struct scan_done_wk;
80 struct work_struct sched_scan_results_wk; 80 struct work_struct sched_scan_results_wk;
@@ -416,9 +416,16 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
416void __cfg80211_scan_done(struct work_struct *wk); 416void __cfg80211_scan_done(struct work_struct *wk);
417void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, 417void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
418 bool send_message); 418 bool send_message);
419void cfg80211_add_sched_scan_req(struct cfg80211_registered_device *rdev,
420 struct cfg80211_sched_scan_request *req);
421int cfg80211_sched_scan_req_possible(struct cfg80211_registered_device *rdev,
422 bool want_multi);
419void __cfg80211_sched_scan_results(struct work_struct *wk); 423void __cfg80211_sched_scan_results(struct work_struct *wk);
424int cfg80211_stop_sched_scan_req(struct cfg80211_registered_device *rdev,
425 struct cfg80211_sched_scan_request *req,
426 bool driver_initiated);
420int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, 427int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
421 bool driver_initiated); 428 u64 reqid, bool driver_initiated);
422void cfg80211_upload_connect_keys(struct wireless_dev *wdev); 429void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
423int cfg80211_change_iface(struct cfg80211_registered_device *rdev, 430int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
424 struct net_device *dev, enum nl80211_iftype ntype, 431 struct net_device *dev, enum nl80211_iftype ntype,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 45f5f418e562..ac7e2314f9ec 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -419,6 +419,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
419 .len = FILS_ERP_MAX_RRK_LEN }, 419 .len = FILS_ERP_MAX_RRK_LEN },
420 [NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 }, 420 [NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
421 [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN }, 421 [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
422 [NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
422}; 423};
423 424
424/* policy for the key attributes */ 425/* policy for the key attributes */
@@ -1376,7 +1377,7 @@ static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
1376 CMD(tdls_mgmt, TDLS_MGMT); 1377 CMD(tdls_mgmt, TDLS_MGMT);
1377 CMD(tdls_oper, TDLS_OPER); 1378 CMD(tdls_oper, TDLS_OPER);
1378 } 1379 }
1379 if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) 1380 if (rdev->wiphy.max_sched_scan_reqs)
1380 CMD(sched_scan_start, START_SCHED_SCAN); 1381 CMD(sched_scan_start, START_SCHED_SCAN);
1381 CMD(probe_client, PROBE_CLIENT); 1382 CMD(probe_client, PROBE_CLIENT);
1382 CMD(set_noack_map, SET_NOACK_MAP); 1383 CMD(set_noack_map, SET_NOACK_MAP);
@@ -1815,6 +1816,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
1815 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG)) 1816 nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
1816 goto nla_put_failure; 1817 goto nla_put_failure;
1817 1818
1819 if (rdev->wiphy.max_sched_scan_reqs &&
1820 nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_MAX_REQS,
1821 rdev->wiphy.max_sched_scan_reqs))
1822 goto nla_put_failure;
1823
1818 if (nla_put(msg, NL80211_ATTR_EXT_FEATURES, 1824 if (nla_put(msg, NL80211_ATTR_EXT_FEATURES,
1819 sizeof(rdev->wiphy.ext_features), 1825 sizeof(rdev->wiphy.ext_features),
1820 rdev->wiphy.ext_features)) 1826 rdev->wiphy.ext_features))
@@ -7336,14 +7342,16 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
7336 struct net_device *dev = info->user_ptr[1]; 7342 struct net_device *dev = info->user_ptr[1];
7337 struct wireless_dev *wdev = dev->ieee80211_ptr; 7343 struct wireless_dev *wdev = dev->ieee80211_ptr;
7338 struct cfg80211_sched_scan_request *sched_scan_req; 7344 struct cfg80211_sched_scan_request *sched_scan_req;
7345 bool want_multi;
7339 int err; 7346 int err;
7340 7347
7341 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || 7348 if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_start)
7342 !rdev->ops->sched_scan_start)
7343 return -EOPNOTSUPP; 7349 return -EOPNOTSUPP;
7344 7350
7345 if (rdev->sched_scan_req) 7351 want_multi = info->attrs[NL80211_ATTR_SCHED_SCAN_MULTI];
7346 return -EINPROGRESS; 7352 err = cfg80211_sched_scan_req_possible(rdev, want_multi);
7353 if (err)
7354 return err;
7347 7355
7348 sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev, 7356 sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
7349 info->attrs, 7357 info->attrs,
@@ -7353,6 +7361,14 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
7353 if (err) 7361 if (err)
7354 goto out_err; 7362 goto out_err;
7355 7363
7364 /* leave request id zero for legacy request
7365 * or if driver does not support multi-scheduled scan
7366 */
7367 if (want_multi && rdev->wiphy.max_sched_scan_reqs > 1) {
7368 while (!sched_scan_req->reqid)
7369 sched_scan_req->reqid = rdev->wiphy.cookie_counter++;
7370 }
7371
7356 err = rdev_sched_scan_start(rdev, dev, sched_scan_req); 7372 err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
7357 if (err) 7373 if (err)
7358 goto out_free; 7374 goto out_free;
@@ -7363,7 +7379,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
7363 if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) 7379 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
7364 sched_scan_req->owner_nlportid = info->snd_portid; 7380 sched_scan_req->owner_nlportid = info->snd_portid;
7365 7381
7366 rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req); 7382 cfg80211_add_sched_scan_req(rdev, sched_scan_req);
7367 7383
7368 nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_START_SCHED_SCAN); 7384 nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_START_SCHED_SCAN);
7369 return 0; 7385 return 0;
@@ -7377,13 +7393,27 @@ out_err:
7377static int nl80211_stop_sched_scan(struct sk_buff *skb, 7393static int nl80211_stop_sched_scan(struct sk_buff *skb,
7378 struct genl_info *info) 7394 struct genl_info *info)
7379{ 7395{
7396 struct cfg80211_sched_scan_request *req;
7380 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 7397 struct cfg80211_registered_device *rdev = info->user_ptr[0];
7398 u64 cookie;
7381 7399
7382 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || 7400 if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_stop)
7383 !rdev->ops->sched_scan_stop)
7384 return -EOPNOTSUPP; 7401 return -EOPNOTSUPP;
7385 7402
7386 return __cfg80211_stop_sched_scan(rdev, false); 7403 if (info->attrs[NL80211_ATTR_COOKIE]) {
7404 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
7405 return __cfg80211_stop_sched_scan(rdev, cookie, false);
7406 }
7407
7408 req = list_first_or_null_rcu(&rdev->sched_scan_req_list,
7409 struct cfg80211_sched_scan_request,
7410 list);
7411 if (!req || req->reqid ||
7412 (req->owner_nlportid &&
7413 req->owner_nlportid != info->snd_portid))
7414 return -ENOENT;
7415
7416 return cfg80211_stop_sched_scan_req(rdev, req, false);
7387} 7417}
7388 7418
7389static int nl80211_start_radar_detection(struct sk_buff *skb, 7419static int nl80211_start_radar_detection(struct sk_buff *skb,
@@ -14883,16 +14913,15 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
14883 rcu_read_lock(); 14913 rcu_read_lock();
14884 14914
14885 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { 14915 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
14886 struct cfg80211_sched_scan_request *sched_scan_req = 14916 struct cfg80211_sched_scan_request *sched_scan_req;
14887 rcu_dereference(rdev->sched_scan_req);
14888
14889 if (sched_scan_req && notify->portid &&
14890 sched_scan_req->owner_nlportid == notify->portid) {
14891 sched_scan_req->owner_nlportid = 0;
14892 14917
14893 if (rdev->ops->sched_scan_stop && 14918 list_for_each_entry_rcu(sched_scan_req,
14894 rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) 14919 &rdev->sched_scan_req_list,
14920 list) {
14921 if (sched_scan_req->owner_nlportid == notify->portid) {
14922 sched_scan_req->nl_owner_dead = true;
14895 schedule_work(&rdev->sched_scan_stop_wk); 14923 schedule_work(&rdev->sched_scan_stop_wk);
14924 }
14896 } 14925 }
14897 14926
14898 list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) { 14927 list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index e4a99989dd06..783f89c3e504 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -813,7 +813,7 @@ rdev_sched_scan_start(struct cfg80211_registered_device *rdev,
813 struct cfg80211_sched_scan_request *request) 813 struct cfg80211_sched_scan_request *request)
814{ 814{
815 int ret; 815 int ret;
816 trace_rdev_sched_scan_start(&rdev->wiphy, dev, request); 816 trace_rdev_sched_scan_start(&rdev->wiphy, dev, request->reqid);
817 ret = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request); 817 ret = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request);
818 trace_rdev_return_int(&rdev->wiphy, ret); 818 trace_rdev_return_int(&rdev->wiphy, ret);
819 return ret; 819 return ret;
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 6f4996c0f4df..bd9feed95c1e 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -300,6 +300,70 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request,
300} 300}
301EXPORT_SYMBOL(cfg80211_scan_done); 301EXPORT_SYMBOL(cfg80211_scan_done);
302 302
303void cfg80211_add_sched_scan_req(struct cfg80211_registered_device *rdev,
304 struct cfg80211_sched_scan_request *req)
305{
306 ASSERT_RTNL();
307
308 list_add_rcu(&req->list, &rdev->sched_scan_req_list);
309}
310
311static void cfg80211_del_sched_scan_req(struct cfg80211_registered_device *rdev,
312 struct cfg80211_sched_scan_request *req)
313{
314 ASSERT_RTNL();
315
316 list_del_rcu(&req->list);
317 kfree_rcu(req, rcu_head);
318}
319
320static struct cfg80211_sched_scan_request *
321cfg80211_find_sched_scan_req(struct cfg80211_registered_device *rdev, u64 reqid)
322{
323 struct cfg80211_sched_scan_request *pos;
324
325 ASSERT_RTNL();
326
327 list_for_each_entry(pos, &rdev->sched_scan_req_list, list) {
328 if (pos->reqid == reqid)
329 return pos;
330 }
331 return ERR_PTR(-ENOENT);
332}
333
334/*
335 * Determines if a scheduled scan request can be handled. When a legacy
336 * scheduled scan is running no other scheduled scan is allowed regardless
337 * whether the request is for legacy or multi-support scan. When a multi-support
338 * scheduled scan is running a request for legacy scan is not allowed. In this
339 * case a request for multi-support scan can be handled if resources are
340 * available, ie. struct wiphy::max_sched_scan_reqs limit is not yet reached.
341 */
342int cfg80211_sched_scan_req_possible(struct cfg80211_registered_device *rdev,
343 bool want_multi)
344{
345 struct cfg80211_sched_scan_request *pos;
346 int i = 0;
347
348 list_for_each_entry(pos, &rdev->sched_scan_req_list, list) {
349 /* request id zero means legacy in progress */
350 if (!i && !pos->reqid)
351 return -EINPROGRESS;
352 i++;
353 }
354
355 if (i) {
356 /* no legacy allowed when multi request(s) are active */
357 if (!want_multi)
358 return -EINPROGRESS;
359
360 /* resource limit reached */
361 if (i == rdev->wiphy.max_sched_scan_reqs)
362 return -ENOSPC;
363 }
364 return 0;
365}
366
303void __cfg80211_sched_scan_results(struct work_struct *wk) 367void __cfg80211_sched_scan_results(struct work_struct *wk)
304{ 368{
305 struct cfg80211_registered_device *rdev; 369 struct cfg80211_registered_device *rdev;
@@ -310,10 +374,10 @@ void __cfg80211_sched_scan_results(struct work_struct *wk)
310 374
311 rtnl_lock(); 375 rtnl_lock();
312 376
313 request = rtnl_dereference(rdev->sched_scan_req); 377 request = cfg80211_find_sched_scan_req(rdev, 0);
314 378
315 /* we don't have sched_scan_req anymore if the scan is stopping */ 379 /* we don't have sched_scan_req anymore if the scan is stopping */
316 if (request) { 380 if (!IS_ERR(request)) {
317 if (request->flags & NL80211_SCAN_FLAG_FLUSH) { 381 if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
318 /* flush entries from previous scans */ 382 /* flush entries from previous scans */
319 spin_lock_bh(&rdev->bss_lock); 383 spin_lock_bh(&rdev->bss_lock);
@@ -329,10 +393,17 @@ void __cfg80211_sched_scan_results(struct work_struct *wk)
329 393
330void cfg80211_sched_scan_results(struct wiphy *wiphy) 394void cfg80211_sched_scan_results(struct wiphy *wiphy)
331{ 395{
396 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
397 struct cfg80211_sched_scan_request *request;
398
332 trace_cfg80211_sched_scan_results(wiphy); 399 trace_cfg80211_sched_scan_results(wiphy);
333 /* ignore if we're not scanning */ 400 /* ignore if we're not scanning */
334 401
335 if (rcu_access_pointer(wiphy_to_rdev(wiphy)->sched_scan_req)) 402 rtnl_lock();
403 request = cfg80211_find_sched_scan_req(rdev, 0);
404 rtnl_unlock();
405
406 if (!IS_ERR(request))
336 queue_work(cfg80211_wq, 407 queue_work(cfg80211_wq,
337 &wiphy_to_rdev(wiphy)->sched_scan_results_wk); 408 &wiphy_to_rdev(wiphy)->sched_scan_results_wk);
338} 409}
@@ -346,7 +417,7 @@ void cfg80211_sched_scan_stopped_rtnl(struct wiphy *wiphy)
346 417
347 trace_cfg80211_sched_scan_stopped(wiphy); 418 trace_cfg80211_sched_scan_stopped(wiphy);
348 419
349 __cfg80211_stop_sched_scan(rdev, true); 420 __cfg80211_stop_sched_scan(rdev, 0, true);
350} 421}
351EXPORT_SYMBOL(cfg80211_sched_scan_stopped_rtnl); 422EXPORT_SYMBOL(cfg80211_sched_scan_stopped_rtnl);
352 423
@@ -358,34 +429,40 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
358} 429}
359EXPORT_SYMBOL(cfg80211_sched_scan_stopped); 430EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
360 431
361int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, 432int cfg80211_stop_sched_scan_req(struct cfg80211_registered_device *rdev,
362 bool driver_initiated) 433 struct cfg80211_sched_scan_request *req,
434 bool driver_initiated)
363{ 435{
364 struct cfg80211_sched_scan_request *sched_scan_req;
365 struct net_device *dev;
366
367 ASSERT_RTNL(); 436 ASSERT_RTNL();
368 437
369 if (!rdev->sched_scan_req)
370 return -ENOENT;
371
372 sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
373 dev = sched_scan_req->dev;
374
375 if (!driver_initiated) { 438 if (!driver_initiated) {
376 int err = rdev_sched_scan_stop(rdev, dev); 439 int err = rdev_sched_scan_stop(rdev, req->dev);
377 if (err) 440 if (err)
378 return err; 441 return err;
379 } 442 }
380 443
381 nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_SCHED_SCAN_STOPPED); 444 nl80211_send_sched_scan(req, NL80211_CMD_SCHED_SCAN_STOPPED);
382 445
383 RCU_INIT_POINTER(rdev->sched_scan_req, NULL); 446 cfg80211_del_sched_scan_req(rdev, req);
384 kfree_rcu(sched_scan_req, rcu_head);
385 447
386 return 0; 448 return 0;
387} 449}
388 450
451int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
452 u64 reqid, bool driver_initiated)
453{
454 struct cfg80211_sched_scan_request *sched_scan_req;
455
456 ASSERT_RTNL();
457
458 sched_scan_req = cfg80211_find_sched_scan_req(rdev, reqid);
459 if (IS_ERR(sched_scan_req))
460 return PTR_ERR(sched_scan_req);
461
462 return cfg80211_stop_sched_scan_req(rdev, sched_scan_req,
463 driver_initiated);
464}
465
389void cfg80211_bss_age(struct cfg80211_registered_device *rdev, 466void cfg80211_bss_age(struct cfg80211_registered_device *rdev,
390 unsigned long age_secs) 467 unsigned long age_secs)
391{ 468{
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index fd55786f0462..52935c48b342 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1610,20 +1610,26 @@ DEFINE_EVENT(tx_rx_evt, rdev_set_antenna,
1610 TP_ARGS(wiphy, rx, tx) 1610 TP_ARGS(wiphy, rx, tx)
1611); 1611);
1612 1612
1613TRACE_EVENT(rdev_sched_scan_start, 1613DECLARE_EVENT_CLASS(wiphy_netdev_id_evt,
1614 TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, 1614 TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u64 id),
1615 struct cfg80211_sched_scan_request *request), 1615 TP_ARGS(wiphy, netdev, id),
1616 TP_ARGS(wiphy, netdev, request),
1617 TP_STRUCT__entry( 1616 TP_STRUCT__entry(
1618 WIPHY_ENTRY 1617 WIPHY_ENTRY
1619 NETDEV_ENTRY 1618 NETDEV_ENTRY
1619 __field(u64, id)
1620 ), 1620 ),
1621 TP_fast_assign( 1621 TP_fast_assign(
1622 WIPHY_ASSIGN; 1622 WIPHY_ASSIGN;
1623 NETDEV_ASSIGN; 1623 NETDEV_ASSIGN;
1624 __entry->id = id;
1624 ), 1625 ),
1625 TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, 1626 TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", id: %llu",
1626 WIPHY_PR_ARG, NETDEV_PR_ARG) 1627 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->id)
1628);
1629
1630DEFINE_EVENT(wiphy_netdev_id_evt, rdev_sched_scan_start,
1631 TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u64 id),
1632 TP_ARGS(wiphy, netdev, id)
1627); 1633);
1628 1634
1629TRACE_EVENT(rdev_tdls_mgmt, 1635TRACE_EVENT(rdev_tdls_mgmt,