Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 52616f2b authored by Ilan Peer's avatar Ilan Peer Committed by Johannes Berg
Browse files

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: default avatarIlan Peer <ilan.peer@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 174e0cd2
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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,
};

/**
+7 −11
Original line number Diff line number Diff line
@@ -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;

@@ -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]);
@@ -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,
+57 −1
Original line number Diff line number Diff line
@@ -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 = {
@@ -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);
@@ -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());
@@ -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);

@@ -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;
	}
@@ -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:
@@ -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);
@@ -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)
{
@@ -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);

+1 −0
Original line number Diff line number Diff line
@@ -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);