diff options
Diffstat (limited to 'net/wireless/reg.c')
| -rw-r--r-- | net/wireless/reg.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2d9760084b74..c040f8a0f1ed 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
| @@ -1307,6 +1307,9 @@ static bool ignore_reg_update(struct wiphy *wiphy, | |||
| 1307 | { | 1307 | { |
| 1308 | struct regulatory_request *lr = get_last_request(); | 1308 | struct regulatory_request *lr = get_last_request(); |
| 1309 | 1309 | ||
| 1310 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) | ||
| 1311 | return true; | ||
| 1312 | |||
| 1310 | if (!lr) { | 1313 | if (!lr) { |
| 1311 | REG_DBG_PRINT("Ignoring regulatory request set by %s " | 1314 | REG_DBG_PRINT("Ignoring regulatory request set by %s " |
| 1312 | "since last_request is not set\n", | 1315 | "since last_request is not set\n", |
| @@ -2147,11 +2150,52 @@ static void reg_process_pending_beacon_hints(void) | |||
| 2147 | spin_unlock_bh(®_pending_beacons_lock); | 2150 | spin_unlock_bh(®_pending_beacons_lock); |
| 2148 | } | 2151 | } |
| 2149 | 2152 | ||
| 2153 | static void reg_process_self_managed_hints(void) | ||
| 2154 | { | ||
| 2155 | struct cfg80211_registered_device *rdev; | ||
| 2156 | struct wiphy *wiphy; | ||
| 2157 | const struct ieee80211_regdomain *tmp; | ||
| 2158 | const struct ieee80211_regdomain *regd; | ||
| 2159 | enum ieee80211_band band; | ||
| 2160 | struct regulatory_request request = {}; | ||
| 2161 | |||
| 2162 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | ||
| 2163 | wiphy = &rdev->wiphy; | ||
| 2164 | |||
| 2165 | spin_lock(®_requests_lock); | ||
| 2166 | regd = rdev->requested_regd; | ||
| 2167 | rdev->requested_regd = NULL; | ||
| 2168 | spin_unlock(®_requests_lock); | ||
| 2169 | |||
| 2170 | if (regd == NULL) | ||
| 2171 | continue; | ||
| 2172 | |||
| 2173 | tmp = get_wiphy_regdom(wiphy); | ||
| 2174 | rcu_assign_pointer(wiphy->regd, regd); | ||
| 2175 | rcu_free_regdom(tmp); | ||
| 2176 | |||
| 2177 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | ||
| 2178 | handle_band_custom(wiphy, wiphy->bands[band], regd); | ||
| 2179 | |||
| 2180 | reg_process_ht_flags(wiphy); | ||
| 2181 | |||
| 2182 | request.wiphy_idx = get_wiphy_idx(wiphy); | ||
| 2183 | request.alpha2[0] = regd->alpha2[0]; | ||
| 2184 | request.alpha2[1] = regd->alpha2[1]; | ||
| 2185 | request.initiator = NL80211_REGDOM_SET_BY_DRIVER; | ||
| 2186 | |||
| 2187 | nl80211_send_wiphy_reg_change_event(&request); | ||
| 2188 | } | ||
| 2189 | |||
| 2190 | reg_check_channels(); | ||
| 2191 | } | ||
| 2192 | |||
| 2150 | static void reg_todo(struct work_struct *work) | 2193 | static void reg_todo(struct work_struct *work) |
| 2151 | { | 2194 | { |
| 2152 | rtnl_lock(); | 2195 | rtnl_lock(); |
| 2153 | reg_process_pending_hints(); | 2196 | reg_process_pending_hints(); |
| 2154 | reg_process_pending_beacon_hints(); | 2197 | reg_process_pending_beacon_hints(); |
| 2198 | reg_process_self_managed_hints(); | ||
| 2155 | rtnl_unlock(); | 2199 | rtnl_unlock(); |
| 2156 | } | 2200 | } |
| 2157 | 2201 | ||
| @@ -2432,6 +2476,8 @@ static void restore_regulatory_settings(bool reset_user) | |||
| 2432 | world_alpha2[1] = cfg80211_world_regdom->alpha2[1]; | 2476 | world_alpha2[1] = cfg80211_world_regdom->alpha2[1]; |
| 2433 | 2477 | ||
| 2434 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 2478 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
| 2479 | if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) | ||
| 2480 | continue; | ||
| 2435 | if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG) | 2481 | if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG) |
| 2436 | restore_custom_reg_settings(&rdev->wiphy); | 2482 | restore_custom_reg_settings(&rdev->wiphy); |
| 2437 | } | 2483 | } |
| @@ -2835,10 +2881,52 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
| 2835 | return 0; | 2881 | return 0; |
| 2836 | } | 2882 | } |
| 2837 | 2883 | ||
| 2884 | int regulatory_set_wiphy_regd(struct wiphy *wiphy, | ||
| 2885 | struct ieee80211_regdomain *rd) | ||
| 2886 | { | ||
| 2887 | const struct ieee80211_regdomain *regd; | ||
| 2888 | const struct ieee80211_regdomain *prev_regd; | ||
| 2889 | struct cfg80211_registered_device *rdev; | ||
| 2890 | |||
| 2891 | if (WARN_ON(!wiphy || !rd)) | ||
| 2892 | return -EINVAL; | ||
| 2893 | |||
| 2894 | if (WARN(!(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED), | ||
| 2895 | "wiphy should have REGULATORY_WIPHY_SELF_MANAGED\n")) | ||
| 2896 | return -EPERM; | ||
| 2897 | |||
| 2898 | if (WARN(!is_valid_rd(rd), "Invalid regulatory domain detected\n")) { | ||
| 2899 | print_regdomain_info(rd); | ||
| 2900 | return -EINVAL; | ||
| 2901 | } | ||
| 2902 | |||
| 2903 | regd = reg_copy_regd(rd); | ||
| 2904 | if (IS_ERR(regd)) | ||
| 2905 | return PTR_ERR(regd); | ||
| 2906 | |||
| 2907 | rdev = wiphy_to_rdev(wiphy); | ||
| 2908 | |||
| 2909 | spin_lock(®_requests_lock); | ||
| 2910 | prev_regd = rdev->requested_regd; | ||
| 2911 | rdev->requested_regd = regd; | ||
| 2912 | spin_unlock(®_requests_lock); | ||
| 2913 | |||
| 2914 | kfree(prev_regd); | ||
| 2915 | |||
| 2916 | schedule_work(®_work); | ||
| 2917 | return 0; | ||
| 2918 | } | ||
| 2919 | EXPORT_SYMBOL(regulatory_set_wiphy_regd); | ||
| 2920 | |||
| 2838 | void wiphy_regulatory_register(struct wiphy *wiphy) | 2921 | void wiphy_regulatory_register(struct wiphy *wiphy) |
| 2839 | { | 2922 | { |
| 2840 | struct regulatory_request *lr; | 2923 | struct regulatory_request *lr; |
| 2841 | 2924 | ||
| 2925 | /* self-managed devices ignore external hints */ | ||
| 2926 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) | ||
| 2927 | wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS | | ||
| 2928 | REGULATORY_COUNTRY_IE_IGNORE; | ||
| 2929 | |||
| 2842 | if (!reg_dev_ignore_cell_hint(wiphy)) | 2930 | if (!reg_dev_ignore_cell_hint(wiphy)) |
| 2843 | reg_num_devs_support_basehint++; | 2931 | reg_num_devs_support_basehint++; |
| 2844 | 2932 | ||
