This is a note to let you know that I've just added the patch titled wifi: cfg80211: fix CQM for non-range use to the 6.1-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: wifi-cfg80211-fix-cqm-for-non-range-use.patch and it can be found in the queue-6.1 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From leo@xxxxxxxxx Sat Dec 16 05:48:17 2023 From: "Léo Lam" <leo@xxxxxxxxx> Date: Sat, 16 Dec 2023 05:47:15 +0000 Subject: wifi: cfg80211: fix CQM for non-range use To: stable@xxxxxxxxxxxxxxx Cc: "Johannes Berg" <johannes.berg@xxxxxxxxx>, "Greg Kroah-Hartman" <gregkh@xxxxxxxxxxxxxxxxxxx>, "Léo Lam" <leo@xxxxxxxxx> Message-ID: <20231216054715.7729-2-leo@xxxxxxxxx> From: Johannes Berg <johannes.berg@xxxxxxxxx> commit 7e7efdda6adb385fbdfd6f819d76bc68c923c394 upstream. [note: this is commit 4a7e92551618f3737b305f62451353ee05662f57 reapplied; that commit had been reverted in 6.6.6 because it caused regressions, see https://lore.kernel.org/stable/2023121450-habitual-transpose-68a1@gregkh/ for details] 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@xxxxxxxxxxxxxxx Fixes: 4a4b8169501b ("cfg80211: Accept multiple RSSI thresholds for CQM") Fixes: 37c20b2effe9 ("wifi: cfg80211: fix cqm_config access race") Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> Signed-off-by: Léo Lam <leo@xxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- net/wireless/core.h | 1 net/wireless/nl80211.c | 50 ++++++++++++++++++++++++++++++------------------- 2 files changed, 32 insertions(+), 19 deletions(-) --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -297,6 +297,7 @@ struct cfg80211_cqm_config { u32 rssi_hyst; s32 last_rssi_event_value; enum nl80211_cqm_rssi_threshold_event last_rssi_event_type; + bool use_range_api; int n_rssi_thresholds; s32 rssi_thresholds[]; }; --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -12574,10 +12574,6 @@ static int cfg80211_cqm_rssi_update(stru int i, n, low_index; int err; - /* RSSI reporting disabled? */ - if (!cqm_config) - return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0); - /* * Obtain current RSSI value if possible, if not and no RSSI threshold * event has been received yet, we should receive an event after a @@ -12652,18 +12648,6 @@ static int nl80211_set_cqm_rssi(struct g wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) { - if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */ - return rdev_set_cqm_rssi_config(rdev, dev, 0, 0); - - return rdev_set_cqm_rssi_config(rdev, dev, - thresholds[0], hysteresis); - } - - if (!wiphy_ext_feature_isset(&rdev->wiphy, - NL80211_EXT_FEATURE_CQM_RSSI_LIST)) - return -EOPNOTSUPP; - if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */ n_thresholds = 0; @@ -12671,6 +12655,20 @@ static int nl80211_set_cqm_rssi(struct g old = rcu_dereference_protected(wdev->cqm_config, lockdep_is_held(&wdev->mtx)); + /* if already disabled just succeed */ + if (!n_thresholds && !old) + return 0; + + if (n_thresholds > 1) { + if (!wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_CQM_RSSI_LIST) || + !rdev->ops->set_cqm_rssi_range_config) + return -EOPNOTSUPP; + } else { + if (!rdev->ops->set_cqm_rssi_config) + return -EOPNOTSUPP; + } + if (n_thresholds) { cqm_config = kzalloc(struct_size(cqm_config, rssi_thresholds, n_thresholds), @@ -12685,13 +12683,26 @@ static int nl80211_set_cqm_rssi(struct g memcpy(cqm_config->rssi_thresholds, thresholds, flex_array_size(cqm_config, rssi_thresholds, n_thresholds)); + cqm_config->use_range_api = n_thresholds > 1 || + !rdev->ops->set_cqm_rssi_config; rcu_assign_pointer(wdev->cqm_config, cqm_config); + + if (cqm_config->use_range_api) + err = cfg80211_cqm_rssi_update(rdev, dev, cqm_config); + else + err = rdev_set_cqm_rssi_config(rdev, dev, + thresholds[0], + hysteresis); } else { RCU_INIT_POINTER(wdev->cqm_config, NULL); + /* if enabled as range also disable via range */ + if (old->use_range_api) + err = rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0); + else + err = rdev_set_cqm_rssi_config(rdev, dev, 0, 0); } - err = cfg80211_cqm_rssi_update(rdev, dev, cqm_config); if (err) { rcu_assign_pointer(wdev->cqm_config, old); kfree_rcu(cqm_config, rcu_head); @@ -18758,10 +18769,11 @@ void cfg80211_cqm_rssi_notify_work(struc wdev_lock(wdev); cqm_config = rcu_dereference_protected(wdev->cqm_config, lockdep_is_held(&wdev->mtx)); - if (!wdev->cqm_config) + if (!cqm_config) goto unlock; - cfg80211_cqm_rssi_update(rdev, wdev->netdev, cqm_config); + if (cqm_config->use_range_api) + cfg80211_cqm_rssi_update(rdev, wdev->netdev, cqm_config); rssi_level = cqm_config->last_rssi_event_value; rssi_event = cqm_config->last_rssi_event_type; Patches currently in stable-queue which might be from leo@xxxxxxxxx are queue-6.1/wifi-nl80211-fix-deadlock-in-nl80211_set_cqm_rssi-6.6.x.patch queue-6.1/wifi-cfg80211-fix-cqm-for-non-range-use.patch