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

Commit 671042a4 authored by Sara Sharon's avatar Sara Sharon Committed by Johannes Berg
Browse files

mac80211: support non-inheritance element



Subelement profile may specify element IDs it doesn't inherit
from the management frame. Support it.

Signed-off-by: default avatarSara Sharon <sara.sharon@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent f7dacfb1
Loading
Loading
Loading
Loading
+77 −57
Original line number Original line Diff line number Diff line
@@ -894,10 +894,10 @@ EXPORT_SYMBOL(ieee80211_queue_delayed_work);
static u32
static u32
_ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
_ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
			    struct ieee802_11_elems *elems,
			    struct ieee802_11_elems *elems,
			    u64 filter, u32 crc, u8 *transmitter_bssid,
			    u64 filter, u32 crc,
			    u8 *bss_bssid)
			    const struct element *check_inherit)
{
{
	const struct element *elem, *sub;
	const struct element *elem;
	bool calc_crc = filter != 0;
	bool calc_crc = filter != 0;
	DECLARE_BITMAP(seen_elems, 256);
	DECLARE_BITMAP(seen_elems, 256);
	const u8 *ie;
	const u8 *ie;
@@ -910,6 +910,11 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
		u8 elen = elem->datalen;
		u8 elen = elem->datalen;
		const u8 *pos = elem->data;
		const u8 *pos = elem->data;


		if (check_inherit &&
		    !cfg80211_is_element_inherited(elem,
						   check_inherit))
			continue;

		switch (id) {
		switch (id) {
		case WLAN_EID_SSID:
		case WLAN_EID_SSID:
		case WLAN_EID_SUPP_RATES:
		case WLAN_EID_SUPP_RATES:
@@ -1208,57 +1213,6 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
			if (elen >= sizeof(*elems->max_idle_period_ie))
			if (elen >= sizeof(*elems->max_idle_period_ie))
				elems->max_idle_period_ie = (void *)pos;
				elems->max_idle_period_ie = (void *)pos;
			break;
			break;
		case WLAN_EID_MULTIPLE_BSSID:
			if (!bss_bssid || !transmitter_bssid || elen < 4)
				break;

			elems->max_bssid_indicator = pos[0];

			for_each_element(sub, pos + 1, elen - 1) {
				u8 sub_len = sub->datalen;
				u8 new_bssid[ETH_ALEN];
				const u8 *index;

				/*
				 * we only expect the "non-transmitted BSSID
				 * profile" subelement (subelement id 0)
				 */
				if (sub->id != 0 || sub->datalen < 4) {
					/* not a valid BSS profile */
					continue;
				}

				if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
				    sub->data[1] != 2) {
					/* The first element of the
					 * Nontransmitted BSSID Profile is not
					 * the Nontransmitted BSSID Capability
					 * element.
					 */
					continue;
				}

				/* found a Nontransmitted BSSID Profile */
				index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
							 sub->data, sub_len);
				if (!index || index[1] < 1 || index[2] == 0) {
					/* Invalid MBSSID Index element */
					continue;
				}

				cfg80211_gen_new_bssid(transmitter_bssid,
						       pos[0],
						       index[2],
						       new_bssid);
				if (ether_addr_equal(new_bssid, bss_bssid)) {
					elems->nontransmitted_bssid_profile =
						(void *)sub;
					elems->bssid_index_len = index[1];
					elems->bssid_index = (void *)&index[2];
					break;
				}
			}
			break;
		case WLAN_EID_EXTENSION:
		case WLAN_EID_EXTENSION:
			if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA &&
			if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA &&
			    elen >= (sizeof(*elems->mu_edca_param_set) + 1)) {
			    elen >= (sizeof(*elems->mu_edca_param_set) + 1)) {
@@ -1300,25 +1254,91 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
	return crc;
	return crc;
}
}


static void ieee802_11_find_bssid_profile(const u8 *start, size_t len,
					  struct ieee802_11_elems *elems,
					  u8 *transmitter_bssid,
					  u8 *bss_bssid)
{
	const struct element *elem, *sub;

	if (!bss_bssid || !transmitter_bssid)
		return;

	for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) {
		if (elem->datalen < 2)
			continue;

		for_each_element(sub, elem->data + 1, elem->datalen - 1) {
			u8 new_bssid[ETH_ALEN];
			const u8 *index;

			if (sub->id != 0 || sub->datalen < 4) {
				/* not a valid BSS profile */
				continue;
			}

			if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
			    sub->data[1] != 2) {
				/* The first element of the
				 * Nontransmitted BSSID Profile is not
				 * the Nontransmitted BSSID Capability
				 * element.
				 */
				continue;
			}

			/* found a Nontransmitted BSSID Profile */
			index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
						 sub->data, sub->datalen);
			if (!index || index[1] < 1 || index[2] == 0) {
				/* Invalid MBSSID Index element */
				continue;
			}

			cfg80211_gen_new_bssid(transmitter_bssid,
					       elem->data[0],
					       index[2],
					       new_bssid);
			if (ether_addr_equal(new_bssid, bss_bssid)) {
				elems->nontransmitted_bssid_profile =
					elem->data;
				elems->bssid_index_len = index[1];
				elems->bssid_index = (void *)&index[2];
				break;
			}
		}
	}
}

u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
			       struct ieee802_11_elems *elems,
			       struct ieee802_11_elems *elems,
			       u64 filter, u32 crc, u8 *transmitter_bssid,
			       u64 filter, u32 crc, u8 *transmitter_bssid,
			       u8 *bss_bssid)
			       u8 *bss_bssid)
{
{
	const struct element *non_inherit = NULL;

	memset(elems, 0, sizeof(*elems));
	memset(elems, 0, sizeof(*elems));
	elems->ie_start = start;
	elems->ie_start = start;
	elems->total_len = len;
	elems->total_len = len;


	ieee802_11_find_bssid_profile(start, len, elems, transmitter_bssid,
				      bss_bssid);

	if (elems->nontransmitted_bssid_profile)
		non_inherit =
			cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
					       &elems->nontransmitted_bssid_profile[2],
					       elems->nontransmitted_bssid_profile[1]);

	crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
	crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
					  crc, transmitter_bssid, bss_bssid);
					  crc, non_inherit);


	/* Override with nontransmitted profile, if found */
	/* Override with nontransmitted profile, if found */
	if (transmitter_bssid && elems->nontransmitted_bssid_profile) {
	if (transmitter_bssid && elems->nontransmitted_bssid_profile) {
		const u8 *profile = elems->nontransmitted_bssid_profile;
		const u8 *profile = elems->nontransmitted_bssid_profile;


		_ieee802_11_parse_elems_crc(&profile[2], profile[1],
		_ieee802_11_parse_elems_crc(&profile[2], profile[1],
					    action, elems, 0, 0,
					    action, elems, 0, 0, NULL);
					    transmitter_bssid, bss_bssid);
	}
	}


	if (elems->tim && !elems->parse_error) {
	if (elems->tim && !elems->parse_error) {