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

wifi: cfg80211/mac80211: check EHT capability size correctly



For AP/non-AP the EHT MCS/NSS subfield size differs, the
4-octet subfield is only used for 20 MHz-only non-AP STA.
Pass an argument around everywhere to be able to parse it
properly.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 4992b360
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -2886,7 +2886,8 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
/* Calculate 802.11be EHT capabilities IE Tx/Rx EHT MCS NSS Support Field size */
static inline u8
ieee80211_eht_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap,
			   const struct ieee80211_eht_cap_elem_fixed *eht_cap)
			   const struct ieee80211_eht_cap_elem_fixed *eht_cap,
			   bool from_ap)
{
	u8 count = 0;

@@ -2907,7 +2908,10 @@ ieee80211_eht_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap,
	if (eht_cap->phy_cap_info[0] & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)
		count += 3;

	return count ? count : 4;
	if (count)
		return count;

	return from_ap ? 3 : 4;
}

/* 802.11be EHT PPE Thresholds */
@@ -2943,7 +2947,8 @@ ieee80211_eht_ppe_size(u16 ppe_thres_hdr, const u8 *phy_cap_info)
}

static inline bool
ieee80211_eht_capa_size_ok(const u8 *he_capa, const u8 *data, u8 len)
ieee80211_eht_capa_size_ok(const u8 *he_capa, const u8 *data, u8 len,
			   bool from_ap)
{
	const struct ieee80211_eht_cap_elem_fixed *elem = (const void *)data;
	u8 needed = sizeof(struct ieee80211_eht_cap_elem_fixed);
@@ -2952,7 +2957,8 @@ ieee80211_eht_capa_size_ok(const u8 *he_capa, const u8 *data, u8 len)
		return false;

	needed += ieee80211_eht_mcs_nss_size((const void *)he_capa,
					     (const void *)data);
					     (const void *)data,
					     from_ap);
	if (len < needed)
		return false;

+3 −1
Original line number Diff line number Diff line
@@ -30,7 +30,9 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
		return;

	mcs_nss_size = ieee80211_eht_mcs_nss_size(he_cap_ie_elem,
						  &eht_cap_ie_elem->fixed);
						  &eht_cap_ie_elem->fixed,
						  sdata->vif.type ==
							NL80211_IFTYPE_STATION);

	eht_total_size += mcs_nss_size;

+5 −1
Original line number Diff line number Diff line
@@ -2185,6 +2185,8 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
 *	for that non-transmitting BSS is returned
 * @link_id: the link ID to parse elements for, if a STA profile
 *	is present in the multi-link element, or -1 to ignore
 * @from_ap: frame is received from an AP (currently used only
 *	for EHT capabilities parsing)
 */
struct ieee80211_elems_parse_params {
	const u8 *start;
@@ -2194,6 +2196,7 @@ struct ieee80211_elems_parse_params {
	u32 crc;
	struct cfg80211_bss *bss;
	int link_id;
	bool from_ap;
};

struct ieee802_11_elems *
@@ -2514,7 +2517,8 @@ u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata, u8 iftype);
u8 *ieee80211_ie_build_eht_cap(u8 *pos,
			       const struct ieee80211_sta_he_cap *he_cap,
			       const struct ieee80211_sta_eht_cap *eht_cap,
			       u8 *end);
			       u8 *end,
			       bool for_ap);

void
ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
+34 −9
Original line number Diff line number Diff line
@@ -746,11 +746,13 @@ static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata,
	eht_cap_size =
		2 + 1 + sizeof(eht_cap->eht_cap_elem) +
		ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
					   &eht_cap->eht_cap_elem) +
					   &eht_cap->eht_cap_elem,
					   false) +
		ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0],
				       eht_cap->eht_cap_elem.phy_cap_info);
	pos = skb_put(skb, eht_cap_size);
	ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, pos + eht_cap_size);
	ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, pos + eht_cap_size,
				   false);
}

static void ieee80211_assoc_add_rates(struct sk_buff *skb,
@@ -3912,6 +3914,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
		.len = elem_len,
		.bss = cbss,
		.link_id = link == &sdata->deflink ? -1 : link->link_id,
		.from_ap = true,
	};
	bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
	bool is_s1g = cbss->channel->band == NL80211_BAND_S1GHZ;
@@ -4580,6 +4583,11 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
	bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
	bool is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ;
	struct ieee80211_bss *bss = (void *)cbss->priv;
	struct ieee80211_elems_parse_params parse_params = {
		.bss = cbss,
		.link_id = -1,
		.from_ap = true,
	};
	struct ieee802_11_elems *elems;
	const struct cfg80211_bss_ies *ies;
	int ret;
