As the operating environment of a device can change, add
API for user space to indicate a change of indoor settings.
In addition modify the handling of the indoor processing as
follows:
1. Directly update the indoor setting without wrapping it as a
regulatory request.
2. 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.
3. Reset the indoor setting when restoring the regulatory settings in
case it is not owned by a user space process.
Signed-off-by: Ilan Peer <[email protected]>
Signed-off-by: ArikX Nemtsov <[email protected]>
---
include/uapi/linux/nl80211.h | 9 +++++
net/wireless/nl80211.c | 15 +++++++-
net/wireless/reg.c | 90 +++++++++++++++++++++++++++-----------------
net/wireless/reg.h | 15 +++++++-
4 files changed, 93 insertions(+), 36 deletions(-)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 68b294e..98fc77f 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1684,6 +1684,10 @@ enum nl80211_commands {
* If set during scheduled scan start then the new scan req will be
* owned by the netlink socket that created it and the scheduled scan will
* be stopped when the socket is closed.
+ * If set during configuration of regulatory indoor operation then the
+ * regulatory indoor configuration would be owned by the netlink socket
+ * that configured the indoor setting, and the indoor operation would be
+ * cleared when the socket is closed.
*
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
* the TDLS link initiator.
@@ -1739,6 +1743,9 @@ enum nl80211_commands {
*
* @NL80211_ATTR_SCHED_SCAN_DELAY: delay before a scheduled scan (or a
* WoWLAN net-detect scan) is started, u32 in seconds.
+
+ * @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device
+ * is operating in an indoor environment.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2107,6 +2114,8 @@ enum nl80211_attrs {
NL80211_ATTR_SCHED_SCAN_DELAY,
+ NL80211_ATTR_REG_INDOOR,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 454d7a0..3f6b395 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] = {
[NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
[NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
[NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
+ [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
};
/* policy for the key attributes */
@@ -4955,7 +4956,10 @@ static int parse_reg_rule(struct nlattr *tb[],
static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
{
char *data = NULL;
+ bool is_indoor;
enum nl80211_user_reg_hint_type user_reg_hint_type;
+ u32 owner_nlportid = 0;
+
/*
* You should only get this when cfg80211 hasn't yet initialized
@@ -4981,7 +4985,11 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
return regulatory_hint_user(data, user_reg_hint_type);
case NL80211_USER_REG_HINT_INDOOR:
- return regulatory_hint_indoor_user();
+ is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
+ if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
+ owner_nlportid = info->snd_portid;
+
+ return regulatory_hint_indoor(is_indoor, owner_nlportid);
default:
return -EINVAL;
}
@@ -12759,6 +12767,11 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
rcu_read_unlock();
+ /*
+ * It is possible that the user space process that is controlling the
+ * indoor setting disappeared, so notify the regulatory core.
+ */
+ regulatory_netlink_notify(notify->portid);
return NOTIFY_OK;
}
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 886cc7c..771319e 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -82,17 +82,12 @@
* be intersected with the current one.
* @REG_REQ_ALREADY_SET: the regulatory request will not change the current
* regulatory settings, and no further processing is required.
- * @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no
- * further processing is required, i.e., not need to update last_request
- * etc. This should be used for user hints that do not provide an alpha2
- * but some other type of regulatory hint, i.e., indoor operation.
*/
enum reg_request_treatment {
REG_REQ_OK,
REG_REQ_IGNORE,
REG_REQ_INTERSECT,
REG_REQ_ALREADY_SET,
- REG_REQ_USER_HINT_HANDLED,
};
static struct regulatory_request core_request_world = {
@@ -133,9 +128,12 @@ static int reg_num_devs_support_basehint;
* State variable indicating if the platform on which the devices
* are attached is operating in an indoor environment. The state variable
* is relevant for all registered devices.
- * (protected by RTNL)
*/
static bool reg_is_indoor;
+static spinlock_t reg_indoor_lock;
+
+/* Used to track the userspace process controlling the indoor setting */
+static u32 reg_is_indoor_portid;
static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
{
@@ -1248,13 +1246,6 @@ static bool reg_request_cell_base(struct regulatory_request *request)
return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE;
}
-static bool reg_request_indoor(struct regulatory_request *request)
-{
- if (request->initiator != NL80211_REGDOM_SET_BY_USER)
- return false;
- return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR;
-}
-
bool reg_last_request_cell_base(void)
{
return reg_request_cell_base(get_last_request());
@@ -1821,11 +1812,6 @@ __reg_process_hint_user(struct regulatory_request *user_request)
{
struct regulatory_request *lr = get_last_request();
- if (reg_request_indoor(user_request)) {
- reg_is_indoor = true;
- return REG_REQ_USER_HINT_HANDLED;
- }
-
if (reg_request_cell_base(user_request))
return reg_ignore_cell_hint(user_request);
@@ -1873,8 +1859,7 @@ reg_process_hint_user(struct regulatory_request *user_request)
treatment = __reg_process_hint_user(user_request);
if (treatment == REG_REQ_IGNORE ||
- treatment == REG_REQ_ALREADY_SET ||
- treatment == REG_REQ_USER_HINT_HANDLED) {
+ treatment == REG_REQ_ALREADY_SET) {
reg_free_request(user_request);
return treatment;
}
@@ -1935,7 +1920,6 @@ reg_process_hint_driver(struct wiphy *wiphy,
case REG_REQ_OK:
break;
case REG_REQ_IGNORE:
- case REG_REQ_USER_HINT_HANDLED:
reg_free_request(driver_request);
return treatment;
case REG_REQ_INTERSECT:
@@ -2035,7 +2019,6 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
case REG_REQ_OK:
break;
case REG_REQ_IGNORE:
- case REG_REQ_USER_HINT_HANDLED:
/* fall through */
case REG_REQ_ALREADY_SET:
reg_free_request(country_ie_request);
@@ -2074,8 +2057,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
case NL80211_REGDOM_SET_BY_USER:
treatment = reg_process_hint_user(reg_request);
if (treatment == REG_REQ_IGNORE ||
- treatment == REG_REQ_ALREADY_SET ||
- treatment == REG_REQ_USER_HINT_HANDLED)
+ treatment == REG_REQ_ALREADY_SET)
return;
queue_delayed_work(system_power_efficient_wq,
®_timeout, msecs_to_jiffies(3142));
@@ -2297,22 +2279,51 @@ int regulatory_hint_user(const char *alpha2,
return 0;
}
-int regulatory_hint_indoor_user(void)
+int regulatory_hint_indoor(bool is_indoor, u32 portid)
{
- struct regulatory_request *request;
+ spin_lock(®_indoor_lock);
- request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
- if (!request)
- return -ENOMEM;
+ /*
+ * Process only if there is a real change, so the original port ID is
+ * saved (to handle cases that several processes try to change the
+ * indoor setting).
+ */
+ if (reg_is_indoor == is_indoor) {
+ spin_unlock(®_indoor_lock);
+ return 0;
+ }
- request->wiphy_idx = WIPHY_IDX_INVALID;
- request->initiator = NL80211_REGDOM_SET_BY_USER;
- request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR;
- queue_regulatory_request(request);
+ reg_is_indoor = is_indoor;
+ if (reg_is_indoor)
+ reg_is_indoor_portid = portid;
+ else
+ reg_is_indoor_portid = 0;
+
+ spin_unlock(®_indoor_lock);
+
+ if (!is_indoor)
+ reg_check_channels();
return 0;
}
+void regulatory_netlink_notify(u32 portid)
+{
+ spin_lock(®_indoor_lock);
+
+ if (reg_is_indoor_portid != portid) {
+ spin_unlock(®_indoor_lock);
+ return;
+ }
+
+ reg_is_indoor = false;
+ reg_is_indoor_portid = 0;
+
+ spin_unlock(®_indoor_lock);
+
+ reg_check_channels();
+}
+
/* Driver hints */
int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
{
@@ -2480,7 +2491,17 @@ static void restore_regulatory_settings(bool reset_user)
ASSERT_RTNL();
- reg_is_indoor = false;
+ /*
+ * Clear the indoor setting in case that it is not controlled by user
+ * space, as otherwise there is no guarantee that the device is still
+ * operating in an indoor environment.
+ */
+ spin_lock(®_indoor_lock);
+ if (reg_is_indoor && !reg_is_indoor_portid) {
+ reg_is_indoor = false;
+ reg_check_channels();
+ }
+ spin_unlock(®_indoor_lock);
reset_regdomains(true, &world_regdom);
restore_alpha2(alpha2, reset_user);
@@ -3077,6 +3098,7 @@ int __init regulatory_init(void)
spin_lock_init(®_requests_lock);
spin_lock_init(®_pending_beacons_lock);
+ spin_lock_init(®_indoor_lock);
reg_regdb_size_check();
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index 4b45d6e..a2c4e16 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);
int regulatory_hint_user(const char *alpha2,
enum nl80211_user_reg_hint_type user_reg_hint_type);
-int regulatory_hint_indoor_user(void);
+
+/**
+ * regulatory_hint_indoor - hint operation in indoor env. or not
+ * @is_indoor: if true indicates that user space thinks that the
+ * device is operating in an indoor environment.
+ * @portid: the netlink port ID on which the hint was given.
+ */
+int regulatory_hint_indoor(bool is_indoor, u32 portid);
+
+/**
+ * regulatory_netlink_notify - notify on released netlink socket
+ * @portid: the netlink socket port ID
+ */
+void regulatory_netlink_notify(u32 portid);
void wiphy_regulatory_register(struct wiphy *wiphy);
void wiphy_regulatory_deregister(struct wiphy *wiphy);
--
1.8.3.2
> -----Original Message-----
> From: [email protected] [mailto:linux-wireless-
> [email protected]] On Behalf Of Luis R. Rodriguez
> Sent: Thursday, February 26, 2015 04:08
> To: Peer, Ilan
> Cc: Jouni Malinen; [email protected]; ArikX Nemtsov
> Subject: Re: [PATCH v6 1/2] cfg80211: Add API to change the indoor
> regulatory setting
>
> On Wed, Feb 25, 2015 at 02:30:40PM +0000, Peer, Ilan wrote:
> > Hi Luis,
> >
> > > -----Original Message-----
> > > From: Luis R. Rodriguez [mailto:[email protected]]
> > > Sent: Tuesday, February 24, 2015 02:03
> > > To: Peer, Ilan; Jouni Malinen
> > > Cc: [email protected]; ArikX Nemtsov
> > > Subject: Re: [PATCH v6 1/2] cfg80211: Add API to change the indoor
> > > regulatory setting
> > >
> > > On Sat, Feb 21, 2015 at 10:57:10PM -0500, Ilan Peer wrote:
> > > > 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.
> > >
> > > At the protocol level should we consider the need for a dynamic
> > > environment change? Until then a change of environment likely should
> > > implicate an AP disconnect, which is what Linux does. With your
> > > changes in place we could do something even more graceful should the
> protocol allow for it.
> > >
> >
> > Not sure I follow ...
>
> OK right now we should disconnect if there are some regulatory params that
> do not agree. This event will also ony happen *rarely*. Even though this
> happens rarely I can find use for forcing this to happen in a not so rare case to
> help optimize RF spectrum use dynamically, if the protocol had a way to
> communicate a desired change in environment this could be reused for a
> dynaic RF spectrum change in environment.
>
I think that RF spectrum changes are addressed in some extend in 11h, 11k and 11v etc. So maybe
What you are looking for is already there.
> > > For instance if the regulatory parameters for a country are the same
> > > for indoor and outdoro a change in environment should not require a
> disconnect.
> > >
> >
> > So you are suggesting to extend the mechanism to also indicate if a
> > teardown of active interfaces is needed or not? And if so, not sure
> > that this should be done by the kernel.
>
> If the AP *knew* a change in environment (now forget indoor/outdoor as that
> is rare today) was not disruptive this could be information that the STAs can
> get to use to evaluate and make a better decision as to whether or not it did
> need to tear down or not.
>
> > > If the change was from a more restrictive environment to a more
> > > liberal set of regulatory settings it could mean increasing TX power
> > > of the AP changing to a channel which perhaps was not allowed before.
> > >
> >
> > I think that such a flow needs to be handled in user-space by hostapd,
> > which can leverage the proper mechanisms to do the change, e.g., eCSA.
>
> Right but that's the AP, how would the STAs get that information? This is why I
> mentioned the idea of a possible protocol enhancement to let the AP inform
> STAs of an environmental change. The AP *could* feed more than just the
> boring parameters we're used to. Its OK this is just an idea, ignore it.
>
I think that APs (at least what the spec allows) have mechanisms to inform the client
on some change such as channel switch, operational bandwidth (11ac), tx power control etc.
> > > If the change was from a less restrictive environment to a more
> > > restrictive environment the AP might want to change channels for
> > > instance or reduce TX power.
> > >
> >
> > Same as above. For example, hostapd handles DFS related channel
> > changes in user space. We also added flows to handle channel switch etc. in
> wpa_supplicant ...
> > and I need to resubmit them to hostap.
>
> OK..
>
> > > While change in indoor/outdoor might be something silly to consider
> > > given the likelihood of it being a common thing to happen that you
> > > change an AP from indoor / outdoor regularly I'd consider instead
> > > the possibility to reuse such a dynamic environment change
> > > notification for purposes of dynamic environmental adjustments of
> > > BSSes. Typically BSSes settings are static but RF environments
> > > change regularly so its silly to expect a BSS and its initial
> > > Automatic Channel Selection algorithm to be corrrect during the lifetime
> of a BSS.
> > >
> > > > - 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.
> > >
> > > Sure.
> > >
> > > You also fail to explain how we currently provide the indoor thing
> > > to the kernel, I think its worth providing that in the commit log
> > > and also explaining how we don't use the country IE environment thing at
> all.
> > >
> >
> > I explained some of the use cases in previous patches, e.g., AC power,
> > device type etc. I can add this, but I do not understand how country
> > IE is related here.
>
> Mention it and the country IE is important given its the other place folks
> expect it to be deduced from -- and we don't use it at all. Without that
> information folks can assume we do unless they are familiar with the code.
> It provides useful context for your change, even for me!
>
Done.
Thanks,
Ilan.
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.
While at it directly update the indoor setting without wrapping it as
a regulatory request, to simplify the processing.
Signed-off-by: Ilan Peer <[email protected]>
Signed-off-by: ArikX Nemtsov <[email protected]>
---
include/uapi/linux/nl80211.h | 9 +++++
net/wireless/nl80211.c | 15 +++++++-
net/wireless/reg.c | 90 +++++++++++++++++++++++++++-----------------
net/wireless/reg.h | 15 +++++++-
4 files changed, 93 insertions(+), 36 deletions(-)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 68b294e..98fc77f 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1684,6 +1684,10 @@ enum nl80211_commands {
* If set during scheduled scan start then the new scan req will be
* owned by the netlink socket that created it and the scheduled scan will
* be stopped when the socket is closed.
+ * If set during configuration of regulatory indoor operation then the
+ * regulatory indoor configuration would be owned by the netlink socket
+ * that configured the indoor setting, and the indoor operation would be
+ * cleared when the socket is closed.
*
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
* the TDLS link initiator.
@@ -1739,6 +1743,9 @@ enum nl80211_commands {
*
* @NL80211_ATTR_SCHED_SCAN_DELAY: delay before a scheduled scan (or a
* WoWLAN net-detect scan) is started, u32 in seconds.
+
+ * @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device
+ * is operating in an indoor environment.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2107,6 +2114,8 @@ enum nl80211_attrs {
NL80211_ATTR_SCHED_SCAN_DELAY,
+ NL80211_ATTR_REG_INDOOR,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 454d7a0..3f6b395 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] = {
[NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
[NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
[NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
+ [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
};
/* policy for the key attributes */
@@ -4955,7 +4956,10 @@ static int parse_reg_rule(struct nlattr *tb[],
static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
{
char *data = NULL;
+ bool is_indoor;
enum nl80211_user_reg_hint_type user_reg_hint_type;
+ u32 owner_nlportid = 0;
+
/*
* You should only get this when cfg80211 hasn't yet initialized
@@ -4981,7 +4985,11 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
return regulatory_hint_user(data, user_reg_hint_type);
case NL80211_USER_REG_HINT_INDOOR:
- return regulatory_hint_indoor_user();
+ is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
+ if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
+ owner_nlportid = info->snd_portid;
+
+ return regulatory_hint_indoor(is_indoor, owner_nlportid);
default:
return -EINVAL;
}
@@ -12759,6 +12767,11 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
rcu_read_unlock();
+ /*
+ * It is possible that the user space process that is controlling the
+ * indoor setting disappeared, so notify the regulatory core.
+ */
+ regulatory_netlink_notify(notify->portid);
return NOTIFY_OK;
}
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 886cc7c..771319e 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -82,17 +82,12 @@
* be intersected with the current one.
* @REG_REQ_ALREADY_SET: the regulatory request will not change the current
* regulatory settings, and no further processing is required.
- * @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no
- * further processing is required, i.e., not need to update last_request
- * etc. This should be used for user hints that do not provide an alpha2
- * but some other type of regulatory hint, i.e., indoor operation.
*/
enum reg_request_treatment {
REG_REQ_OK,
REG_REQ_IGNORE,
REG_REQ_INTERSECT,
REG_REQ_ALREADY_SET,
- REG_REQ_USER_HINT_HANDLED,
};
static struct regulatory_request core_request_world = {
@@ -133,9 +128,12 @@ static int reg_num_devs_support_basehint;
* State variable indicating if the platform on which the devices
* are attached is operating in an indoor environment. The state variable
* is relevant for all registered devices.
- * (protected by RTNL)
*/
static bool reg_is_indoor;
+static spinlock_t reg_indoor_lock;
+
+/* Used to track the userspace process controlling the indoor setting */
+static u32 reg_is_indoor_portid;
static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
{
@@ -1248,13 +1246,6 @@ static bool reg_request_cell_base(struct regulatory_request *request)
return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE;
}
-static bool reg_request_indoor(struct regulatory_request *request)
-{
- if (request->initiator != NL80211_REGDOM_SET_BY_USER)
- return false;
- return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR;
-}
-
bool reg_last_request_cell_base(void)
{
return reg_request_cell_base(get_last_request());
@@ -1821,11 +1812,6 @@ __reg_process_hint_user(struct regulatory_request *user_request)
{
struct regulatory_request *lr = get_last_request();
- if (reg_request_indoor(user_request)) {
- reg_is_indoor = true;
- return REG_REQ_USER_HINT_HANDLED;
- }
-
if (reg_request_cell_base(user_request))
return reg_ignore_cell_hint(user_request);
@@ -1873,8 +1859,7 @@ reg_process_hint_user(struct regulatory_request *user_request)
treatment = __reg_process_hint_user(user_request);
if (treatment == REG_REQ_IGNORE ||
- treatment == REG_REQ_ALREADY_SET ||
- treatment == REG_REQ_USER_HINT_HANDLED) {
+ treatment == REG_REQ_ALREADY_SET) {
reg_free_request(user_request);
return treatment;
}
@@ -1935,7 +1920,6 @@ reg_process_hint_driver(struct wiphy *wiphy,
case REG_REQ_OK:
break;
case REG_REQ_IGNORE:
- case REG_REQ_USER_HINT_HANDLED:
reg_free_request(driver_request);
return treatment;
case REG_REQ_INTERSECT:
@@ -2035,7 +2019,6 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
case REG_REQ_OK:
break;
case REG_REQ_IGNORE:
- case REG_REQ_USER_HINT_HANDLED:
/* fall through */
case REG_REQ_ALREADY_SET:
reg_free_request(country_ie_request);
@@ -2074,8 +2057,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
case NL80211_REGDOM_SET_BY_USER:
treatment = reg_process_hint_user(reg_request);
if (treatment == REG_REQ_IGNORE ||
- treatment == REG_REQ_ALREADY_SET ||
- treatment == REG_REQ_USER_HINT_HANDLED)
+ treatment == REG_REQ_ALREADY_SET)
return;
queue_delayed_work(system_power_efficient_wq,
®_timeout, msecs_to_jiffies(3142));
@@ -2297,22 +2279,51 @@ int regulatory_hint_user(const char *alpha2,
return 0;
}
-int regulatory_hint_indoor_user(void)
+int regulatory_hint_indoor(bool is_indoor, u32 portid)
{
- struct regulatory_request *request;
+ spin_lock(®_indoor_lock);
- request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
- if (!request)
- return -ENOMEM;
+ /*
+ * Process only if there is a real change, so the original port ID is
+ * saved (to handle cases that several processes try to change the
+ * indoor setting).
+ */
+ if (reg_is_indoor == is_indoor) {
+ spin_unlock(®_indoor_lock);
+ return 0;
+ }
- request->wiphy_idx = WIPHY_IDX_INVALID;
- request->initiator = NL80211_REGDOM_SET_BY_USER;
- request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR;
- queue_regulatory_request(request);
+ reg_is_indoor = is_indoor;
+ if (reg_is_indoor)
+ reg_is_indoor_portid = portid;
+ else
+ reg_is_indoor_portid = 0;
+
+ spin_unlock(®_indoor_lock);
+
+ if (!is_indoor)
+ reg_check_channels();
return 0;
}
+void regulatory_netlink_notify(u32 portid)
+{
+ spin_lock(®_indoor_lock);
+
+ if (reg_is_indoor_portid != portid) {
+ spin_unlock(®_indoor_lock);
+ return;
+ }
+
+ reg_is_indoor = false;
+ reg_is_indoor_portid = 0;
+
+ spin_unlock(®_indoor_lock);
+
+ reg_check_channels();
+}
+
/* Driver hints */
int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
{
@@ -2480,7 +2491,17 @@ static void restore_regulatory_settings(bool reset_user)
ASSERT_RTNL();
- reg_is_indoor = false;
+ /*
+ * Clear the indoor setting in case that it is not controlled by user
+ * space, as otherwise there is no guarantee that the device is still
+ * operating in an indoor environment.
+ */
+ spin_lock(®_indoor_lock);
+ if (reg_is_indoor && !reg_is_indoor_portid) {
+ reg_is_indoor = false;
+ reg_check_channels();
+ }
+ spin_unlock(®_indoor_lock);
reset_regdomains(true, &world_regdom);
restore_alpha2(alpha2, reset_user);
@@ -3077,6 +3098,7 @@ int __init regulatory_init(void)
spin_lock_init(®_requests_lock);
spin_lock_init(®_pending_beacons_lock);
+ spin_lock_init(®_indoor_lock);
reg_regdb_size_check();
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index 4b45d6e..a2c4e16 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);
int regulatory_hint_user(const char *alpha2,
enum nl80211_user_reg_hint_type user_reg_hint_type);
-int regulatory_hint_indoor_user(void);
+
+/**
+ * regulatory_hint_indoor - hint operation in indoor env. or not
+ * @is_indoor: if true indicates that user space thinks that the
+ * device is operating in an indoor environment.
+ * @portid: the netlink port ID on which the hint was given.
+ */
+int regulatory_hint_indoor(bool is_indoor, u32 portid);
+
+/**
+ * regulatory_netlink_notify - notify on released netlink socket
+ * @portid: the netlink socket port ID
+ */
+void regulatory_netlink_notify(u32 portid);
void wiphy_regulatory_register(struct wiphy *wiphy);
void wiphy_regulatory_deregister(struct wiphy *wiphy);
--
1.8.3.2
On Sat, Feb 21, 2015 at 10:57:10PM -0500, Ilan Peer wrote:
> 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.
At the protocol level should we consider the need for a dynamic environment
change? Until then a change of environment likely should implicate an AP
disconnect, which is what Linux does. With your changes in place we could
do something even more graceful should the protocol allow for it.
For instance if the regulatory parameters for a country are the same for
indoor and outdoro a change in environment should not require a disconnect.
If the change was from a more restrictive environment to a more liberal
set of regulatory settings it could mean increasing TX power of the AP
changing to a channel which perhaps was not allowed before.
If the change was from a less restrictive environment to a more restrictive
environment the AP might want to change channels for instance or reduce
TX power.
While change in indoor/outdoor might be something silly to consider given
the likelihood of it being a common thing to happen that you change an
AP from indoor / outdoor regularly I'd consider instead the possibility to
reuse such a dynamic environment change notification for purposes of dynamic
environmental adjustments of BSSes. Typically BSSes settings are static but RF
environments change regularly so its silly to expect a BSS and its initial
Automatic Channel Selection algorithm to be corrrect during the lifetime of a
BSS.
> - 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.
Sure.
You also fail to explain how we currently provide the indoor
thing to the kernel, I think its worth providing that in the commit
log and also explaining how we don't use the country IE environment
thing at all.
> 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.
>
> While at it directly update the indoor setting without wrapping it as
> a regulatory request, to simplify the processing.
Please wrap that specific change into its own separate commit, it
will make it easier to review the changes and also make this change
atomic.
Luis
Timeout was scheduled only in case CRDA was called due to user hints,
but was not scheduled for other cases. This can result in regulatory
hint processing getting stuck in case that there is no CRDA configured.
Change this by scheduling a timeout every time CRDA is called. In
addition, in restore_regulatory_settings() all pending requests are
restored (and not only the user ones).
Signed-off-by: Ilan Peer <[email protected]>
---
net/wireless/reg.c | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 771319e..46c8031 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -552,6 +552,9 @@ reg_call_crda(struct regulatory_request *request)
{
if (call_crda(request->alpha2))
return REG_REQ_IGNORE;
+
+ queue_delayed_work(system_power_efficient_wq,
+ ®_timeout, msecs_to_jiffies(3142));
return REG_REQ_OK;
}
@@ -1779,8 +1782,7 @@ static void reg_set_request_processed(void)
need_more_processing = true;
spin_unlock(®_requests_lock);
- if (lr->initiator == NL80211_REGDOM_SET_BY_USER)
- cancel_delayed_work(®_timeout);
+ cancel_delayed_work(®_timeout);
if (need_more_processing)
schedule_work(®_work);
@@ -2059,8 +2061,6 @@ static void reg_process_hint(struct regulatory_request *reg_request)
if (treatment == REG_REQ_IGNORE ||
treatment == REG_REQ_ALREADY_SET)
return;
- queue_delayed_work(system_power_efficient_wq,
- ®_timeout, msecs_to_jiffies(3142));
return;
case NL80211_REGDOM_SET_BY_DRIVER:
if (!wiphy)
@@ -2485,7 +2485,6 @@ static void restore_regulatory_settings(bool reset_user)
char alpha2[2];
char world_alpha2[2];
struct reg_beacon *reg_beacon, *btmp;
- struct regulatory_request *reg_request, *tmp;
LIST_HEAD(tmp_reg_req_list);
struct cfg80211_registered_device *rdev;
@@ -2513,11 +2512,7 @@ static void restore_regulatory_settings(bool reset_user)
* settings.
*/
spin_lock(®_requests_lock);
- list_for_each_entry_safe(reg_request, tmp, ®_requests_list, list) {
- if (reg_request->initiator != NL80211_REGDOM_SET_BY_USER)
- continue;
- list_move_tail(®_request->list, &tmp_reg_req_list);
- }
+ list_splice_tail_init(®_requests_list, &tmp_reg_req_list);
spin_unlock(®_requests_lock);
/* Clear beacon hints */
--
1.8.3.2
Hi Luis,
> -----Original Message-----
> From: Luis R. Rodriguez [mailto:[email protected]]
> Sent: Tuesday, February 24, 2015 02:03
> To: Peer, Ilan; Jouni Malinen
> Cc: [email protected]; ArikX Nemtsov
> Subject: Re: [PATCH v6 1/2] cfg80211: Add API to change the indoor
> regulatory setting
>
> On Sat, Feb 21, 2015 at 10:57:10PM -0500, Ilan Peer wrote:
> > 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.
>
> At the protocol level should we consider the need for a dynamic environment
> change? Until then a change of environment likely should implicate an AP
> disconnect, which is what Linux does. With your changes in place we could do
> something even more graceful should the protocol allow for it.
>
Not sure I follow ...
> For instance if the regulatory parameters for a country are the same for
> indoor and outdoro a change in environment should not require a disconnect.
>
So you are suggesting to extend the mechanism to also indicate if a teardown
of active interfaces is needed or not? And if so, not sure that this should be done by
the kernel.
> If the change was from a more restrictive environment to a more liberal set of
> regulatory settings it could mean increasing TX power of the AP changing to a
> channel which perhaps was not allowed before.
>
I think that such a flow needs to be handled in user-space by hostapd, which can
leverage the proper mechanisms to do the change, e.g., eCSA.
> If the change was from a less restrictive environment to a more restrictive
> environment the AP might want to change channels for instance or reduce TX
> power.
>
Same as above. For example, hostapd handles DFS related channel changes in
user space. We also added flows to handle channel switch etc. in wpa_supplicant ...
and I need to resubmit them to hostap.
> While change in indoor/outdoor might be something silly to consider given
> the likelihood of it being a common thing to happen that you change an AP
> from indoor / outdoor regularly I'd consider instead the possibility to reuse
> such a dynamic environment change notification for purposes of dynamic
> environmental adjustments of BSSes. Typically BSSes settings are static but RF
> environments change regularly so its silly to expect a BSS and its initial
> Automatic Channel Selection algorithm to be corrrect during the lifetime of a
> BSS.
>
> > - 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.
>
> Sure.
>
> You also fail to explain how we currently provide the indoor thing to the
> kernel, I think its worth providing that in the commit log and also explaining
> how we don't use the country IE environment thing at all.
>
I explained some of the use cases in previous patches, e.g., AC power,
device type etc. I can add this, but I do not understand how country IE is related
here.
> > 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.
> >
> > While at it directly update the indoor setting without wrapping it as
> > a regulatory request, to simplify the processing.
>
> Please wrap that specific change into its own separate commit, it will make it
> easier to review the changes and also make this change atomic.
>
Ok.
Thanks,
Ilan.
On Wed, Feb 25, 2015 at 02:30:40PM +0000, Peer, Ilan wrote:
> Hi Luis,
>
> > -----Original Message-----
> > From: Luis R. Rodriguez [mailto:[email protected]]
> > Sent: Tuesday, February 24, 2015 02:03
> > To: Peer, Ilan; Jouni Malinen
> > Cc: [email protected]; ArikX Nemtsov
> > Subject: Re: [PATCH v6 1/2] cfg80211: Add API to change the indoor
> > regulatory setting
> >
> > On Sat, Feb 21, 2015 at 10:57:10PM -0500, Ilan Peer wrote:
> > > 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.
> >
> > At the protocol level should we consider the need for a dynamic environment
> > change? Until then a change of environment likely should implicate an AP
> > disconnect, which is what Linux does. With your changes in place we could do
> > something even more graceful should the protocol allow for it.
> >
>
> Not sure I follow ...
OK right now we should disconnect if there are some regulatory params that do not
agree. This event will also ony happen *rarely*. Even though this happens rarely
I can find use for forcing this to happen in a not so rare case to help optimize
RF spectrum use dynamically, if the protocol had a way to communicate a desired
change in environment this could be reused for a dynaic RF spectrum change in
environment.
> > For instance if the regulatory parameters for a country are the same for
> > indoor and outdoro a change in environment should not require a disconnect.
> >
>
> So you are suggesting to extend the mechanism to also indicate if a teardown
> of active interfaces is needed or not? And if so, not sure that this should be done by
> the kernel.
If the AP *knew* a change in environment (now forget indoor/outdoor as that is
rare today) was not disruptive this could be information that the STAs can
get to use to evaluate and make a better decision as to whether or not it
did need to tear down or not.
> > If the change was from a more restrictive environment to a more liberal set of
> > regulatory settings it could mean increasing TX power of the AP changing to a
> > channel which perhaps was not allowed before.
> >
>
> I think that such a flow needs to be handled in user-space by hostapd, which can
> leverage the proper mechanisms to do the change, e.g., eCSA.
Right but that's the AP, how would the STAs get that information? This is why
I mentioned the idea of a possible protocol enhancement to let the AP inform
STAs of an environmental change. The AP *could* feed more than just the boring
parameters we're used to. Its OK this is just an idea, ignore it.
> > If the change was from a less restrictive environment to a more restrictive
> > environment the AP might want to change channels for instance or reduce TX
> > power.
> >
>
> Same as above. For example, hostapd handles DFS related channel changes in
> user space. We also added flows to handle channel switch etc. in wpa_supplicant ...
> and I need to resubmit them to hostap.
OK..
> > While change in indoor/outdoor might be something silly to consider given
> > the likelihood of it being a common thing to happen that you change an AP
> > from indoor / outdoor regularly I'd consider instead the possibility to reuse
> > such a dynamic environment change notification for purposes of dynamic
> > environmental adjustments of BSSes. Typically BSSes settings are static but RF
> > environments change regularly so its silly to expect a BSS and its initial
> > Automatic Channel Selection algorithm to be corrrect during the lifetime of a
> > BSS.
> >
> > > - 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.
> >
> > Sure.
> >
> > You also fail to explain how we currently provide the indoor thing to the
> > kernel, I think its worth providing that in the commit log and also explaining
> > how we don't use the country IE environment thing at all.
> >
>
> I explained some of the use cases in previous patches, e.g., AC power,
> device type etc. I can add this, but I do not understand how country IE is related
> here.
Mention it and the country IE is important given its the other place folks
expect it to be deduced from -- and we don't use it at all. Without that
information folks can assume we do unless they are familiar with the code.
It provides useful context for your change, even for me!
Luis