aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-07-30 03:13:03 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-07-30 03:13:03 -0400
commitfcb06702f023a0e7b1e6ebf9746f34b610ca0508 (patch)
treedb022324c4978dd9af059be38822d23455a45f55 /net/wireless/reg.c
parent5e31fc0815a4e2c72b1b495fe7a0d8f9bfb9e4b4 (diff)
parent9dbf5f55f8d35ff9aedc75267f4e4042aaf89755 (diff)
Merge remote-tracking branch 'wireless/master' into mac80211
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c137
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 */
101static DEFINE_MUTEX(reg_mutex); 102static 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 */
108static int reg_num_devs_support_basehint;
109
103static inline void assert_reg_lock(void) 110static inline void assert_reg_lock(void)
104{ 111{
105 lockdep_assert_held(&reg_mutex); 112 lockdep_assert_held(&reg_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 */
131static const struct ieee80211_regdomain world_regdom = { 138static 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
935static 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
944bool reg_last_request_cell_base(void)
945{
946 bool val;
947 assert_cfg80211_lock();
948
949 mutex_lock(&reg_mutex);
950 val = reg_request_cell_base(last_request);
951 mutex_unlock(&reg_mutex);
952 return val;
953}
954
955#ifdef CONFIG_CFG80211_CERTIFICATION_ONUS
956
957/* Core specific check */
958static 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 */
972static 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
979static int reg_ignore_cell_hint(struct regulatory_request *pending_request)
980{
981 return -EOPNOTSUPP;
982}
983static int reg_dev_ignore_cell_hint(struct wiphy *wiphy)
984{
985 return true;
986}
987#endif
988
989
925static bool ignore_reg_update(struct wiphy *wiphy, 990static 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
1183void regulatory_update(struct wiphy *wiphy,
1184 enum nl80211_reg_initiator setby)
1185{
1186 mutex_lock(&reg_mutex);
1187 wiphy_update_regulatory(wiphy, setby);
1188 mutex_unlock(&reg_mutex);
1189}
1190
1191static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) 1251static 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 */
1654int regulatory_hint_user(const char *alpha2) 1727int 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(&reg_mutex); 2348 mutex_unlock(&reg_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
2389void wiphy_regulatory_register(struct wiphy *wiphy)
2390{
2391 assert_cfg80211_lock();
2392
2393 mutex_lock(&reg_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(&reg_mutex);
2401}
2402
2304/* Caller must hold cfg80211_mutex */ 2403/* Caller must hold cfg80211_mutex */
2305void reg_device_remove(struct wiphy *wiphy) 2404void 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(&reg_mutex); 2410 mutex_lock(&reg_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}