@@ -4589,7 +4597,9 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
	rcu_read_lock();

	ies = rcu_dereference(cbss->ies);
	elems = ieee802_11_parse_elems(ies->data, ies->len, false, cbss);
	parse_params.start = ies->data;
	parse_params.len = ies->len;
	elems = ieee802_11_parse_elems_full(&parse_params);
	if (!elems) {
		rcu_read_unlock();
		return -ENOMEM;
@@ -4944,6 +4954,11 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
	struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
	u16 capab_info, status_code, aid;
	struct ieee80211_elems_parse_params parse_params = {
		.bss = NULL,
		.link_id = -1,
		.from_ap = true,
	};
	struct ieee802_11_elems *elems;
	int ac;
	const u8 *elem_start;
@@ -4998,7 +5013,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
		return;

	elem_len = len - (elem_start - (u8 *)mgmt);
	elems = ieee802_11_parse_elems(elem_start, elem_len, false, NULL);
	parse_params.start = elem_start;
	parse_params.len = elem_len;
	elems = ieee802_11_parse_elems_full(&parse_params);
	if (!elems)
		goto notify_driver;

@@ -5363,6 +5380,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
	u32 ncrc = 0;
	u8 *bssid, *variable = mgmt->u.beacon.variable;
	u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN];
	struct ieee80211_elems_parse_params parse_params = {
		.link_id = -1,
		.from_ap = true,
	};

	sdata_assert_lock(sdata);

@@ -5381,6 +5402,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
	if (baselen > len)
		return;

	parse_params.start = variable;
	parse_params.len = len - baselen;

	rcu_read_lock();
	chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
	if (!chanctx_conf) {
@@ -5399,8 +5423,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
	if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
	    !WARN_ON(sdata->vif.valid_links) &&
	    ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->link[0].bss)) {
		elems = ieee802_11_parse_elems(variable, len - baselen, false,
					       ifmgd->assoc_data->link[0].bss);
		parse_params.bss = ifmgd->assoc_data->link[0].bss;
		elems = ieee802_11_parse_elems_full(&parse_params);
		if (!elems)
			return;

@@ -5466,9 +5490,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
	 */
	if (!ieee80211_is_s1g_beacon(hdr->frame_control))
		ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
	elems = ieee802_11_parse_elems_crc(variable, len - baselen,
					   false, care_about_ies, ncrc,
					   link->u.mgd.bss);
	parse_params.bss = link->u.mgd.bss;
	parse_params.filter = care_about_ies;
	parse_params.crc = ncrc;
	elems = ieee802_11_parse_elems_full(&parse_params);
	if (!elems)
		return;
	ncrc = elems->crc;
+20 −9
Original line number Diff line number Diff line
@@ -954,9 +954,11 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_queue_delayed_work);

static void ieee80211_parse_extension_element(u32 *crc,
static void
ieee80211_parse_extension_element(u32 *crc,
				  const struct element *elem,
					      struct ieee802_11_elems *elems)
				  struct ieee802_11_elems *elems,
				  struct ieee80211_elems_parse_params *params)
{
	const void *data = elem->data + 1;
	u8 len;
@@ -1013,7 +1015,8 @@ static void ieee80211_parse_extension_element(u32 *crc,
		break;
	case WLAN_EID_EXT_EHT_CAPABILITY:
		if (ieee80211_eht_capa_size_ok(elems->he_cap,
					       data, len)) {
					       data, len,
					       params->from_ap)) {
			elems->eht_cap = data;
			elems->eht_cap_len = len;
		}
@@ -1385,7 +1388,7 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
		case WLAN_EID_EXTENSION:
			ieee80211_parse_extension_element(calc_crc ?
								&crc : NULL,
							  elem, elems);
							  elem, elems, params);
			break;
		case WLAN_EID_S1G_CAPABILITIES:
			if (elen >= sizeof(*elems->s1g_capab))
@@ -2025,7 +2028,8 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata,
	    cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band),
					 IEEE80211_CHAN_NO_HE |
					 IEEE80211_CHAN_NO_EHT)) {
		pos = ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, end);
		pos = ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, end,
						 sdata->vif.type == NL80211_IFTYPE_AP);
		if (!pos)
			goto out_err;
	}
@@ -4770,6 +4774,7 @@ u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata, u8 iftype)
	const struct ieee80211_sta_he_cap *he_cap;
	const struct ieee80211_sta_eht_cap *eht_cap;
	struct ieee80211_supported_band *sband;
	bool is_ap;
	u8 n;

	sband = ieee80211_get_sband(sdata);
@@ -4781,8 +4786,12 @@ u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata, u8 iftype)
	if (!he_cap || !eht_cap)
		return 0;

	is_ap = iftype == NL80211_IFTYPE_AP ||
		iftype == NL80211_IFTYPE_P2P_GO;

	n = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
				       &eht_cap->eht_cap_elem);
				       &eht_cap->eht_cap_elem,
				       is_ap);
	return 2 + 1 +
	       sizeof(he_cap->he_cap_elem) + n +
	       ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0],
@@ -4793,7 +4802,8 @@ u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata, u8 iftype)
u8 *ieee80211_ie_build_eht_cap(u8 *pos,
			       const struct ieee80211_sta_he_cap *he_cap,
			       const struct ieee80211_sta_eht_cap *eht_cap,
			       u8 *end)
			       u8 *end,
			       bool for_ap)
{
	u8 mcs_nss_len, ppet_len;
	u8 ie_len;
@@ -4804,7 +4814,8 @@ u8 *ieee80211_ie_build_eht_cap(u8 *pos,
		return orig_pos;

	mcs_nss_len = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
						 &eht_cap->eht_cap_elem);
						 &eht_cap->eht_cap_elem,
						 for_ap);
	ppet_len = ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0],
					  eht_cap->eht_cap_elem.phy_cap_info);

Loading