diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-07-30 03:13:03 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-07-30 03:13:03 -0400 |
commit | fcb06702f023a0e7b1e6ebf9746f34b610ca0508 (patch) | |
tree | db022324c4978dd9af059be38822d23455a45f55 /net/wireless/reg.c | |
parent | 5e31fc0815a4e2c72b1b495fe7a0d8f9bfb9e4b4 (diff) | |
parent | 9dbf5f55f8d35ff9aedc75267f4e4042aaf89755 (diff) |
Merge remote-tracking branch 'wireless/master' into mac80211
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r-- | net/wireless/reg.c | 137 |
1 files changed, 120 insertions, 17 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 460af03d8149..a9175fedeb59 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -97,9 +97,16 @@ const struct ieee80211_regdomain *cfg80211_regdomain; | |||
97 | * - cfg80211_world_regdom | 97 | * - cfg80211_world_regdom |
98 | * - cfg80211_regdom | 98 | * - cfg80211_regdom |
99 | * - last_request | 99 | * - last_request |
100 | * - reg_num_devs_support_basehint | ||
100 | */ | 101 | */ |
101 | static DEFINE_MUTEX(reg_mutex); | 102 | static DEFINE_MUTEX(reg_mutex); |
102 | 103 | ||
104 | /* | ||
105 | * Number of devices that registered to the core | ||
106 | * that support cellular base station regulatory hints | ||
107 | */ | ||
108 | static int reg_num_devs_support_basehint; | ||
109 | |||
103 | static inline void assert_reg_lock(void) | 110 | static inline void assert_reg_lock(void) |
104 | { | 111 | { |
105 | lockdep_assert_held(®_mutex); | 112 | lockdep_assert_held(®_mutex); |
@@ -129,7 +136,7 @@ static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); | |||
129 | 136 | ||
130 | /* We keep a static world regulatory domain in case of the absence of CRDA */ | 137 | /* We keep a static world regulatory domain in case of the absence of CRDA */ |
131 | static const struct ieee80211_regdomain world_regdom = { | 138 | static const struct ieee80211_regdomain world_regdom = { |
132 | .n_reg_rules = 5, | 139 | .n_reg_rules = 6, |
133 | .alpha2 = "00", | 140 | .alpha2 = "00", |
134 | .reg_rules = { | 141 | .reg_rules = { |
135 | /* IEEE 802.11b/g, channels 1..11 */ | 142 | /* IEEE 802.11b/g, channels 1..11 */ |
@@ -156,6 +163,9 @@ static const struct ieee80211_regdomain world_regdom = { | |||
156 | REG_RULE(5745-10, 5825+10, 40, 6, 20, | 163 | REG_RULE(5745-10, 5825+10, 40, 6, 20, |
157 | NL80211_RRF_PASSIVE_SCAN | | 164 | NL80211_RRF_PASSIVE_SCAN | |
158 | NL80211_RRF_NO_IBSS), | 165 | NL80211_RRF_NO_IBSS), |
166 | |||
167 | /* IEEE 802.11ad (60gHz), channels 1..3 */ | ||
168 | REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), | ||
159 | } | 169 | } |
160 | }; | 170 | }; |
161 | 171 | ||
@@ -922,6 +932,61 @@ static void handle_band(struct wiphy *wiphy, | |||
922 | handle_channel(wiphy, initiator, band, i); | 932 | handle_channel(wiphy, initiator, band, i); |
923 | } | 933 | } |
924 | 934 | ||
935 | static bool reg_request_cell_base(struct regulatory_request *request) | ||
936 | { | ||
937 | if (request->initiator != NL80211_REGDOM_SET_BY_USER) | ||
938 | return false; | ||
939 | if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE) | ||
940 | return false; | ||
941 | return true; | ||
942 | } | ||
943 | |||
944 | bool reg_last_request_cell_base(void) | ||
945 | { | ||
946 | bool val; | ||
947 | assert_cfg80211_lock(); | ||
948 | |||
949 | mutex_lock(®_mutex); | ||
950 | val = reg_request_cell_base(last_request); | ||
951 | mutex_unlock(®_mutex); | ||
952 | return val; | ||
953 | } | ||
954 | |||
955 | #ifdef CONFIG_CFG80211_CERTIFICATION_ONUS | ||
956 | |||
957 | /* Core specific check */ | ||
958 | static int reg_ignore_cell_hint(struct regulatory_request *pending_request) | ||
959 | { | ||
960 | if (!reg_num_devs_support_basehint) | ||
961 | return -EOPNOTSUPP; | ||
962 | |||
963 | if (reg_request_cell_base(last_request)) { | ||
964 | if (!regdom_changes(pending_request->alpha2)) | ||
965 | return -EALREADY; | ||
966 | return 0; | ||
967 | } | ||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | /* Device specific check */ | ||
972 | static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy) | ||
973 | { | ||
974 | if (!(wiphy->features & NL80211_FEATURE_CELL_BASE_REG_HINTS)) | ||
975 | return true; | ||
976 | return false; | ||
977 | } | ||
978 | #else | ||
979 | static int reg_ignore_cell_hint(struct regulatory_request *pending_request) | ||
980 | { | ||
981 | return -EOPNOTSUPP; | ||
982 | } | ||
983 | static int reg_dev_ignore_cell_hint(struct wiphy *wiphy) | ||
984 | { | ||
985 | return true; | ||
986 | } | ||
987 | #endif | ||
988 | |||
989 | |||
925 | static bool ignore_reg_update(struct wiphy *wiphy, | 990 | static bool ignore_reg_update(struct wiphy *wiphy, |
926 | enum nl80211_reg_initiator initiator) | 991 | enum nl80211_reg_initiator initiator) |
927 | { | 992 | { |
@@ -955,6 +1020,9 @@ static bool ignore_reg_update(struct wiphy *wiphy, | |||
955 | return true; | 1020 | return true; |
956 | } | 1021 | } |
957 | 1022 | ||
1023 | if (reg_request_cell_base(last_request)) | ||
1024 | return reg_dev_ignore_cell_hint(wiphy); | ||
1025 | |||
958 | return false; | 1026 | return false; |
959 | } | 1027 | } |
960 | 1028 | ||
@@ -1180,14 +1248,6 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, | |||
1180 | wiphy->reg_notifier(wiphy, last_request); | 1248 | wiphy->reg_notifier(wiphy, last_request); |
1181 | } | 1249 | } |
1182 | 1250 | ||
1183 | void regulatory_update(struct wiphy *wiphy, | ||
1184 | enum nl80211_reg_initiator setby) | ||
1185 | { | ||
1186 | mutex_lock(®_mutex); | ||
1187 | wiphy_update_regulatory(wiphy, setby); | ||
1188 | mutex_unlock(®_mutex); | ||
1189 | } | ||
1190 | |||
1191 | static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) | 1251 | static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) |
1192 | { | 1252 | { |
1193 | struct cfg80211_registered_device *rdev; | 1253 | struct cfg80211_registered_device *rdev; |
@@ -1318,6 +1378,13 @@ static int ignore_request(struct wiphy *wiphy, | |||
1318 | return 0; | 1378 | return 0; |
1319 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: | 1379 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: |
1320 | 1380 | ||
1381 | if (reg_request_cell_base(last_request)) { | ||
1382 | /* Trust a Cell base station over the AP's country IE */ | ||
1383 | if (regdom_changes(pending_request->alpha2)) | ||
1384 | return -EOPNOTSUPP; | ||
1385 | return -EALREADY; | ||
1386 | } | ||
1387 | |||
1321 | last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | 1388 | last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); |
1322 | 1389 | ||
1323 | if (unlikely(!is_an_alpha2(pending_request->alpha2))) | 1390 | if (unlikely(!is_an_alpha2(pending_request->alpha2))) |
@@ -1362,6 +1429,12 @@ static int ignore_request(struct wiphy *wiphy, | |||
1362 | 1429 | ||
1363 | return REG_INTERSECT; | 1430 | return REG_INTERSECT; |
1364 | case NL80211_REGDOM_SET_BY_USER: | 1431 | case NL80211_REGDOM_SET_BY_USER: |
1432 | if (reg_request_cell_base(pending_request)) | ||
1433 | return reg_ignore_cell_hint(pending_request); | ||
1434 | |||
1435 | if (reg_request_cell_base(last_request)) | ||
1436 | return -EOPNOTSUPP; | ||
1437 | |||
1365 | if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) | 1438 | if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) |
1366 | return REG_INTERSECT; | 1439 | return REG_INTERSECT; |
1367 | /* | 1440 | /* |
@@ -1651,7 +1724,8 @@ static int regulatory_hint_core(const char *alpha2) | |||
1651 | } | 1724 | } |
1652 | 1725 | ||
1653 | /* User hints */ | 1726 | /* User hints */ |
1654 | int regulatory_hint_user(const char *alpha2) | 1727 | int regulatory_hint_user(const char *alpha2, |
1728 | enum nl80211_user_reg_hint_type user_reg_hint_type) | ||
1655 | { | 1729 | { |
1656 | struct regulatory_request *request; | 1730 | struct regulatory_request *request; |
1657 | 1731 | ||
@@ -1665,6 +1739,7 @@ int regulatory_hint_user(const char *alpha2) | |||
1665 | request->alpha2[0] = alpha2[0]; | 1739 | request->alpha2[0] = alpha2[0]; |
1666 | request->alpha2[1] = alpha2[1]; | 1740 | request->alpha2[1] = alpha2[1]; |
1667 | request->initiator = NL80211_REGDOM_SET_BY_USER; | 1741 | request->initiator = NL80211_REGDOM_SET_BY_USER; |
1742 | request->user_reg_hint_type = user_reg_hint_type; | ||
1668 | 1743 | ||
1669 | queue_regulatory_request(request); | 1744 | queue_regulatory_request(request); |
1670 | 1745 | ||
@@ -1917,7 +1992,7 @@ static void restore_regulatory_settings(bool reset_user) | |||
1917 | * settings, user regulatory settings takes precedence. | 1992 | * settings, user regulatory settings takes precedence. |
1918 | */ | 1993 | */ |
1919 | if (is_an_alpha2(alpha2)) | 1994 | if (is_an_alpha2(alpha2)) |
1920 | regulatory_hint_user(user_alpha2); | 1995 | regulatory_hint_user(user_alpha2, NL80211_USER_REG_HINT_USER); |
1921 | 1996 | ||
1922 | if (list_empty(&tmp_reg_req_list)) | 1997 | if (list_empty(&tmp_reg_req_list)) |
1923 | return; | 1998 | return; |
@@ -2092,9 +2167,16 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
2092 | else { | 2167 | else { |
2093 | if (is_unknown_alpha2(rd->alpha2)) | 2168 | if (is_unknown_alpha2(rd->alpha2)) |
2094 | pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n"); | 2169 | pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n"); |
2095 | else | 2170 | else { |
2096 | pr_info("Regulatory domain changed to country: %c%c\n", | 2171 | if (reg_request_cell_base(last_request)) |
2097 | rd->alpha2[0], rd->alpha2[1]); | 2172 | pr_info("Regulatory domain changed " |
2173 | "to country: %c%c by Cell Station\n", | ||
2174 | rd->alpha2[0], rd->alpha2[1]); | ||
2175 | else | ||
2176 | pr_info("Regulatory domain changed " | ||
2177 | "to country: %c%c\n", | ||
2178 | rd->alpha2[0], rd->alpha2[1]); | ||
2179 | } | ||
2098 | } | 2180 | } |
2099 | print_dfs_region(rd->dfs_region); | 2181 | print_dfs_region(rd->dfs_region); |
2100 | print_rd_rules(rd); | 2182 | print_rd_rules(rd); |
@@ -2139,7 +2221,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2139 | * checking if the alpha2 changes if CRDA was already called | 2221 | * checking if the alpha2 changes if CRDA was already called |
2140 | */ | 2222 | */ |
2141 | if (!regdom_changes(rd->alpha2)) | 2223 | if (!regdom_changes(rd->alpha2)) |
2142 | return -EINVAL; | 2224 | return -EALREADY; |
2143 | } | 2225 | } |
2144 | 2226 | ||
2145 | /* | 2227 | /* |
@@ -2259,6 +2341,9 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2259 | /* Note that this doesn't update the wiphys, this is done below */ | 2341 | /* Note that this doesn't update the wiphys, this is done below */ |
2260 | r = __set_regdom(rd); | 2342 | r = __set_regdom(rd); |
2261 | if (r) { | 2343 | if (r) { |
2344 | if (r == -EALREADY) | ||
2345 | reg_set_request_processed(); | ||
2346 | |||
2262 | kfree(rd); | 2347 | kfree(rd); |
2263 | mutex_unlock(®_mutex); | 2348 | mutex_unlock(®_mutex); |
2264 | return r; | 2349 | return r; |
@@ -2301,8 +2386,22 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
2301 | } | 2386 | } |
2302 | #endif /* CONFIG_HOTPLUG */ | 2387 | #endif /* CONFIG_HOTPLUG */ |
2303 | 2388 | ||
2389 | void wiphy_regulatory_register(struct wiphy *wiphy) | ||
2390 | { | ||
2391 | assert_cfg80211_lock(); | ||
2392 | |||
2393 | mutex_lock(®_mutex); | ||
2394 | |||
2395 | if (!reg_dev_ignore_cell_hint(wiphy)) | ||
2396 | reg_num_devs_support_basehint++; | ||
2397 | |||
2398 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); | ||
2399 | |||
2400 | mutex_unlock(®_mutex); | ||
2401 | } | ||
2402 | |||
2304 | /* Caller must hold cfg80211_mutex */ | 2403 | /* Caller must hold cfg80211_mutex */ |
2305 | void reg_device_remove(struct wiphy *wiphy) | 2404 | void wiphy_regulatory_deregister(struct wiphy *wiphy) |
2306 | { | 2405 | { |
2307 | struct wiphy *request_wiphy = NULL; | 2406 | struct wiphy *request_wiphy = NULL; |
2308 | 2407 | ||
@@ -2310,6 +2409,9 @@ void reg_device_remove(struct wiphy *wiphy) | |||
2310 | 2409 | ||
2311 | mutex_lock(®_mutex); | 2410 | mutex_lock(®_mutex); |
2312 | 2411 | ||
2412 | if (!reg_dev_ignore_cell_hint(wiphy)) | ||
2413 | reg_num_devs_support_basehint--; | ||
2414 | |||
2313 | kfree(wiphy->regd); | 2415 | kfree(wiphy->regd); |
2314 | 2416 | ||
2315 | if (last_request) | 2417 | if (last_request) |
@@ -2375,7 +2477,8 @@ int __init regulatory_init(void) | |||
2375 | * as a user hint. | 2477 | * as a user hint. |
2376 | */ | 2478 | */ |
2377 | if (!is_world_regdom(ieee80211_regdom)) | 2479 | if (!is_world_regdom(ieee80211_regdom)) |
2378 | regulatory_hint_user(ieee80211_regdom); | 2480 | regulatory_hint_user(ieee80211_regdom, |
2481 | NL80211_USER_REG_HINT_USER); | ||
2379 | 2482 | ||
2380 | return 0; | 2483 | return 0; |
2381 | } | 2484 | } |