|
@@ -419,6 +419,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
|
|
.len = FILS_ERP_MAX_RRK_LEN },
|
|
|
[NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
|
|
|
[NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
|
|
|
+ [NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
|
|
|
};
|
|
|
|
|
|
/* policy for the key attributes */
|
|
@@ -1376,7 +1377,7 @@ static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
|
|
|
CMD(tdls_mgmt, TDLS_MGMT);
|
|
|
CMD(tdls_oper, TDLS_OPER);
|
|
|
}
|
|
|
- if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
|
|
|
+ if (rdev->wiphy.max_sched_scan_reqs)
|
|
|
CMD(sched_scan_start, START_SCHED_SCAN);
|
|
|
CMD(probe_client, PROBE_CLIENT);
|
|
|
CMD(set_noack_map, SET_NOACK_MAP);
|
|
@@ -1815,6 +1816,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|
|
nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
+ if (rdev->wiphy.max_sched_scan_reqs &&
|
|
|
+ nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_MAX_REQS,
|
|
|
+ rdev->wiphy.max_sched_scan_reqs))
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
if (nla_put(msg, NL80211_ATTR_EXT_FEATURES,
|
|
|
sizeof(rdev->wiphy.ext_features),
|
|
|
rdev->wiphy.ext_features))
|
|
@@ -7336,14 +7342,16 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
|
|
|
struct net_device *dev = info->user_ptr[1];
|
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
struct cfg80211_sched_scan_request *sched_scan_req;
|
|
|
+ bool want_multi;
|
|
|
int err;
|
|
|
|
|
|
- if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
|
|
|
- !rdev->ops->sched_scan_start)
|
|
|
+ if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_start)
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- if (rdev->sched_scan_req)
|
|
|
- return -EINPROGRESS;
|
|
|
+ want_multi = info->attrs[NL80211_ATTR_SCHED_SCAN_MULTI];
|
|
|
+ err = cfg80211_sched_scan_req_possible(rdev, want_multi);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
|
|
|
sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
|
|
|
info->attrs,
|
|
@@ -7353,6 +7361,14 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
|
|
|
if (err)
|
|
|
goto out_err;
|
|
|
|
|
|
+ /* leave request id zero for legacy request
|
|
|
+ * or if driver does not support multi-scheduled scan
|
|
|
+ */
|
|
|
+ if (want_multi && rdev->wiphy.max_sched_scan_reqs > 1) {
|
|
|
+ while (!sched_scan_req->reqid)
|
|
|
+ sched_scan_req->reqid = rdev->wiphy.cookie_counter++;
|
|
|
+ }
|
|
|
+
|
|
|
err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
|
|
|
if (err)
|
|
|
goto out_free;
|
|
@@ -7363,7 +7379,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
|
|
|
if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
|
|
|
sched_scan_req->owner_nlportid = info->snd_portid;
|
|
|
|
|
|
- rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
|
|
|
+ cfg80211_add_sched_scan_req(rdev, sched_scan_req);
|
|
|
|
|
|
nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_START_SCHED_SCAN);
|
|
|
return 0;
|
|
@@ -7377,13 +7393,27 @@ out_err:
|
|
|
static int nl80211_stop_sched_scan(struct sk_buff *skb,
|
|
|
struct genl_info *info)
|
|
|
{
|
|
|
+ struct cfg80211_sched_scan_request *req;
|
|
|
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
|
+ u64 cookie;
|
|
|
|
|
|
- if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
|
|
|
- !rdev->ops->sched_scan_stop)
|
|
|
+ if (!rdev->wiphy.max_sched_scan_reqs || !rdev->ops->sched_scan_stop)
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- return __cfg80211_stop_sched_scan(rdev, false);
|
|
|
+ if (info->attrs[NL80211_ATTR_COOKIE]) {
|
|
|
+ cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
|
|
|
+ return __cfg80211_stop_sched_scan(rdev, cookie, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ req = list_first_or_null_rcu(&rdev->sched_scan_req_list,
|
|
|
+ struct cfg80211_sched_scan_request,
|
|
|
+ list);
|
|
|
+ if (!req || req->reqid ||
|
|
|
+ (req->owner_nlportid &&
|
|
|
+ req->owner_nlportid != info->snd_portid))
|
|
|
+ return -ENOENT;
|
|
|
+
|
|
|
+ return cfg80211_stop_sched_scan_req(rdev, req, false);
|
|
|
}
|
|
|
|
|
|
static int nl80211_start_radar_detection(struct sk_buff *skb,
|
|
@@ -14883,16 +14913,15 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
|
|
|
rcu_read_lock();
|
|
|
|
|
|
list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
|
|
|
- struct cfg80211_sched_scan_request *sched_scan_req =
|
|
|
- rcu_dereference(rdev->sched_scan_req);
|
|
|
-
|
|
|
- if (sched_scan_req && notify->portid &&
|
|
|
- sched_scan_req->owner_nlportid == notify->portid) {
|
|
|
- sched_scan_req->owner_nlportid = 0;
|
|
|
+ struct cfg80211_sched_scan_request *sched_scan_req;
|
|
|
|
|
|
- if (rdev->ops->sched_scan_stop &&
|
|
|
- rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
|
|
|
+ list_for_each_entry_rcu(sched_scan_req,
|
|
|
+ &rdev->sched_scan_req_list,
|
|
|
+ list) {
|
|
|
+ if (sched_scan_req->owner_nlportid == notify->portid) {
|
|
|
+ sched_scan_req->nl_owner_dead = true;
|
|
|
schedule_work(&rdev->sched_scan_stop_wk);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
|