aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIlan Peer <ilan.peer@intel.com>2014-02-25 09:26:00 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-04-09 04:55:35 -0400
commit52616f2b446eaad8eb2cd78bbd052f0066069757 (patch)
treee410fdc5238dc4d1aec48035ecef7ff51f579730
parent174e0cd28af0fe3c6c634c3e4d9e042c683bd7f7 (diff)
cfg80211: Add an option to hint indoor operation
Add the option to hint the wireless core that it is operating in an indoor environment. Signed-off-by: Ilan Peer <ilan.peer@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/uapi/linux/nl80211.h3
-rw-r--r--net/wireless/nl80211.c18
-rw-r--r--net/wireless/reg.c58
-rw-r--r--net/wireless/reg.h1
4 files changed, 68 insertions, 12 deletions
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index ac5b2d25f0fc..513bfd7b2e5f 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2602,10 +2602,13 @@ enum nl80211_dfs_regions {
2602 * present has been registered with the wireless core that 2602 * present has been registered with the wireless core that
2603 * has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a 2603 * has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a
2604 * supported feature. 2604 * supported feature.
2605 * @NL80211_USER_REG_HINT_INDOOR: a user sent an hint indicating that the
2606 * platform is operating in an indoor environment.
2605 */ 2607 */
2606enum nl80211_user_reg_hint_type { 2608enum nl80211_user_reg_hint_type {
2607 NL80211_USER_REG_HINT_USER = 0, 2609 NL80211_USER_REG_HINT_USER = 0,
2608 NL80211_USER_REG_HINT_CELL_BASE = 1, 2610 NL80211_USER_REG_HINT_CELL_BASE = 1,
2611 NL80211_USER_REG_HINT_INDOOR = 2,
2609}; 2612};
2610 2613
2611/** 2614/**
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b8d81e41b0f7..85bc830fd7e3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4677,7 +4677,6 @@ static int parse_reg_rule(struct nlattr *tb[],
4677 4677
4678static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) 4678static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
4679{ 4679{
4680 int r;
4681 char *data = NULL; 4680 char *data = NULL;
4682 enum nl80211_user_reg_hint_type user_reg_hint_type; 4681 enum nl80211_user_reg_hint_type user_reg_hint_type;
4683 4682
@@ -4690,11 +4689,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
4690 if (unlikely(!rcu_access_pointer(cfg80211_regdomain))) 4689 if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
4691 return -EINPROGRESS; 4690 return -EINPROGRESS;
4692 4691
4693 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
4694 return -EINVAL;
4695
4696 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
4697
4698 if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]) 4692 if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
4699 user_reg_hint_type = 4693 user_reg_hint_type =
4700 nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]); 4694 nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
@@ -4704,14 +4698,16 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
4704 switch (user_reg_hint_type) { 4698 switch (user_reg_hint_type) {
4705 case NL80211_USER_REG_HINT_USER: 4699 case NL80211_USER_REG_HINT_USER:
4706 case NL80211_USER_REG_HINT_CELL_BASE: 4700 case NL80211_USER_REG_HINT_CELL_BASE:
4707 break; 4701 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
4702 return -EINVAL;
4703
4704 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
4705 return regulatory_hint_user(data, user_reg_hint_type);
4706 case NL80211_USER_REG_HINT_INDOOR:
4707 return regulatory_hint_indoor_user();
4708 default: 4708 default:
4709 return -EINVAL; 4709 return -EINVAL;
4710 } 4710 }
4711
4712 r = regulatory_hint_user(data, user_reg_hint_type);
4713
4714 return r;
4715} 4711}
4716 4712
4717static int nl80211_get_mesh_config(struct sk_buff *skb, 4713static int nl80211_get_mesh_config(struct sk_buff *skb,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 58f48b8f42ae..55d68c31ad72 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -65,11 +65,26 @@
65#define REG_DBG_PRINT(args...) 65#define REG_DBG_PRINT(args...)
66#endif 66#endif
67 67
68/**
69 * enum reg_request_treatment - regulatory request treatment
70 *
71 * @REG_REQ_OK: continue processing the regulatory request
72 * @REG_REQ_IGNORE: ignore the regulatory request
73 * @REG_REQ_INTERSECT: the regulatory domain resulting from this request should
74 * be intersected with the current one.
75 * @REG_REQ_ALREADY_SET: the regulatory request will not change the current
76 * regulatory settings, and no further processing is required.
77 * @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no
78 * further processing is required, i.e., not need to update last_request
79 * etc. This should be used for user hints that do not provide an alpha2
80 * but some other type of regulatory hint, i.e., indoor operation.
81 */
68enum reg_request_treatment { 82enum reg_request_treatment {
69 REG_REQ_OK, 83 REG_REQ_OK,
70 REG_REQ_IGNORE, 84 REG_REQ_IGNORE,
71 REG_REQ_INTERSECT, 85 REG_REQ_INTERSECT,
72 REG_REQ_ALREADY_SET, 86 REG_REQ_ALREADY_SET,
87 REG_REQ_USER_HINT_HANDLED,
73}; 88};
74 89
75static struct regulatory_request core_request_world = { 90static struct regulatory_request core_request_world = {
@@ -106,6 +121,14 @@ const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
106 */ 121 */
107static int reg_num_devs_support_basehint; 122static int reg_num_devs_support_basehint;
108 123
124/*
125 * State variable indicating if the platform on which the devices
126 * are attached is operating in an indoor environment. The state variable
127 * is relevant for all registered devices.
128 * (protected by RTNL)
129 */
130static bool reg_is_indoor;
131
109static const struct ieee80211_regdomain *get_cfg80211_regdom(void) 132static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
110{ 133{
111 return rtnl_dereference(cfg80211_regdomain); 134 return rtnl_dereference(cfg80211_regdomain);
@@ -1128,6 +1151,13 @@ static bool reg_request_cell_base(struct regulatory_request *request)
1128 return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE; 1151 return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE;
1129} 1152}
1130 1153
1154static bool reg_request_indoor(struct regulatory_request *request)
1155{
1156 if (request->initiator != NL80211_REGDOM_SET_BY_USER)
1157 return false;
1158 return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR;
1159}
1160
1131bool reg_last_request_cell_base(void) 1161bool reg_last_request_cell_base(void)
1132{ 1162{
1133 return reg_request_cell_base(get_last_request()); 1163 return reg_request_cell_base(get_last_request());
@@ -1570,6 +1600,11 @@ __reg_process_hint_user(struct regulatory_request *user_request)
1570{ 1600{
1571 struct regulatory_request *lr = get_last_request(); 1601 struct regulatory_request *lr = get_last_request();
1572 1602
1603 if (reg_request_indoor(user_request)) {
1604 reg_is_indoor = true;
1605 return REG_REQ_USER_HINT_HANDLED;
1606 }
1607
1573 if (reg_request_cell_base(user_request)) 1608 if (reg_request_cell_base(user_request))
1574 return reg_ignore_cell_hint(user_request); 1609 return reg_ignore_cell_hint(user_request);
1575 1610
@@ -1617,7 +1652,8 @@ reg_process_hint_user(struct regulatory_request *user_request)
1617 1652
1618 treatment = __reg_process_hint_user(user_request); 1653 treatment = __reg_process_hint_user(user_request);
1619 if (treatment == REG_REQ_IGNORE || 1654 if (treatment == REG_REQ_IGNORE ||
1620 treatment == REG_REQ_ALREADY_SET) { 1655 treatment == REG_REQ_ALREADY_SET ||
1656 treatment == REG_REQ_USER_HINT_HANDLED) {
1621 kfree(user_request); 1657 kfree(user_request);
1622 return treatment; 1658 return treatment;
1623 } 1659 }
@@ -1678,6 +1714,7 @@ reg_process_hint_driver(struct wiphy *wiphy,
1678 case REG_REQ_OK: 1714 case REG_REQ_OK:
1679 break; 1715 break;
1680 case REG_REQ_IGNORE: 1716 case REG_REQ_IGNORE:
1717 case REG_REQ_USER_HINT_HANDLED:
1681 kfree(driver_request); 1718 kfree(driver_request);
1682 return treatment; 1719 return treatment;
1683 case REG_REQ_INTERSECT: 1720 case REG_REQ_INTERSECT:
@@ -1777,6 +1814,7 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
1777 case REG_REQ_OK: 1814 case REG_REQ_OK:
1778 break; 1815 break;
1779 case REG_REQ_IGNORE: 1816 case REG_REQ_IGNORE:
1817 case REG_REQ_USER_HINT_HANDLED:
1780 /* fall through */ 1818 /* fall through */
1781 case REG_REQ_ALREADY_SET: 1819 case REG_REQ_ALREADY_SET:
1782 kfree(country_ie_request); 1820 kfree(country_ie_request);
@@ -1969,6 +2007,22 @@ int regulatory_hint_user(const char *alpha2,
1969 return 0; 2007 return 0;
1970} 2008}
1971 2009
2010int regulatory_hint_indoor_user(void)
2011{
2012 struct regulatory_request *request;
2013
2014 request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
2015 if (!request)
2016 return -ENOMEM;
2017
2018 request->wiphy_idx = WIPHY_IDX_INVALID;
2019 request->initiator = NL80211_REGDOM_SET_BY_USER;
2020 request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR;
2021 queue_regulatory_request(request);
2022
2023 return 0;
2024}
2025
1972/* Driver hints */ 2026/* Driver hints */
1973int regulatory_hint(struct wiphy *wiphy, const char *alpha2) 2027int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
1974{ 2028{
@@ -2136,6 +2190,8 @@ static void restore_regulatory_settings(bool reset_user)
2136 2190
2137 ASSERT_RTNL(); 2191 ASSERT_RTNL();
2138 2192
2193 reg_is_indoor = false;
2194
2139 reset_regdomains(true, &world_regdom); 2195 reset_regdomains(true, &world_regdom);
2140 restore_alpha2(alpha2, reset_user); 2196 restore_alpha2(alpha2, reset_user);
2141 2197
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index 334a53af0fc8..2a3842828f6d 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -25,6 +25,7 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy);
25 25
26int regulatory_hint_user(const char *alpha2, 26int regulatory_hint_user(const char *alpha2,
27 enum nl80211_user_reg_hint_type user_reg_hint_type); 27 enum nl80211_user_reg_hint_type user_reg_hint_type);
28int regulatory_hint_indoor_user(void);
28 29
29void wiphy_regulatory_register(struct wiphy *wiphy); 30void wiphy_regulatory_register(struct wiphy *wiphy);
30void wiphy_regulatory_deregister(struct wiphy *wiphy); 31void wiphy_regulatory_deregister(struct wiphy *wiphy);