aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c19
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c3
-rw-r--r--include/net/cfg80211.h9
-rw-r--r--include/uapi/linux/nl80211.h10
-rw-r--r--net/wireless/nl80211.c70
5 files changed, 92 insertions, 19 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index fd4c89df67e1..eba32f56850a 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -3256,6 +3256,15 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
3256 struct ath6kl_vif *vif = netdev_priv(dev); 3256 struct ath6kl_vif *vif = netdev_priv(dev);
3257 u16 interval; 3257 u16 interval;
3258 int ret, rssi_thold; 3258 int ret, rssi_thold;
3259 int n_match_sets = request->n_match_sets;
3260
3261 /*
3262 * If there's a matchset w/o an SSID, then assume it's just for
3263 * the RSSI (nothing else is currently supported) and ignore it.
3264 * The device only supports a global RSSI filter that we set below.
3265 */
3266 if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len)
3267 n_match_sets = 0;
3259 3268
3260 if (ar->state != ATH6KL_STATE_ON) 3269 if (ar->state != ATH6KL_STATE_ON)
3261 return -EIO; 3270 return -EIO;
@@ -3268,11 +3277,11 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
3268 ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, 3277 ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
3269 request->n_ssids, 3278 request->n_ssids,
3270 request->match_sets, 3279 request->match_sets,
3271 request->n_match_sets); 3280 n_match_sets);
3272 if (ret < 0) 3281 if (ret < 0)
3273 return ret; 3282 return ret;
3274 3283
3275 if (!request->n_match_sets) { 3284 if (!n_match_sets) {
3276 ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, 3285 ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
3277 ALL_BSS_FILTER, 0); 3286 ALL_BSS_FILTER, 0);
3278 if (ret < 0) 3287 if (ret < 0)
@@ -3286,12 +3295,12 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
3286 3295
3287 if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, 3296 if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
3288 ar->fw_capabilities)) { 3297 ar->fw_capabilities)) {
3289 if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) 3298 if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
3290 rssi_thold = 0; 3299 rssi_thold = 0;
3291 else if (request->rssi_thold < -127) 3300 else if (request->min_rssi_thold < -127)
3292 rssi_thold = -127; 3301 rssi_thold = -127;
3293 else 3302 else
3294 rssi_thold = request->rssi_thold; 3303 rssi_thold = request->min_rssi_thold;
3295 3304
3296 ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx, 3305 ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,
3297 rssi_thold); 3306 rssi_thold);
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 0e0007960612..9674bfd978f1 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -595,6 +595,9 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
595 * config match list. 595 * config match list.
596 */ 596 */
597 for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) { 597 for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) {
598 /* skip empty SSID matchsets */
599 if (!req->match_sets[i].ssid.ssid_len)
600 continue;
598 scan->direct_scan[i].id = WLAN_EID_SSID; 601 scan->direct_scan[i].id = WLAN_EID_SSID;
599 scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len; 602 scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len;
600 memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid, 603 memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d5e57bf678a6..009290e36d15 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1394,10 +1394,12 @@ struct cfg80211_scan_request {
1394/** 1394/**
1395 * struct cfg80211_match_set - sets of attributes to match 1395 * struct cfg80211_match_set - sets of attributes to match
1396 * 1396 *
1397 * @ssid: SSID to be matched 1397 * @ssid: SSID to be matched; may be zero-length for no match (RSSI only)
1398 * @rssi_thold: don't report scan results below this threshold (in s32 dBm)
1398 */ 1399 */
1399struct cfg80211_match_set { 1400struct cfg80211_match_set {
1400 struct cfg80211_ssid ssid; 1401 struct cfg80211_ssid ssid;
1402 s32 rssi_thold;
1401}; 1403};
1402 1404
1403/** 1405/**
@@ -1420,7 +1422,8 @@ struct cfg80211_match_set {
1420 * @dev: the interface 1422 * @dev: the interface
1421 * @scan_start: start time of the scheduled scan 1423 * @scan_start: start time of the scheduled scan
1422 * @channels: channels to scan 1424 * @channels: channels to scan
1423 * @rssi_thold: don't report scan results below this threshold (in s32 dBm) 1425 * @min_rssi_thold: for drivers only supporting a single threshold, this
1426 * contains the minimum over all matchsets
1424 */ 1427 */
1425struct cfg80211_sched_scan_request { 1428struct cfg80211_sched_scan_request {
1426 struct cfg80211_ssid *ssids; 1429 struct cfg80211_ssid *ssids;
@@ -1433,7 +1436,7 @@ struct cfg80211_sched_scan_request {
1433 u32 flags; 1436 u32 flags;
1434 struct cfg80211_match_set *match_sets; 1437 struct cfg80211_match_set *match_sets;
1435 int n_match_sets; 1438 int n_match_sets;
1436 s32 rssi_thold; 1439 s32 min_rssi_thold;
1437 1440
1438 /* internal */ 1441 /* internal */
1439 struct wiphy *wiphy; 1442 struct wiphy *wiphy;
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 53e56cf7c0fe..474ce32e0797 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2467,9 +2467,15 @@ enum nl80211_reg_rule_attr {
2467 * enum nl80211_sched_scan_match_attr - scheduled scan match attributes 2467 * enum nl80211_sched_scan_match_attr - scheduled scan match attributes
2468 * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved 2468 * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
2469 * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching, 2469 * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
2470 * only report BSS with matching SSID. 2470 * only report BSS with matching SSID.
2471 * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a 2471 * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a
2472 * BSS in scan results. Filtering is turned off if not specified. 2472 * BSS in scan results. Filtering is turned off if not specified. Note that
2473 * if this attribute is in a match set of its own, then it is treated as
2474 * the default value for all matchsets with an SSID, rather than being a
2475 * matchset of its own without an RSSI filter. This is due to problems with
2476 * how this API was implemented in the past. Also, due to the same problem,
2477 * the only way to create a matchset with only an RSSI filter (with this
2478 * attribute) is if there's only a single matchset with the RSSI attribute.
2473 * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter 2479 * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
2474 * attribute number currently defined 2480 * attribute number currently defined
2475 * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use 2481 * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 043bfbd58b56..20be186f7f77 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5467,6 +5467,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
5467 enum ieee80211_band band; 5467 enum ieee80211_band band;
5468 size_t ie_len; 5468 size_t ie_len;
5469 struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; 5469 struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
5470 s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
5470 5471
5471 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || 5472 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
5472 !rdev->ops->sched_scan_start) 5473 !rdev->ops->sched_scan_start)
@@ -5501,11 +5502,40 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
5501 if (n_ssids > wiphy->max_sched_scan_ssids) 5502 if (n_ssids > wiphy->max_sched_scan_ssids)
5502 return -EINVAL; 5503 return -EINVAL;
5503 5504
5504 if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) 5505 /*
5506 * First, count the number of 'real' matchsets. Due to an issue with
5507 * the old implementation, matchsets containing only the RSSI attribute
5508 * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
5509 * RSSI for all matchsets, rather than their own matchset for reporting
5510 * all APs with a strong RSSI. This is needed to be compatible with
5511 * older userspace that treated a matchset with only the RSSI as the
5512 * global RSSI for all other matchsets - if there are other matchsets.
5513 */
5514 if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
5505 nla_for_each_nested(attr, 5515 nla_for_each_nested(attr,
5506 info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], 5516 info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
5507 tmp) 5517 tmp) {
5508 n_match_sets++; 5518 struct nlattr *rssi;
5519
5520 err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
5521 nla_data(attr), nla_len(attr),
5522 nl80211_match_policy);
5523 if (err)
5524 return err;
5525 /* add other standalone attributes here */
5526 if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) {
5527 n_match_sets++;
5528 continue;
5529 }
5530 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
5531 if (rssi)
5532 default_match_rssi = nla_get_s32(rssi);
5533 }
5534 }
5535
5536 /* However, if there's no other matchset, add the RSSI one */
5537 if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
5538 n_match_sets = 1;
5509 5539
5510 if (n_match_sets > wiphy->max_match_sets) 5540 if (n_match_sets > wiphy->max_match_sets)
5511 return -EINVAL; 5541 return -EINVAL;
@@ -5633,6 +5663,15 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
5633 goto out_free; 5663 goto out_free;
5634 ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; 5664 ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
5635 if (ssid) { 5665 if (ssid) {
5666 if (WARN_ON(i >= n_match_sets)) {
5667 /* this indicates a programming error,
5668 * the loop above should have verified
5669 * things properly
5670 */
5671 err = -EINVAL;
5672 goto out_free;
5673 }
5674
5636 if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { 5675 if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
5637 err = -EINVAL; 5676 err = -EINVAL;
5638 goto out_free; 5677 goto out_free;
@@ -5641,15 +5680,28 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
5641 nla_data(ssid), nla_len(ssid)); 5680 nla_data(ssid), nla_len(ssid));
5642 request->match_sets[i].ssid.ssid_len = 5681 request->match_sets[i].ssid.ssid_len =
5643 nla_len(ssid); 5682 nla_len(ssid);
5683 /* special attribute - old implemenation w/a */
5684 request->match_sets[i].rssi_thold =
5685 default_match_rssi;
5686 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
5687 if (rssi)
5688 request->match_sets[i].rssi_thold =
5689 nla_get_s32(rssi);
5644 } 5690 }
5645 rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
5646 if (rssi)
5647 request->rssi_thold = nla_get_u32(rssi);
5648 else
5649 request->rssi_thold =
5650 NL80211_SCAN_RSSI_THOLD_OFF;
5651 i++; 5691 i++;
5652 } 5692 }
5693
5694 /* there was no other matchset, so the RSSI one is alone */
5695 if (i == 0)
5696 request->match_sets[0].rssi_thold = default_match_rssi;
5697
5698 request->min_rssi_thold = INT_MAX;
5699 for (i = 0; i < n_match_sets; i++)
5700 request->min_rssi_thold =
5701 min(request->match_sets[i].rssi_thold,
5702 request->min_rssi_thold);
5703 } else {
5704 request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
5653 } 5705 }
5654 5706
5655 if (info->attrs[NL80211_ATTR_IE]) { 5707 if (info->attrs[NL80211_ATTR_IE]) {