diff options
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 19 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/scan.c | 3 | ||||
| -rw-r--r-- | include/net/cfg80211.h | 9 | ||||
| -rw-r--r-- | include/uapi/linux/nl80211.h | 10 | ||||
| -rw-r--r-- | net/wireless/nl80211.c | 70 |
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 | */ |
| 1399 | struct cfg80211_match_set { | 1400 | struct 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 | */ |
| 1425 | struct cfg80211_sched_scan_request { | 1428 | struct 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]) { |
