aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
authorLuis R. Rodriguez <mcgrof@qca.qualcomm.com>2012-07-12 14:49:18 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-07-17 06:16:39 -0400
commit57b5ce072e7361218a8e2ea1d62960cbb71d9cff (patch)
treec00265b8f2123f860978d293fa122427ea2139f8 /net/wireless/reg.c
parentb594bab9021f5225a24bcb69d7f7b7272419adb2 (diff)
cfg80211: add cellular base station regulatory hint support
Cellular base stations can provide hints to cfg80211 about where they think we are. This can be done for example on a cell phone. To enable these hints we simply allow them through as user regulatory hints but we allow userspace to clasify the hint as either coming directly from the user or coming from a cellular base station. This option is only available when you enable CONFIG_CFG80211_CERTIFICATION_ONUS. The base station hints themselves will not be processed by the core unless at least one device on the system supports this feature. Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c113
1 files changed, 107 insertions, 6 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index ad6f9029c564..83583a9c15d9 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);
@@ -911,6 +918,59 @@ static void handle_band(struct wiphy *wiphy,
911 handle_channel(wiphy, initiator, band, i); 918 handle_channel(wiphy, initiator, band, i);
912} 919}
913 920
921static bool reg_request_cell_base(struct regulatory_request *request)
922{
923 if (request->initiator != NL80211_REGDOM_SET_BY_USER)
924 return false;
925 if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
926 return false;
927 return true;
928}
929
930bool reg_last_request_cell_base(void)
931{
932 assert_cfg80211_lock();
933
934 mutex_lock(&reg_mutex);
935 return reg_request_cell_base(last_request);
936 mutex_unlock(&reg_mutex);
937}
938
939#ifdef CONFIG_CFG80211_CERTIFICATION_ONUS
940
941/* Core specific check */
942static int reg_ignore_cell_hint(struct regulatory_request *pending_request)
943{
944 if (!reg_num_devs_support_basehint)
945 return -EOPNOTSUPP;
946
947 if (reg_request_cell_base(last_request)) {
948 if (!regdom_changes(pending_request->alpha2))
949 return -EALREADY;
950 return 0;
951 }
952 return 0;
953}
954
955/* Device specific check */
956static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
957{
958 if (!(wiphy->features & NL80211_FEATURE_CELL_BASE_REG_HINTS))
959 return true;
960 return false;
961}
962#else
963static int reg_ignore_cell_hint(struct regulatory_request *pending_request)
964{
965 return -EOPNOTSUPP;
966}
967static int reg_dev_ignore_cell_hint(struct wiphy *wiphy)
968{
969 return true;
970}
971#endif
972
973
914static bool ignore_reg_update(struct wiphy *wiphy, 974static bool ignore_reg_update(struct wiphy *wiphy,
915 enum nl80211_reg_initiator initiator) 975 enum nl80211_reg_initiator initiator)
916{ 976{
@@ -944,6 +1004,9 @@ static bool ignore_reg_update(struct wiphy *wiphy,
944 return true; 1004 return true;
945 } 1005 }
946 1006
1007 if (reg_request_cell_base(last_request))
1008 return reg_dev_ignore_cell_hint(wiphy);
1009
947 return false; 1010 return false;
948} 1011}
949 1012
@@ -1307,6 +1370,13 @@ static int ignore_request(struct wiphy *wiphy,
1307 return 0; 1370 return 0;
1308 case NL80211_REGDOM_SET_BY_COUNTRY_IE: 1371 case NL80211_REGDOM_SET_BY_COUNTRY_IE:
1309 1372
1373 if (reg_request_cell_base(last_request)) {
1374 /* Trust a Cell base station over the AP's country IE */
1375 if (regdom_changes(pending_request->alpha2))
1376 return -EOPNOTSUPP;
1377 return -EALREADY;
1378 }
1379
1310 last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); 1380 last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
1311 1381
1312 if (unlikely(!is_an_alpha2(pending_request->alpha2))) 1382 if (unlikely(!is_an_alpha2(pending_request->alpha2)))
@@ -1351,6 +1421,12 @@ static int ignore_request(struct wiphy *wiphy,
1351 1421
1352 return REG_INTERSECT; 1422 return REG_INTERSECT;
1353 case NL80211_REGDOM_SET_BY_USER: 1423 case NL80211_REGDOM_SET_BY_USER:
1424 if (reg_request_cell_base(pending_request))
1425 return reg_ignore_cell_hint(pending_request);
1426
1427 if (reg_request_cell_base(last_request))
1428 return -EOPNOTSUPP;
1429
1354 if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) 1430 if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
1355 return REG_INTERSECT; 1431 return REG_INTERSECT;
1356 /* 1432 /*
@@ -1640,7 +1716,8 @@ static int regulatory_hint_core(const char *alpha2)
1640} 1716}
1641 1717
1642/* User hints */ 1718/* User hints */
1643int regulatory_hint_user(const char *alpha2) 1719int regulatory_hint_user(const char *alpha2,
1720 enum nl80211_user_reg_hint_type user_reg_hint_type)
1644{ 1721{
1645 struct regulatory_request *request; 1722 struct regulatory_request *request;
1646 1723
@@ -1654,6 +1731,7 @@ int regulatory_hint_user(const char *alpha2)
1654 request->alpha2[0] = alpha2[0]; 1731 request->alpha2[0] = alpha2[0];
1655 request->alpha2[1] = alpha2[1]; 1732 request->alpha2[1] = alpha2[1];
1656 request->initiator = NL80211_REGDOM_SET_BY_USER; 1733 request->initiator = NL80211_REGDOM_SET_BY_USER;
1734 request->user_reg_hint_type = user_reg_hint_type;
1657 1735
1658 queue_regulatory_request(request); 1736 queue_regulatory_request(request);
1659 1737
@@ -1906,7 +1984,7 @@ static void restore_regulatory_settings(bool reset_user)
1906 * settings, user regulatory settings takes precedence. 1984 * settings, user regulatory settings takes precedence.
1907 */ 1985 */
1908 if (is_an_alpha2(alpha2)) 1986 if (is_an_alpha2(alpha2))
1909 regulatory_hint_user(user_alpha2); 1987 regulatory_hint_user(user_alpha2, NL80211_USER_REG_HINT_USER);
1910 1988
1911 if (list_empty(&tmp_reg_req_list)) 1989 if (list_empty(&tmp_reg_req_list))
1912 return; 1990 return;
@@ -2081,9 +2159,16 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
2081 else { 2159 else {
2082 if (is_unknown_alpha2(rd->alpha2)) 2160 if (is_unknown_alpha2(rd->alpha2))
2083 pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n"); 2161 pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n");
2084 else 2162 else {
2085 pr_info("Regulatory domain changed to country: %c%c\n", 2163 if (reg_request_cell_base(last_request))
2086 rd->alpha2[0], rd->alpha2[1]); 2164 pr_info("Regulatory domain changed "
2165 "to country: %c%c by Cell Station\n",
2166 rd->alpha2[0], rd->alpha2[1]);
2167 else
2168 pr_info("Regulatory domain changed "
2169 "to country: %c%c\n",
2170 rd->alpha2[0], rd->alpha2[1]);
2171 }
2087 } 2172 }
2088 print_dfs_region(rd->dfs_region); 2173 print_dfs_region(rd->dfs_region);
2089 print_rd_rules(rd); 2174 print_rd_rules(rd);
@@ -2293,6 +2378,18 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
2293} 2378}
2294#endif /* CONFIG_HOTPLUG */ 2379#endif /* CONFIG_HOTPLUG */
2295 2380
2381void wiphy_regulatory_register(struct wiphy *wiphy)
2382{
2383 assert_cfg80211_lock();
2384
2385 mutex_lock(&reg_mutex);
2386
2387 if (!reg_dev_ignore_cell_hint(wiphy))
2388 reg_num_devs_support_basehint++;
2389
2390 mutex_unlock(&reg_mutex);
2391}
2392
2296/* Caller must hold cfg80211_mutex */ 2393/* Caller must hold cfg80211_mutex */
2297void reg_device_remove(struct wiphy *wiphy) 2394void reg_device_remove(struct wiphy *wiphy)
2298{ 2395{
@@ -2302,6 +2399,9 @@ void reg_device_remove(struct wiphy *wiphy)
2302 2399
2303 mutex_lock(&reg_mutex); 2400 mutex_lock(&reg_mutex);
2304 2401
2402 if (!reg_dev_ignore_cell_hint(wiphy))
2403 reg_num_devs_support_basehint--;
2404
2305 kfree(wiphy->regd); 2405 kfree(wiphy->regd);
2306 2406
2307 if (last_request) 2407 if (last_request)
@@ -2367,7 +2467,8 @@ int __init regulatory_init(void)
2367 * as a user hint. 2467 * as a user hint.
2368 */ 2468 */
2369 if (!is_world_regdom(ieee80211_regdom)) 2469 if (!is_world_regdom(ieee80211_regdom))
2370 regulatory_hint_user(ieee80211_regdom); 2470 regulatory_hint_user(ieee80211_regdom,
2471 NL80211_USER_REG_HINT_USER);
2371 2472
2372 return 0; 2473 return 0;
2373} 2474}