Skip to content
This repository was archived by the owner on Dec 20, 2023. It is now read-only.

Commit ea73cbc

Browse files
committed
nl80211: fix scheduled scan RSSI matchset attribute confusion
The scheduled scan matchsets were intended to be a list of filters, with the found BSS having to pass at least one of them to be passed to the host. When the RSSI attribute was added, however, this was broken and currently wpa_supplicant adds that attribute in its own matchset; however, it doesn't intend that to mean that anything that passes the RSSI filter should be passed to the host, instead it wants it to mean that everything needs to also have higher RSSI. This is semantically problematic because we have a list of filters like [ SSID1, SSID2, SSID3, RSSI ] with no real indication which one should be OR'ed and which one AND'ed. To fix this, move the RSSI filter attribute into each matchset. As we need to stay backward compatible, treat a matchset with only the RSSI attribute as a "default RSSI filter" for all other matchsets, but only if there are other matchsets (an RSSI-only matchset by itself is still desirable.) To make driver implementation easier, keep a global min_rssi_thold for the entire request as well. The only affected driver is ath6kl. I found this when I looked into the code after Raja Mani submitted a patch fixing the n_match_sets calculation to disregard the RSSI, but that patch didn't address the semantic issue. Reported-by: Raja Mani <[email protected]> Acked-by: Luciano Coelho <[email protected]> Signed-off-by: Johannes Berg <[email protected]>
1 parent 9fa37a3 commit ea73cbc

File tree

5 files changed

+92
-19
lines changed

5 files changed

+92
-19
lines changed

drivers/net/wireless/ath/ath6kl/cfg80211.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3256,6 +3256,15 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
32563256
struct ath6kl_vif *vif = netdev_priv(dev);
32573257
u16 interval;
32583258
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;
32593268

32603269
if (ar->state != ATH6KL_STATE_ON)
32613270
return -EIO;
@@ -3268,11 +3277,11 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
32683277
ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
32693278
request->n_ssids,
32703279
request->match_sets,
3271-
request->n_match_sets);
3280+
n_match_sets);
32723281
if (ret < 0)
32733282
return ret;
32743283

3275-
if (!request->n_match_sets) {
3284+
if (!n_match_sets) {
32763285
ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
32773286
ALL_BSS_FILTER, 0);
32783287
if (ret < 0)
@@ -3286,12 +3295,12 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
32863295

32873296
if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
32883297
ar->fw_capabilities)) {
3289-
if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
3298+
if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
32903299
rssi_thold = 0;
3291-
else if (request->rssi_thold < -127)
3300+
else if (request->min_rssi_thold < -127)
32923301
rssi_thold = -127;
32933302
else
3294-
rssi_thold = request->rssi_thold;
3303+
rssi_thold = request->min_rssi_thold;
32953304

32963305
ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,
32973306
rssi_thold);

drivers/net/wireless/iwlwifi/mvm/scan.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,9 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
595595
* config match list.
596596
*/
597597
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;
598601
scan->direct_scan[i].id = WLAN_EID_SSID;
599602
scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len;
600603
memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid,

include/net/cfg80211.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,10 +1394,12 @@ struct cfg80211_scan_request {
13941394
/**
13951395
* struct cfg80211_match_set - sets of attributes to match
13961396
*
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)
13981399
*/
13991400
struct cfg80211_match_set {
14001401
struct cfg80211_ssid ssid;
1402+
s32 rssi_thold;
14011403
};
14021404

14031405
/**
@@ -1420,7 +1422,8 @@ struct cfg80211_match_set {
14201422
* @dev: the interface
14211423
* @scan_start: start time of the scheduled scan
14221424
* @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
14241427
*/
14251428
struct cfg80211_sched_scan_request {
14261429
struct cfg80211_ssid *ssids;
@@ -1433,7 +1436,7 @@ struct cfg80211_sched_scan_request {
14331436
u32 flags;
14341437
struct cfg80211_match_set *match_sets;
14351438
int n_match_sets;
1436-
s32 rssi_thold;
1439+
s32 min_rssi_thold;
14371440

14381441
/* internal */
14391442
struct wiphy *wiphy;

include/uapi/linux/nl80211.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2467,9 +2467,15 @@ enum nl80211_reg_rule_attr {
24672467
* enum nl80211_sched_scan_match_attr - scheduled scan match attributes
24682468
* @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
24692469
* @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.
24712471
* @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.
24732479
* @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
24742480
* attribute number currently defined
24752481
* @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use

net/wireless/nl80211.c

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5467,6 +5467,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
54675467
enum ieee80211_band band;
54685468
size_t ie_len;
54695469
struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
5470+
s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
54705471

54715472
if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
54725473
!rdev->ops->sched_scan_start)
@@ -5501,11 +5502,40 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
55015502
if (n_ssids > wiphy->max_sched_scan_ssids)
55025503
return -EINVAL;
55035504

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]) {
55055515
nla_for_each_nested(attr,
55065516
info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
5507-
tmp)
5508-
n_match_sets++;
5517+
tmp) {
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;
55095539

55105540
if (n_match_sets > wiphy->max_match_sets)
55115541
return -EINVAL;
@@ -5633,6 +5663,15 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
56335663
goto out_free;
56345664
ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
56355665
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+
56365675
if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
56375676
err = -EINVAL;
56385677
goto out_free;
@@ -5641,15 +5680,28 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
56415680
nla_data(ssid), nla_len(ssid));
56425681
request->match_sets[i].ssid.ssid_len =
56435682
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);
56445690
}
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;
56515691
i++;
56525692
}
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;
56535705
}
56545706

56555707
if (info->attrs[NL80211_ATTR_IE]) {

0 commit comments

Comments
 (0)