Revert "wifi: cfg80211: fix cqm_config access race"

This reverts commit c797498e86 which is
commit 37c20b2effe987b806c8de6d12978e4ffeff026f upstream.

It breaks the Android ABI so revert it for now, if it is needed in the
future, it can be brought back in an ABI-safe way.

Bug: 161946584
Change-Id: Ida8b8621fb3099fd1b40aae5ad481139e7d7f173
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman 2023-10-28 10:54:04 +00:00
parent 92a425f8ff
commit 66a17692b1
4 changed files with 43 additions and 76 deletions

View File

@ -5977,8 +5977,7 @@ struct wireless_dev {
} wext;
#endif
struct wiphy_work cqm_rssi_work;
struct cfg80211_cqm_config __rcu *cqm_config;
struct cfg80211_cqm_config *cqm_config;
struct list_head pmsr_list;
spinlock_t pmsr_lock;

View File

@ -1176,11 +1176,16 @@ void wiphy_rfkill_set_hw_state_reason(struct wiphy *wiphy, bool blocked,
}
EXPORT_SYMBOL(wiphy_rfkill_set_hw_state_reason);
void cfg80211_cqm_config_free(struct wireless_dev *wdev)
{
kfree(wdev->cqm_config);
wdev->cqm_config = NULL;
}
static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
bool unregister_netdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_cqm_config *cqm_config;
unsigned int link_id;
ASSERT_RTNL();
@ -1219,10 +1224,7 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
kfree_sensitive(wdev->wext.keys);
wdev->wext.keys = NULL;
#endif
wiphy_work_cancel(wdev->wiphy, &wdev->cqm_rssi_work);
/* deleted from the list, so can't be found from nl80211 any more */
cqm_config = rcu_access_pointer(wdev->cqm_config);
kfree_rcu(cqm_config, rcu_head);
cfg80211_cqm_config_free(wdev);
/*
* Ensure that all events have been processed and
@ -1374,8 +1376,6 @@ void cfg80211_init_wdev(struct wireless_dev *wdev)
wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
#endif
wiphy_work_init(&wdev->cqm_rssi_work, cfg80211_cqm_rssi_notify_work);
if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT)
wdev->ps = true;
else

View File

@ -295,17 +295,12 @@ struct cfg80211_beacon_registration {
};
struct cfg80211_cqm_config {
struct rcu_head rcu_head;
u32 rssi_hyst;
s32 last_rssi_event_value;
enum nl80211_cqm_rssi_threshold_event last_rssi_event_type;
int n_rssi_thresholds;
s32 rssi_thresholds[];
};
void cfg80211_cqm_rssi_notify_work(struct wiphy *wiphy,
struct wiphy_work *work);
void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev);
/* free object */
@ -571,6 +566,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
#define CFG80211_DEV_WARN_ON(cond) ({bool __r = (cond); __r; })
#endif
void cfg80211_cqm_config_free(struct wireless_dev *wdev);
void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid);
void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev);
void cfg80211_pmsr_free_wk(struct work_struct *work);

View File

