Commit 38c6aa29 authored by Johannes Berg's avatar Johannes Berg
Browse files

wifi: mac80211: fix multi-BSSID element parsing



When parsing a frame containing a multi-BSSID element, we
need to know both the transmitted and non-transmitted BSSID
so we can parse it correctly.

Unfortunately, in quite a number of cases, we got this wrong
and were passing the wrong BSSID or useless information:
 * the mgmt->bssid from a frame is only the transmitted
   BSSID if the frame is a beacon
 * passing just one of the parameters as non-NULL isn't
   useful and ignored

In those case where we need to parse for a specific BSS we
always have a BSS structure pointer, representing the BSS
we need, whether transmitted or not. Thus, pass that pointer
to the parsing function instead of the two BSSIDs.

Also fix two bugs:
 * we need to re-parse all the elements for the other BSS
   when iterating the non-transmitted BSSes in scan
 * we need to parse for the correct BSS when setting up
   the channel data in client code

Fixes: 78ac51f8 ("mac80211: support multi-bssid")
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent ab3a830d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -502,7 +502,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
				 u.action.u.addba_req.variable);
	if (ies_len) {
		elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
					       ies_len, true, mgmt->bssid, NULL);
					       ies_len, true, NULL);
		if (!elems || elems->parse_error)
			goto free;
	}
+2 −3
Original line number Diff line number Diff line
@@ -1601,8 +1601,7 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
		return;

	elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
				       len - baselen, false,
				       mgmt->bssid, NULL);
				       len - baselen, false, NULL);

	if (elems) {
		ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, elems);
@@ -1655,7 +1654,7 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,

			elems = ieee802_11_parse_elems(
				mgmt->u.action.u.chan_switch.variable,
				ies_len, true, mgmt->bssid, NULL);
				ies_len, true, NULL);

			if (elems && !elems->parse_error)
				ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt,
+8 −14
Original line number Diff line number Diff line
@@ -2147,10 +2147,9 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
 * @filter: bitmap of element IDs to filter out while calculating
 *	the element CRC
 * @crc: CRC starting value
 * @transmitter_bssid: transmitter BSSID to parse the multi-BSSID
 *	element
 * @bss_bssid: BSSID of the BSS we want to obtain elements for
 *	when parsing the multi-BSSID element
 * @bss: the BSS to parse this as, for multi-BSSID cases this can
 *	represent a non-transmitting BSS in which case the data
 *	for that non-transmitting BSS is returned
 */
struct ieee80211_elems_parse_params {
	const u8 *start;
@@ -2158,8 +2157,7 @@ struct ieee80211_elems_parse_params {
	bool action;
	u64 filter;
	u32 crc;
	const u8 *transmitter_bssid;
	const u8 *bss_bssid;
	struct cfg80211_bss *bss;
};

struct ieee802_11_elems *
@@ -2168,8 +2166,7 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params);
static inline struct ieee802_11_elems *
ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
			   u64 filter, u32 crc,
			   const u8 *transmitter_bssid,
			   const u8 *bss_bssid)
			   struct cfg80211_bss *bss)
{
	struct ieee80211_elems_parse_params params = {
		.start = start,
@@ -2177,8 +2174,7 @@ ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
		.action = action,
		.filter = filter,
		.crc = crc,
		.transmitter_bssid = transmitter_bssid,
		.bss_bssid = bss_bssid,
		.bss = bss,
	};

	return ieee802_11_parse_elems_full(&params);
@@ -2186,11 +2182,9 @@ ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,

static inline struct ieee802_11_elems *
ieee802_11_parse_elems(const u8 *start, size_t len, bool action,
		       const u8 *transmitter_bssid,
		       const u8 *bss_bssid)
		       struct cfg80211_bss *bss)
{
	return ieee802_11_parse_elems_crc(start, len, action, 0, 0,
					  transmitter_bssid, bss_bssid);
	return ieee802_11_parse_elems_crc(start, len, action, 0, 0, bss);
}


+3 −5
Original line number Diff line number Diff line
@@ -1256,8 +1256,7 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
	if (baselen > len)
		return;

	elems = ieee802_11_parse_elems(pos, len - baselen, false, mgmt->bssid,
				       NULL);
	elems = ieee802_11_parse_elems(pos, len - baselen, false, NULL);
	if (!elems)
		return;

@@ -1326,7 +1325,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,

	elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
				       len - baselen,
				       false, mgmt->bssid, NULL);
				       false, NULL);
	if (!elems)
		return;

@@ -1468,8 +1467,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
	pos = mgmt->u.action.u.chan_switch.variable;
	baselen = offsetof(struct ieee80211_mgmt,
			   u.action.u.chan_switch.variable);
	elems = ieee802_11_parse_elems(pos, len - baselen, true,
				       mgmt->bssid, NULL);
	elems = ieee802_11_parse_elems(pos, len - baselen, true, NULL);
	if (!elems)
		return;

+1 −1
Original line number Diff line number Diff line
@@ -932,7 +932,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,

	baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
	elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
				       len - baselen, false, mgmt->bssid, NULL);
				       len - baselen, false, NULL);
	if (!elems)
		return;

Loading