summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIlan peer <ilan.peer@intel.com>2015-03-04 00:32:06 -0500
committerJohannes Berg <johannes.berg@intel.com>2015-03-06 03:37:47 -0500
commit05050753602626ed4c46271c689929b625f409e7 (patch)
tree8ffc7a282eddb39e7a4bc8081675eba2d92e31d0
parent0c4ddcd214f5bc72713473e8383041ab7a2c6bb7 (diff)
cfg80211: Add API to change the indoor regulatory setting
Previously, the indoor setting configuration assumed that as long as a station interface is connected, the indoor environment setting does not change. However, this assumption is problematic as: - It is possible that a station interface is connected to a mobile AP, e.g., softAP or a P2P GO, where it is possible that both the station and the mobile AP move out of the indoor environment making the indoor setting invalid. In such a case, user space has no way to invalidate the setting. - A station interface disconnection does not necessarily imply that the device is no longer operating in an indoor environment, e.g., it is possible that the station interface is roaming but is still stays indoor. To handle the above, extend the indoor configuration API to allow user space to indicate a change of indoor settings, and allow it to indicate weather it controls the indoor setting, such that: 1. If the user space process explicitly indicates that it is going to control the indoor setting, do not clear the indoor setting internally, unless the socket is released. The user space process should use the NL80211_ATTR_SOCKET_OWNER attribute in the command to state that it is going to control the indoor setting. 2. Reset the indoor setting when restoring the regulatory settings in case it is not owned by a user space process. Based on the above, a user space tool that continuously monitors the indoor settings, i.e., tracking power setting, location etc., can indicate environment changes to the regulatory core. It should be noted that currently user space is the only provided mechanism used to hint to the regulatory core over the indoor/outdoor environment -- while the country IEs do have an environment setting this has been completely ignored by the regulatory core by design for a while now since country IEs typically can contain bogus data. Acked-by: Luis R. Rodriguez <mcgrof@suse.com> Signed-off-by: ArikX Nemtsov <arik@wizery.com> 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.h9
-rw-r--r--net/wireless/nl80211.c19
-rw-r--r--net/wireless/reg.c57
-rw-r--r--net/wireless/reg.h15
4 files changed, 94 insertions, 6 deletions
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 37e7f39441e5..ae16ba9cb1e3 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1697,6 +1697,10 @@ enum nl80211_commands {
1697 * If set during scheduled scan start then the new scan req will be 1697 * If set during scheduled scan start then the new scan req will be
1698 * owned by the netlink socket that created it and the scheduled scan will 1698 * owned by the netlink socket that created it and the scheduled scan will
1699 * be stopped when the socket is closed. 1699 * be stopped when the socket is closed.
1700 * If set during configuration of regulatory indoor operation then the
1701 * regulatory indoor configuration would be owned by the netlink socket
1702 * that configured the indoor setting, and the indoor operation would be
1703 * cleared when the socket is closed.
1700 * 1704 *
1701 * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is 1705 * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
1702 * the TDLS link initiator. 1706 * the TDLS link initiator.
@@ -1752,6 +1756,9 @@ enum nl80211_commands {
1752 * 1756 *
1753 * @NL80211_ATTR_SCHED_SCAN_DELAY: delay before a scheduled scan (or a 1757 * @NL80211_ATTR_SCHED_SCAN_DELAY: delay before a scheduled scan (or a
1754 * WoWLAN net-detect scan) is started, u32 in seconds. 1758 * WoWLAN net-detect scan) is started, u32 in seconds.
1759
1760 * @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device
1761 * is operating in an indoor environment.
1755 * 1762 *
1756 * @NUM_NL80211_ATTR: total number of nl80211_attrs available 1763 * @NUM_NL80211_ATTR: total number of nl80211_attrs available
1757 * @NL80211_ATTR_MAX: highest attribute number currently defined 1764 * @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2120,6 +2127,8 @@ enum nl80211_attrs {
2120 2127
2121 NL80211_ATTR_SCHED_SCAN_DELAY, 2128 NL80211_ATTR_SCHED_SCAN_DELAY,
2122 2129
2130 NL80211_ATTR_REG_INDOOR,
2131
2123 /* add attributes here, update the policy in nl80211.c */ 2132 /* add attributes here, update the policy in nl80211.c */
2124 2133
2125 __NL80211_ATTR_AFTER_LAST, 2134 __NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 07cef3d7653e..b02085301785 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -399,6 +399,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
399 [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG }, 399 [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
400 [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 }, 400 [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
401 [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 }, 401 [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
402 [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
402}; 403};
403 404
404/* policy for the key attributes */ 405/* policy for the key attributes */
@@ -4958,7 +4959,10 @@ static int parse_reg_rule(struct nlattr *tb[],
4958static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) 4959static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
4959{ 4960{
4960 char *data = NULL; 4961 char *data = NULL;
4962 bool is_indoor;
4961 enum nl80211_user_reg_hint_type user_reg_hint_type; 4963 enum nl80211_user_reg_hint_type user_reg_hint_type;
4964 u32 owner_nlportid;
4965
4962 4966
4963 /* 4967 /*
4964 * You should only get this when cfg80211 hasn't yet initialized 4968 * You should only get this when cfg80211 hasn't yet initialized
@@ -4984,7 +4988,15 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
4984 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); 4988 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
4985 return regulatory_hint_user(data, user_reg_hint_type); 4989 return regulatory_hint_user(data, user_reg_hint_type);
4986 case NL80211_USER_REG_HINT_INDOOR: 4990 case NL80211_USER_REG_HINT_INDOOR:
4987 return regulatory_hint_indoor_user(); 4991 if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
4992 owner_nlportid = info->snd_portid;
4993 is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
4994 } else {
4995 owner_nlportid = 0;
4996 is_indoor = true;
4997 }
4998
4999 return regulatory_hint_indoor(is_indoor, owner_nlportid);
4988 default: 5000 default:
4989 return -EINVAL; 5001 return -EINVAL;
4990 } 5002 }
@@ -12810,6 +12822,11 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
12810 12822
12811 rcu_read_unlock(); 12823 rcu_read_unlock();
12812 12824
12825 /*
12826 * It is possible that the user space process that is controlling the
12827 * indoor setting disappeared, so notify the regulatory core.
12828 */
12829 regulatory_netlink_notify(notify->portid);
12813 return NOTIFY_OK; 12830 return NOTIFY_OK;
12814} 12831}
12815 12832
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index c24c8bf3c988..4239dd408137 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -128,9 +128,12 @@ static int reg_num_devs_support_basehint;
128 * State variable indicating if the platform on which the devices 128 * State variable indicating if the platform on which the devices
129 * are attached is operating in an indoor environment. The state variable 129 * are attached is operating in an indoor environment. The state variable
130 * is relevant for all registered devices. 130 * is relevant for all registered devices.
131 * (protected by RTNL)
132 */ 131 */
133static bool reg_is_indoor; 132static bool reg_is_indoor;
133static spinlock_t reg_indoor_lock;
134
135/* Used to track the userspace process controlling the indoor setting */
136static u32 reg_is_indoor_portid;
134 137
135static const struct ieee80211_regdomain *get_cfg80211_regdom(void) 138static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
136{ 139{
@@ -2288,15 +2291,50 @@ int regulatory_hint_user(const char *alpha2,
2288 return 0; 2291 return 0;
2289} 2292}
2290 2293
2291int regulatory_hint_indoor_user(void) 2294int regulatory_hint_indoor(bool is_indoor, u32 portid)
2292{ 2295{
2296 spin_lock(&reg_indoor_lock);
2297
2298 /* It is possible that more than one user space process is trying to
2299 * configure the indoor setting. To handle such cases, clear the indoor
2300 * setting in case that some process does not think that the device
2301 * is operating in an indoor environment. In addition, if a user space
2302 * process indicates that it is controlling the indoor setting, save its
2303 * portid, i.e., make it the owner.
2304 */
2305 reg_is_indoor = is_indoor;
2306 if (reg_is_indoor) {
2307 if (!reg_is_indoor_portid)
2308 reg_is_indoor_portid = portid;
2309 } else {
2310 reg_is_indoor_portid = 0;
2311 }
2293 2312
2313 spin_unlock(&reg_indoor_lock);
2294 2314
2295 reg_is_indoor = true; 2315 if (!is_indoor)
2316 reg_check_channels();
2296 2317
2297 return 0; 2318 return 0;
2298} 2319}
2299 2320
2321void regulatory_netlink_notify(u32 portid)
2322{
2323 spin_lock(&reg_indoor_lock);
2324
2325 if (reg_is_indoor_portid != portid) {
2326 spin_unlock(&reg_indoor_lock);
2327 return;
2328 }
2329
2330 reg_is_indoor = false;
2331 reg_is_indoor_portid = 0;
2332
2333 spin_unlock(&reg_indoor_lock);
2334
2335 reg_check_channels();
2336}
2337
2300/* Driver hints */ 2338/* Driver hints */
2301int regulatory_hint(struct wiphy *wiphy, const char *alpha2) 2339int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
2302{ 2340{
@@ -2464,7 +2502,17 @@ static void restore_regulatory_settings(bool reset_user)
2464 2502
2465 ASSERT_RTNL(); 2503 ASSERT_RTNL();
2466 2504
2467 reg_is_indoor = false; 2505 /*
2506 * Clear the indoor setting in case that it is not controlled by user
2507 * space, as otherwise there is no guarantee that the device is still
2508 * operating in an indoor environment.
2509 */
2510 spin_lock(&reg_indoor_lock);
2511 if (reg_is_indoor && !reg_is_indoor_portid) {
2512 reg_is_indoor = false;
2513 reg_check_channels();
2514 }
2515 spin_unlock(&reg_indoor_lock);
2468 2516
2469 reset_regdomains(true, &world_regdom); 2517 reset_regdomains(true, &world_regdom);
2470 restore_alpha2(alpha2, reset_user); 2518 restore_alpha2(alpha2, reset_user);
@@ -3061,6 +3109,7 @@ int __init regulatory_init(void)
3061 3109
3062 spin_lock_init(&reg_requests_lock); 3110 spin_lock_init(&reg_requests_lock);
3063 spin_lock_init(&reg_pending_beacons_lock); 3111 spin_lock_init(&reg_pending_beacons_lock);
3112 spin_lock_init(&reg_indoor_lock);
3064 3113
3065 reg_regdb_size_check(); 3114 reg_regdb_size_check();
3066 3115
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index 4b45d6e61d24..a2c4e16459da 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -25,7 +25,20 @@ 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/**
30 * regulatory_hint_indoor - hint operation in indoor env. or not
31 * @is_indoor: if true indicates that user space thinks that the
32 * device is operating in an indoor environment.
33 * @portid: the netlink port ID on which the hint was given.
34 */
35int regulatory_hint_indoor(bool is_indoor, u32 portid);
36
37/**
38 * regulatory_netlink_notify - notify on released netlink socket
39 * @portid: the netlink socket port ID
40 */
41void regulatory_netlink_notify(u32 portid);
29 42
30void wiphy_regulatory_register(struct wiphy *wiphy); 43void wiphy_regulatory_register(struct wiphy *wiphy);
31void wiphy_regulatory_deregister(struct wiphy *wiphy); 44void wiphy_regulatory_deregister(struct wiphy *wiphy);