Skip to content

Commit

Permalink
cfg80211: Add an option to hint indoor operation
Browse files Browse the repository at this point in the history
Add the option to hint the wireless core that it is operating in an indoor
environment.

Signed-off-by: Ilan Peer <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
  • Loading branch information
ilanpeer2 authored and jmberg-intel committed Apr 9, 2014
1 parent 174e0cd commit 52616f2
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 12 deletions.
3 changes: 3 additions & 0 deletions include/uapi/linux/nl80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -2602,10 +2602,13 @@ enum nl80211_dfs_regions {
* present has been registered with the wireless core that
* has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a
* supported feature.
* @NL80211_USER_REG_HINT_INDOOR: a user sent an hint indicating that the
* platform is operating in an indoor environment.
*/
enum nl80211_user_reg_hint_type {
NL80211_USER_REG_HINT_USER = 0,
NL80211_USER_REG_HINT_CELL_BASE = 1,
NL80211_USER_REG_HINT_INDOOR = 2,
};

/**
Expand Down
18 changes: 7 additions & 11 deletions net/wireless/nl80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -4677,7 +4677,6 @@ static int parse_reg_rule(struct nlattr *tb[],

static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
{
int r;
char *data = NULL;
enum nl80211_user_reg_hint_type user_reg_hint_type;

Expand All @@ -4690,11 +4689,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
return -EINPROGRESS;

if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
return -EINVAL;

data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);

if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
user_reg_hint_type =
nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
Expand All @@ -4704,14 +4698,16 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
switch (user_reg_hint_type) {
case NL80211_USER_REG_HINT_USER:
case NL80211_USER_REG_HINT_CELL_BASE:
break;
if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
return -EINVAL;

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();
default:
return -EINVAL;
}

r = regulatory_hint_user(data, user_reg_hint_type);

return r;
}

static int nl80211_get_mesh_config(struct sk_buff *skb,
Expand Down
58 changes: 57 additions & 1 deletion net/wireless/reg.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,26 @@
#define REG_DBG_PRINT(args...)
#endif

/**
* enum reg_request_treatment - regulatory request treatment
*
* @REG_REQ_OK: continue processing the regulatory request
* @REG_REQ_IGNORE: ignore the regulatory request
* @REG_REQ_INTERSECT: the regulatory domain resulting from this request should
* 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 = {
Expand Down Expand Up @@ -106,6 +121,14 @@ const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
*/
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 const struct ieee80211_regdomain *get_cfg80211_regdom(void)
{
return rtnl_dereference(cfg80211_regdomain);
Expand Down Expand Up @@ -1128,6 +1151,13 @@ 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());
Expand Down Expand Up @@ -1570,6 +1600,11 @@ __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);

Expand Down Expand Up @@ -1617,7 +1652,8 @@ 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_ALREADY_SET ||
treatment == REG_REQ_USER_HINT_HANDLED) {
kfree(user_request);
return treatment;
}
Expand Down Expand Up @@ -1678,6 +1714,7 @@ reg_process_hint_driver(struct wiphy *wiphy,
case REG_REQ_OK:
break;
case REG_REQ_IGNORE:
case REG_REQ_USER_HINT_HANDLED:
kfree(driver_request);
return treatment;
case REG_REQ_INTERSECT:
Expand Down Expand Up @@ -1777,6 +1814,7 @@ 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:
kfree(country_ie_request);
Expand Down Expand Up @@ -1969,6 +2007,22 @@ int regulatory_hint_user(const char *alpha2,
return 0;
}

int regulatory_hint_indoor_user(void)
{
struct regulatory_request *request;

request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
if (!request)
return -ENOMEM;

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);

return 0;
}

/* Driver hints */
int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
{
Expand Down Expand Up @@ -2136,6 +2190,8 @@ static void restore_regulatory_settings(bool reset_user)

ASSERT_RTNL();

reg_is_indoor = false;

reset_regdomains(true, &world_regdom);
restore_alpha2(alpha2, reset_user);

Expand Down
1 change: 1 addition & 0 deletions net/wireless/reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ 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);

void wiphy_regulatory_register(struct wiphy *wiphy);
void wiphy_regulatory_deregister(struct wiphy *wiphy);
Expand Down

0 comments on commit 52616f2

Please sign in to comment.