@ -12636,8 +12636,7 @@ static int nl80211_set_cqm_txe(struct genl_info *info,
}
static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_cqm_config *cqm_config)
struct net_device *dev)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
s32 last, low, high;
@ -12646,7 +12645,7 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
int err;
/* RSSI reporting disabled? */
if (!cqm_config)
if (!wdev->cqm_config)
return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
/*
@ -12655,7 +12654,7 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
* connection is established and enough beacons received to calculate
* the average.
*/
if (!cqm_config->last_rssi_event_value &&
if (!wdev->cqm_config->last_rssi_event_value &&
wdev->links[0].client.current_bss &&
rdev->ops->get_station) {
struct station_info sinfo = {};
@ -12669,30 +12668,30 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
cfg80211_sinfo_release_content(&sinfo);
if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
cqm_config->last_rssi_event_value =
wdev->cqm_config->last_rssi_event_value =
(s8) sinfo.rx_beacon_signal_avg;
}
last = cqm_config->last_rssi_event_value;
hyst = cqm_config->rssi_hyst;
n = cqm_config->n_rssi_thresholds;
last = wdev->cqm_config->last_rssi_event_value;
hyst = wdev->cqm_config->rssi_hyst;
n = wdev->cqm_config->n_rssi_thresholds;
for (i = 0; i < n; i++) {
i = array_index_nospec(i, n);
if (last < cqm_config->rssi_thresholds[i])
if (last < wdev->cqm_config->rssi_thresholds[i])
break;
}
low_index = i - 1;
if (low_index >= 0) {
low_index = array_index_nospec(low_index, n);
low = cqm_config->rssi_thresholds[low_index] - hyst;
low = wdev->cqm_config->rssi_thresholds[low_index] - hyst;
} else {
low = S32_MIN;
}
if (i < n) {
i = array_index_nospec(i, n);
high = cqm_config->rssi_thresholds[i] + hyst - 1;
high = wdev->cqm_config->rssi_thresholds[i] + hyst - 1;
} else {
high = S32_MAX;
}
@ -12705,7 +12704,6 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
u32 hysteresis)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct cfg80211_cqm_config *cqm_config = NULL, *old;
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
int i, err;
@ -12723,6 +12721,10 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
return -EOPNOTSUPP;
wdev_lock(wdev);
cfg80211_cqm_config_free(wdev);
wdev_unlock(wdev);
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);
@ -12739,10 +12741,9 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
n_thresholds = 0;
wdev_lock(wdev);
old = rcu_dereference_protected(wdev->cqm_config,
lockdep_is_held(&wdev->mtx));
if (n_thresholds) {
struct cfg80211_cqm_config *cqm_config;
cqm_config = kzalloc(struct_size(cqm_config, rssi_thresholds,
n_thresholds),
GFP_KERNEL);
@ -12757,18 +12758,11 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
flex_array_size(cqm_config, rssi_thresholds,
n_thresholds));
rcu_assign_pointer(wdev->cqm_config, cqm_config);
} else {
RCU_INIT_POINTER(wdev->cqm_config, NULL);
wdev->cqm_config = cqm_config;
}
err = cfg80211_cqm_rssi_update(rdev, dev, cqm_config);
if (err) {
rcu_assign_pointer(wdev->cqm_config, old);
kfree_rcu(cqm_config, rcu_head);
} else {
kfree_rcu(old, rcu_head);
}
err = cfg80211_cqm_rssi_update(rdev, dev);
unlock:
wdev_unlock(wdev);
@ -18813,8 +18807,9 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
enum nl80211_cqm_rssi_threshold_event rssi_event,
s32 rssi_level, gfp_t gfp)
{
struct sk_buff *msg;
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_cqm_config *cqm_config;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
@ -18822,41 +18817,18 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
return;
rcu_read_lock();
cqm_config = rcu_dereference(wdev->cqm_config);
if (cqm_config) {
cqm_config->last_rssi_event_value = rssi_level;
cqm_config->last_rssi_event_type = rssi_event;
wiphy_work_queue(wdev->wiphy, &wdev->cqm_rssi_work);
if (wdev->cqm_config) {
wdev->cqm_config->last_rssi_event_value = rssi_level;
cfg80211_cqm_rssi_update(rdev, dev);
if (rssi_level == 0)
rssi_level = wdev->cqm_config->last_rssi_event_value;
}
rcu_read_unlock();
}
EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
void cfg80211_cqm_rssi_notify_work(struct wiphy *wiphy, struct wiphy_work *work)
{
struct wireless_dev *wdev = container_of(work, struct wireless_dev,
cqm_rssi_work);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
enum nl80211_cqm_rssi_threshold_event rssi_event;
struct cfg80211_cqm_config *cqm_config;
struct sk_buff *msg;
s32 rssi_level;
wdev_lock(wdev);
cqm_config = rcu_dereference_protected(wdev->cqm_config,
lockdep_is_held(&wdev->mtx));
if (!wdev->cqm_config)
goto unlock;
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;
msg = cfg80211_prepare_cqm(wdev->netdev, NULL, GFP_KERNEL);
msg = cfg80211_prepare_cqm(dev, NULL, gfp);
if (!msg)
goto unlock;
return;
if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
rssi_event))
@ -18866,15 +18838,14 @@ void cfg80211_cqm_rssi_notify_work(struct wiphy *wiphy, struct wiphy_work *work)
rssi_level))
goto nla_put_failure;
cfg80211_send_cqm(msg, GFP_KERNEL);
cfg80211_send_cqm(msg, gfp);
goto unlock;
return;
nla_put_failure:
nlmsg_free(msg);
unlock:
wdev_unlock(wdev);
}
EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
void cfg80211_cqm_txe_notify(struct net_device *dev,
const u8 *peer, u32 num_packets,