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

Commit d34265a3 authored by Johannes Berg's avatar Johannes Berg
Browse files

cfg80211: reg: centralize freeing ignored requests



Instead of having a lot of places that free ignored requests
and then return REG_REQ_OK, make reg_process_hint() process
REG_REQ_IGNORE by freeing the request, and let functions it
calls return that instead of freeing.

This also fixes a leak when a second (different) country IE
hint was ignored.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 480908a7
Loading
Loading
Loading
Loading
+35 −29
Original line number Diff line number Diff line
@@ -273,6 +273,9 @@ MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");

static void reg_free_request(struct regulatory_request *request)
{
	if (request == &core_request_world)
		return;

	if (request != get_last_request())
		kfree(request);
}
@@ -1905,13 +1908,17 @@ static void reg_set_request_processed(void)
 * The wireless subsystem can use this function to process
 * a regulatory request issued by the regulatory core.
 */
static void reg_process_hint_core(struct regulatory_request *core_request)
static enum reg_request_treatment
reg_process_hint_core(struct regulatory_request *core_request)
{
	if (reg_query_database(core_request)) {
		core_request->intersect = false;
		core_request->processed = false;
		reg_update_last_request(core_request);
		return REG_REQ_OK;
	}

	return REG_REQ_IGNORE;
}

static enum reg_request_treatment
@@ -1957,16 +1964,15 @@ __reg_process_hint_user(struct regulatory_request *user_request)
 * The wireless subsystem can use this function to process
 * a regulatory request initiated by userspace.
 */
static void reg_process_hint_user(struct regulatory_request *user_request)
static enum reg_request_treatment
reg_process_hint_user(struct regulatory_request *user_request)
{
	enum reg_request_treatment treatment;

	treatment = __reg_process_hint_user(user_request);
	if (treatment == REG_REQ_IGNORE ||
	    treatment == REG_REQ_ALREADY_SET) {
		reg_free_request(user_request);
		return;
	}
	    treatment == REG_REQ_ALREADY_SET)
		return REG_REQ_IGNORE;

	user_request->intersect = treatment == REG_REQ_INTERSECT;
	user_request->processed = false;
@@ -1975,9 +1981,10 @@ static void reg_process_hint_user(struct regulatory_request *user_request)
		reg_update_last_request(user_request);
		user_alpha2[0] = user_request->alpha2[0];
		user_alpha2[1] = user_request->alpha2[1];
	} else {
		reg_free_request(user_request);
		return REG_REQ_OK;
	}

	return REG_REQ_IGNORE;
}

static enum reg_request_treatment
@@ -2025,15 +2032,12 @@ reg_process_hint_driver(struct wiphy *wiphy,
	case REG_REQ_OK:
		break;
	case REG_REQ_IGNORE:
		reg_free_request(driver_request);
		return REG_REQ_OK;
		return REG_REQ_IGNORE;
	case REG_REQ_INTERSECT:
	case REG_REQ_ALREADY_SET:
		regd = reg_copy_regd(get_cfg80211_regdom());
		if (IS_ERR(regd)) {
			reg_free_request(driver_request);
			return REG_REQ_OK;
		}
		if (IS_ERR(regd))
			return REG_REQ_IGNORE;

		tmp = get_wiphy_regdom(wiphy);
		rcu_assign_pointer(wiphy->regd, regd);
@@ -2056,14 +2060,14 @@ reg_process_hint_driver(struct wiphy *wiphy,
		return REG_REQ_ALREADY_SET;
	}

	if (reg_query_database(driver_request))
	if (reg_query_database(driver_request)) {
		reg_update_last_request(driver_request);
	else
		reg_free_request(driver_request);

		return REG_REQ_OK;
	}

	return REG_REQ_IGNORE;
}

static enum reg_request_treatment
__reg_process_hint_country_ie(struct wiphy *wiphy,
			      struct regulatory_request *country_ie_request)
@@ -2127,31 +2131,30 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
	case REG_REQ_OK:
		break;
	case REG_REQ_IGNORE:
		return REG_REQ_OK;
		return REG_REQ_IGNORE;
	case REG_REQ_ALREADY_SET:
		reg_free_request(country_ie_request);
		return REG_REQ_ALREADY_SET;
	case REG_REQ_INTERSECT:
		reg_free_request(country_ie_request);
		/*
		 * This doesn't happen yet, not sure we
		 * ever want to support it for this case.
		 */
		WARN_ONCE(1, "Unexpected intersection for country IEs");
		return REG_REQ_OK;
		return REG_REQ_IGNORE;
	}

	country_ie_request->intersect = false;
	country_ie_request->processed = false;

	if (reg_query_database(country_ie_request))
	if (reg_query_database(country_ie_request)) {
		reg_update_last_request(country_ie_request);
	else
		reg_free_request(country_ie_request);

		return REG_REQ_OK;
	}

	return REG_REQ_IGNORE;
}

/* This processes *all* regulatory hints */
static void reg_process_hint(struct regulatory_request *reg_request)
{
@@ -2163,11 +2166,11 @@ static void reg_process_hint(struct regulatory_request *reg_request)

	switch (reg_request->initiator) {
	case NL80211_REGDOM_SET_BY_CORE:
		reg_process_hint_core(reg_request);
		return;
		treatment = reg_process_hint_core(reg_request);
		break;
	case NL80211_REGDOM_SET_BY_USER:
		reg_process_hint_user(reg_request);
		return;
		treatment = reg_process_hint_user(reg_request);
		break;
	case NL80211_REGDOM_SET_BY_DRIVER:
		if (!wiphy)
			goto out_free;
@@ -2183,6 +2186,9 @@ static void reg_process_hint(struct regulatory_request *reg_request)
		goto out_free;
	}

	if (treatment == REG_REQ_IGNORE)
		goto out_free;

	WARN(treatment != REG_REQ_OK && treatment != REG_REQ_ALREADY_SET,
	     "unexpected treatment value %d\n", treatment);