Skip to content

Commit 7e7efdd

Browse files
committed
wifi: cfg80211: fix CQM for non-range use
My prior race fix here broke CQM when ranges aren't used, as the reporting worker now requires the cqm_config to be set in the wdev, but isn't set when there's no range configured. Rather than continuing to special-case the range version, set the cqm_config always and configure accordingly, also tracking if range was used or not to be able to clear the configuration appropriately with the same API, which was actually not right if both were implemented by a driver for some reason, as is the case with mac80211 (though there the implementations are equivalent so it doesn't matter.) Also, the original multiple-RSSI commit lost checking for the callback, so might have potentially crashed if a driver had neither implementation, and userspace tried to use it despite not being advertised as supported. Cc: stable@vger.kernel.org Fixes: 4a4b816 ("cfg80211: Accept multiple RSSI thresholds for CQM") Fixes: 37c20b2 ("wifi: cfg80211: fix cqm_config access race") Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent 3e3a2b6 commit 7e7efdd

2 files changed

Lines changed: 32 additions & 19 deletions

File tree

net/wireless/core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ struct cfg80211_cqm_config {
293293
u32 rssi_hyst;
294294
s32 last_rssi_event_value;
295295
enum nl80211_cqm_rssi_threshold_event last_rssi_event_type;
296+
bool use_range_api;
296297
int n_rssi_thresholds;
297298
s32 rssi_thresholds[] __counted_by(n_rssi_thresholds);
298299
};

net/wireless/nl80211.c

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12787,10 +12787,6 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
1278712787
int i, n, low_index;
1278812788
int err;
1278912789

12790-
/* RSSI reporting disabled? */
12791-
if (!cqm_config)
12792-
return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
12793-
1279412790
/*
1279512791
* Obtain current RSSI value if possible, if not and no RSSI threshold
1279612792
* event has been received yet, we should receive an event after a
@@ -12865,23 +12861,25 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
1286512861
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
1286612862
return -EOPNOTSUPP;
1286712863

12868-
if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
12869-
if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */
12870-
return rdev_set_cqm_rssi_config(rdev, dev, 0, 0);
12871-
12872-
return rdev_set_cqm_rssi_config(rdev, dev,
12873-
thresholds[0], hysteresis);
12874-
}
12875-
12876-
if (!wiphy_ext_feature_isset(&rdev->wiphy,
12877-
NL80211_EXT_FEATURE_CQM_RSSI_LIST))
12878-
return -EOPNOTSUPP;
12879-
1288012864
if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */
1288112865
n_thresholds = 0;
1288212866

1288312867
old = wiphy_dereference(wdev->wiphy, wdev->cqm_config);
1288412868

12869+
/* if already disabled just succeed */
12870+
if (!n_thresholds && !old)
12871+
return 0;
12872+
12873+
if (n_thresholds > 1) {
12874+
if (!wiphy_ext_feature_isset(&rdev->wiphy,
12875+
NL80211_EXT_FEATURE_CQM_RSSI_LIST) ||
12876+
!rdev->ops->set_cqm_rssi_range_config)
12877+
return -EOPNOTSUPP;
12878+
} else {
12879+
if (!rdev->ops->set_cqm_rssi_config)
12880+
return -EOPNOTSUPP;
12881+
}
12882+
1288512883
if (n_thresholds) {
1288612884
cqm_config = kzalloc(struct_size(cqm_config, rssi_thresholds,
1288712885
n_thresholds),
@@ -12894,13 +12892,26 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
1289412892
memcpy(cqm_config->rssi_thresholds, thresholds,
1289512893
flex_array_size(cqm_config, rssi_thresholds,
1289612894
n_thresholds));
12895+
cqm_config->use_range_api = n_thresholds > 1 ||
12896+
!rdev->ops->set_cqm_rssi_config;
1289712897

1289812898
rcu_assign_pointer(wdev->cqm_config, cqm_config);
12899+
12900+
if (cqm_config->use_range_api)
12901+
err = cfg80211_cqm_rssi_update(rdev, dev, cqm_config);
12902+
else
12903+
err = rdev_set_cqm_rssi_config(rdev, dev,
12904+
thresholds[0],
12905+
hysteresis);
1289912906
} else {
1290012907
RCU_INIT_POINTER(wdev->cqm_config, NULL);
12908+
/* if enabled as range also disable via range */
12909+
if (old->use_range_api)
12910+
err = rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
12911+
else
12912+
err = rdev_set_cqm_rssi_config(rdev, dev, 0, 0);
1290112913
}
1290212914

12903-
err = cfg80211_cqm_rssi_update(rdev, dev, cqm_config);
1290412915
if (err) {
1290512916
rcu_assign_pointer(wdev->cqm_config, old);
1290612917
kfree_rcu(cqm_config, rcu_head);
@@ -19009,10 +19020,11 @@ void cfg80211_cqm_rssi_notify_work(struct wiphy *wiphy, struct wiphy_work *work)
1900919020
s32 rssi_level;
1901019021

1901119022
cqm_config = wiphy_dereference(wdev->wiphy, wdev->cqm_config);
19012-
if (!wdev->cqm_config)
19023+
if (!cqm_config)
1901319024
return;
1901419025

19015-
cfg80211_cqm_rssi_update(rdev, wdev->netdev, cqm_config);
19026+
if (cqm_config->use_range_api)
19027+
cfg80211_cqm_rssi_update(rdev, wdev->netdev, cqm_config);
1901619028

1901719029
rssi_level = cqm_config->last_rssi_event_value;
1901819030
rssi_event = cqm_config->last_rssi_event_type;

0 commit comments

Comments
 (0)