diff --git a/net/wireless/core.c b/net/wireless/core.c index cde3ca85494d..3dfbfb0c10f3 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -671,6 +671,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, INIT_WORK(&rdev->sched_scan_res_wk, cfg80211_sched_scan_results_wk); wiphy_work_init(&rdev->reg_check_chans_wk, reg_leave_invalid_chans_wk); INIT_WORK(&rdev->reg_leave_nan_wk, reg_leave_invalid_nan_wk); + wiphy_work_init(&rdev->reg_self_managed_wk, reg_process_self_managed_hint_wk); INIT_WORK(&rdev->propagate_radar_detect_wk, cfg80211_propagate_radar_detect_wk); INIT_WORK(&rdev->propagate_cac_done_wk, cfg80211_propagate_cac_done_wk); diff --git a/net/wireless/core.h b/net/wireless/core.h index 6138d207caf4..2b3239d0cf1f 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -116,6 +116,7 @@ struct cfg80211_registered_device { struct work_struct sched_scan_res_wk; struct wiphy_work reg_check_chans_wk; struct work_struct reg_leave_nan_wk; + struct wiphy_work reg_self_managed_wk; struct cfg80211_chan_def radar_chandef; struct work_struct propagate_radar_detect_wk; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 11665e0a7efc..22022e7da7ec 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -3180,7 +3180,7 @@ static void reg_process_pending_beacon_hints(void) spin_unlock_bh(®_pending_beacons_lock); } -static void reg_process_self_managed_hint(struct wiphy *wiphy) +static bool reg_process_self_managed_hint(struct wiphy *wiphy) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); const struct ieee80211_regdomain *tmp; @@ -3188,7 +3188,6 @@ static void reg_process_self_managed_hint(struct wiphy *wiphy) enum nl80211_band band; struct regulatory_request request = {}; - ASSERT_RTNL(); lockdep_assert_wiphy(wiphy); spin_lock(®_requests_lock); @@ -3197,7 +3196,7 @@ static void reg_process_self_managed_hint(struct wiphy *wiphy) spin_unlock(®_requests_lock); if (!regd) - return; + return false; tmp = get_wiphy_regdom(wiphy); rcu_assign_pointer(wiphy->regd, regd); @@ -3217,6 +3216,15 @@ static void reg_process_self_managed_hint(struct wiphy *wiphy) reg_call_notifier(wiphy, &request); nl80211_send_wiphy_reg_change_event(&request); + return true; +} + +void reg_process_self_managed_hint_wk(struct wiphy *wiphy, struct wiphy_work *work) +{ + lockdep_assert_held(&wiphy->mtx); + + if (reg_process_self_managed_hint(wiphy)) + reg_check_channels(); } static void reg_process_self_managed_hints(void) @@ -3226,12 +3234,17 @@ static void reg_process_self_managed_hints(void) ASSERT_RTNL(); for_each_rdev(rdev) { - guard(wiphy)(&rdev->wiphy); + bool has_hint; - reg_process_self_managed_hint(&rdev->wiphy); - } + spin_lock(®_requests_lock); + has_hint = !!rdev->requested_regd; + spin_unlock(®_requests_lock); - reg_check_channels(); + if (!has_hint) + continue; + + wiphy_work_queue(&rdev->wiphy, &rdev->reg_self_managed_wk); + } } static void reg_todo(struct work_struct *work) @@ -4110,8 +4123,8 @@ int regulatory_set_wiphy_regd_sync(struct wiphy *wiphy, return ret; /* process the request immediately */ - reg_process_self_managed_hint(wiphy); - reg_check_channels(); + if (reg_process_self_managed_hint(wiphy)) + reg_check_channels(); return 0; } EXPORT_SYMBOL(regulatory_set_wiphy_regd_sync); @@ -4144,9 +4157,17 @@ void wiphy_regulatory_register(struct wiphy *wiphy) void wiphy_regulatory_deregister(struct wiphy *wiphy) { + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct wiphy *request_wiphy = NULL; struct regulatory_request *lr; + spin_lock(®_requests_lock); + kfree(rdev->requested_regd); + rdev->requested_regd = NULL; + spin_unlock(®_requests_lock); + + wiphy_work_cancel(wiphy, &rdev->reg_self_managed_wk); + lr = get_last_request(); if (!reg_dev_ignore_cell_hint(wiphy)) diff --git a/net/wireless/reg.h b/net/wireless/reg.h index c587079ead8f..4cfac05c6178 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -194,6 +194,13 @@ void reg_leave_invalid_chans_wk(struct wiphy *wiphy, struct wiphy_work *work); */ void reg_leave_invalid_nan_wk(struct work_struct *work); +/** + * reg_process_self_managed_hint_wk - process self-managed hint for a wiphy + * @wiphy: the wiphy to process + * @work: the work struct + */ +void reg_process_self_managed_hint_wk(struct wiphy *wiphy, struct wiphy_work *work); + extern const u8 shipped_regdb_certs[]; extern unsigned int shipped_regdb_certs_len; extern const u8 extra_regdb_certs[];