diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 87783893327a..c57fb8454a7f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -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; diff --git a/net/wireless/core.c b/net/wireless/core.c index 2c7960467206..8a1f34e95c4f 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -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 diff --git a/net/wireless/core.h b/net/wireless/core.h index c85832d28199..6c3d25b7fa6e 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -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); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 96205805da3c..1eb5643b68f5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -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,