|
@@ -1307,6 +1307,9 @@ static bool ignore_reg_update(struct wiphy *wiphy,
|
|
|
{
|
|
|
struct regulatory_request *lr = get_last_request();
|
|
|
|
|
|
+ if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
|
|
|
+ return true;
|
|
|
+
|
|
|
if (!lr) {
|
|
|
REG_DBG_PRINT("Ignoring regulatory request set by %s "
|
|
|
"since last_request is not set\n",
|
|
@@ -2147,11 +2150,52 @@ static void reg_process_pending_beacon_hints(void)
|
|
|
spin_unlock_bh(®_pending_beacons_lock);
|
|
|
}
|
|
|
|
|
|
+static void reg_process_self_managed_hints(void)
|
|
|
+{
|
|
|
+ struct cfg80211_registered_device *rdev;
|
|
|
+ struct wiphy *wiphy;
|
|
|
+ const struct ieee80211_regdomain *tmp;
|
|
|
+ const struct ieee80211_regdomain *regd;
|
|
|
+ enum ieee80211_band band;
|
|
|
+ struct regulatory_request request = {};
|
|
|
+
|
|
|
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
|
|
|
+ wiphy = &rdev->wiphy;
|
|
|
+
|
|
|
+ spin_lock(®_requests_lock);
|
|
|
+ regd = rdev->requested_regd;
|
|
|
+ rdev->requested_regd = NULL;
|
|
|
+ spin_unlock(®_requests_lock);
|
|
|
+
|
|
|
+ if (regd == NULL)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ tmp = get_wiphy_regdom(wiphy);
|
|
|
+ rcu_assign_pointer(wiphy->regd, regd);
|
|
|
+ rcu_free_regdom(tmp);
|
|
|
+
|
|
|
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++)
|
|
|
+ handle_band_custom(wiphy, wiphy->bands[band], regd);
|
|
|
+
|
|
|
+ reg_process_ht_flags(wiphy);
|
|
|
+
|
|
|
+ request.wiphy_idx = get_wiphy_idx(wiphy);
|
|
|
+ request.alpha2[0] = regd->alpha2[0];
|
|
|
+ request.alpha2[1] = regd->alpha2[1];
|
|
|
+ request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
|
|
|
+
|
|
|
+ nl80211_send_wiphy_reg_change_event(&request);
|
|
|
+ }
|
|
|
+
|
|
|
+ reg_check_channels();
|
|
|
+}
|
|
|
+
|
|
|
static void reg_todo(struct work_struct *work)
|
|
|
{
|
|
|
rtnl_lock();
|
|
|
reg_process_pending_hints();
|
|
|
reg_process_pending_beacon_hints();
|
|
|
+ reg_process_self_managed_hints();
|
|
|
rtnl_unlock();
|
|
|
}
|
|
|
|
|
@@ -2432,6 +2476,8 @@ static void restore_regulatory_settings(bool reset_user)
|
|
|
world_alpha2[1] = cfg80211_world_regdom->alpha2[1];
|
|
|
|
|
|
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
|
|
|
+ if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
|
|
|
+ continue;
|
|
|
if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG)
|
|
|
restore_custom_reg_settings(&rdev->wiphy);
|
|
|
}
|
|
@@ -2835,10 +2881,52 @@ int set_regdom(const struct ieee80211_regdomain *rd)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+int regulatory_set_wiphy_regd(struct wiphy *wiphy,
|
|
|
+ struct ieee80211_regdomain *rd)
|
|
|
+{
|
|
|
+ const struct ieee80211_regdomain *regd;
|
|
|
+ const struct ieee80211_regdomain *prev_regd;
|
|
|
+ struct cfg80211_registered_device *rdev;
|
|
|
+
|
|
|
+ if (WARN_ON(!wiphy || !rd))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (WARN(!(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED),
|
|
|
+ "wiphy should have REGULATORY_WIPHY_SELF_MANAGED\n"))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ if (WARN(!is_valid_rd(rd), "Invalid regulatory domain detected\n")) {
|
|
|
+ print_regdomain_info(rd);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ regd = reg_copy_regd(rd);
|
|
|
+ if (IS_ERR(regd))
|
|
|
+ return PTR_ERR(regd);
|
|
|
+
|
|
|
+ rdev = wiphy_to_rdev(wiphy);
|
|
|
+
|
|
|
+ spin_lock(®_requests_lock);
|
|
|
+ prev_regd = rdev->requested_regd;
|
|
|
+ rdev->requested_regd = regd;
|
|
|
+ spin_unlock(®_requests_lock);
|
|
|
+
|
|
|
+ kfree(prev_regd);
|
|
|
+
|
|
|
+ schedule_work(®_work);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(regulatory_set_wiphy_regd);
|
|
|
+
|
|
|
void wiphy_regulatory_register(struct wiphy *wiphy)
|
|
|
{
|
|
|
struct regulatory_request *lr;
|
|
|
|
|
|
+ /* self-managed devices ignore external hints */
|
|
|
+ if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
|
|
|
+ wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS |
|
|
|
+ REGULATORY_COUNTRY_IE_IGNORE;
|
|
|
+
|
|
|
if (!reg_dev_ignore_cell_hint(wiphy))
|
|
|
reg_num_devs_support_basehint++;
|
|
|
|