Commit c5142df5 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge tag 'wireless-2025-09-03' of...

Merge tag 'wireless-2025-09-03' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless

Johannes Berg says:

====================
Just a few updates:
 - a set of buffer overflow fixes
 - ath11k: a fix for GTK rekeying
 - ath12k: a missed WiFi7 capability

* tag 'wireless-2025-09-03' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless:
  wifi: wilc1000: avoid buffer overflow in WID string configuration
  wifi: cfg80211: sme: cap SSID length in __cfg80211_connect_result()
  wifi: libertas: cap SSID len in lbs_associate()
  wifi: cw1200: cap SSID length in cw1200_do_join()
  wifi: ath11k: fix group data packet drops during rekey
  wifi: ath12k: Set EMLSR support flag in MLO flags for EML-capable stations
====================

Link: https://patch.msgid.link/20250903075602.30263-4-johannes@sipsolutions.net


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents f63e7c8a 27893dd6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -411,6 +411,8 @@ struct ath11k_vif {
	bool do_not_send_tmpl;
	struct ath11k_arp_ns_offload arp_ns_offload;
	struct ath11k_rekey_data rekey_data;
	u32 num_stations;
	bool reinstall_group_keys;

	struct ath11k_reg_tpc_power_info reg_tpc_info;

+102 −9
Original line number Diff line number Diff line
@@ -4317,6 +4317,40 @@ static int ath11k_clear_peer_keys(struct ath11k_vif *arvif,
	return first_errno;
}

static int ath11k_set_group_keys(struct ath11k_vif *arvif)
{
	struct ath11k *ar = arvif->ar;
	struct ath11k_base *ab = ar->ab;
	const u8 *addr = arvif->bssid;
	int i, ret, first_errno = 0;
	struct ath11k_peer *peer;

	spin_lock_bh(&ab->base_lock);
	peer = ath11k_peer_find(ab, arvif->vdev_id, addr);
	spin_unlock_bh(&ab->base_lock);

	if (!peer)
		return -ENOENT;

	for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
		struct ieee80211_key_conf *key = peer->keys[i];

		if (!key || (key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
			continue;

		ret = ath11k_install_key(arvif, key, SET_KEY, addr,
					 WMI_KEY_GROUP);
		if (ret < 0 && first_errno == 0)
			first_errno = ret;

		if (ret < 0)
			ath11k_warn(ab, "failed to set group key of idx %d for vdev %d: %d\n",
				    i, arvif->vdev_id, ret);
	}

	return first_errno;
}

static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
				 struct ieee80211_vif *vif, struct ieee80211_sta *sta,
				 struct ieee80211_key_conf *key)
@@ -4326,6 +4360,7 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
	struct ath11k_peer *peer;
	struct ath11k_sta *arsta;
	bool is_ap_with_no_sta;
	const u8 *peer_addr;
	int ret = 0;
	u32 flags = 0;
@@ -4386,6 +4421,42 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
	else
		flags |= WMI_KEY_GROUP;

	ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
		   "%s for peer %pM on vdev %d flags 0x%X, type = %d, num_sta %d\n",
		   cmd == SET_KEY ? "SET_KEY" : "DEL_KEY", peer_addr, arvif->vdev_id,
		   flags, arvif->vdev_type, arvif->num_stations);

	/* Allow group key clearing only in AP mode when no stations are
	 * associated. There is a known race condition in firmware where
	 * group addressed packets may be dropped if the key is cleared
	 * and immediately set again during rekey.
	 *
	 * During GTK rekey, mac80211 issues a clear key (if the old key
	 * exists) followed by an install key operation for same key
	 * index. This causes ath11k to send two WMI commands in quick
	 * succession: one to clear the old key and another to install the
	 * new key in the same slot.
	 *
	 * Under certain conditions—especially under high load or time
	 * sensitive scenarios, firmware may process these commands
	 * asynchronously in a way that firmware assumes the key is
	 * cleared whereas hardware has a valid key. This inconsistency
	 * between hardware and firmware leads to group addressed packet
	 * drops after rekey.
	 * Only setting the same key again can restore a valid key in
	 * firmware and allow packets to be transmitted.
	 *
	 * There is a use case where an AP can transition from Secure mode
	 * to open mode without a vdev restart by just deleting all
	 * associated peers and clearing key, Hence allow clear key for
	 * that case alone. Mark arvif->reinstall_group_keys in such cases
	 * and reinstall the same key when the first peer is added,
	 * allowing firmware to recover from the race if it had occurred.
	 */

	is_ap_with_no_sta = (vif->type == NL80211_IFTYPE_AP &&
			     !arvif->num_stations);
	if ((flags & WMI_KEY_PAIRWISE) || cmd == SET_KEY || is_ap_with_no_sta) {
		ret = ath11k_install_key(arvif, key, cmd, peer_addr, flags);
		if (ret) {
			ath11k_warn(ab, "ath11k_install_key failed (%d)\n", ret);
@@ -4394,10 +4465,15 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,

		ret = ath11k_dp_peer_rx_pn_replay_config(arvif, peer_addr, cmd, key);
		if (ret) {
		ath11k_warn(ab, "failed to offload PN replay detection %d\n", ret);
			ath11k_warn(ab, "failed to offload PN replay detection %d\n",
				    ret);
			goto exit;
		}

		if ((flags & WMI_KEY_GROUP) && cmd == SET_KEY && is_ap_with_no_sta)
			arvif->reinstall_group_keys = true;
	}

	spin_lock_bh(&ab->base_lock);
	peer = ath11k_peer_find(ab, arvif->vdev_id, peer_addr);
	if (peer && cmd == SET_KEY) {
@@ -4994,6 +5070,7 @@ static int ath11k_mac_inc_num_stations(struct ath11k_vif *arvif,
		return -ENOBUFS;

	ar->num_stations++;
	arvif->num_stations++;

	return 0;
}
@@ -5009,6 +5086,7 @@ static void ath11k_mac_dec_num_stations(struct ath11k_vif *arvif,
		return;

	ar->num_stations--;
	arvif->num_stations--;
}

static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar,
@@ -9540,6 +9618,21 @@ static int ath11k_mac_station_add(struct ath11k *ar,
		goto exit;
	}

	/* Driver allows the DEL KEY followed by SET KEY sequence for
	 * group keys for only when there is no clients associated, if at
	 * all firmware has entered the race during that window,
	 * reinstalling the same key when the first sta connects will allow
	 * firmware to recover from the race.
	 */
	if (arvif->num_stations == 1 && arvif->reinstall_group_keys) {
		ath11k_dbg(ab, ATH11K_DBG_MAC, "set group keys on 1st station add for vdev %d\n",
			   arvif->vdev_id);
		ret = ath11k_set_group_keys(arvif);
		if (ret)
			goto dec_num_station;
		arvif->reinstall_group_keys = false;
	}

	arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL);
	if (!arsta->rx_stats) {
		ret = -ENOMEM;
+1 −0
Original line number Diff line number Diff line
@@ -2423,6 +2423,7 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,

	eml_cap = arg->ml.eml_cap;
	if (u16_get_bits(eml_cap, IEEE80211_EML_CAP_EMLSR_SUPP)) {
		ml_params->flags |= cpu_to_le32(ATH12K_WMI_FLAG_MLO_EMLSR_SUPPORT);
		/* Padding delay */
		eml_pad_delay = ieee80211_emlsr_pad_delay_in_us(eml_cap);
		ml_params->emlsr_padding_delay_us = cpu_to_le32(eml_pad_delay);
+6 −3
Original line number Diff line number Diff line
@@ -1151,10 +1151,13 @@ static int lbs_associate(struct lbs_private *priv,
	/* add SSID TLV */
	rcu_read_lock();
	ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
	if (ssid_eid)
		pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]);
	else
	if (ssid_eid) {
		u32 ssid_len = min(ssid_eid[1], IEEE80211_MAX_SSID_LEN);

		pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_len);
	} else {
		lbs_deb_assoc("no SSID\n");
	}
	rcu_read_unlock();

	/* add DS param TLV */
+27 −10
Original line number Diff line number Diff line
@@ -41,10 +41,10 @@ static const struct wilc_cfg_word g_cfg_word[] = {
};

static const struct wilc_cfg_str g_cfg_str[] = {
	{WID_FIRMWARE_VERSION, NULL},
	{WID_MAC_ADDR, NULL},
	{WID_ASSOC_RES_INFO, NULL},
	{WID_NIL, NULL}
	{WID_FIRMWARE_VERSION, 0, NULL},
	{WID_MAC_ADDR, 0, NULL},
	{WID_ASSOC_RES_INFO, 0, NULL},
	{WID_NIL, 0, NULL}
};

#define WILC_RESP_MSG_TYPE_CONFIG_REPLY		'R'
@@ -147,44 +147,58 @@ static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, int size)

		switch (FIELD_GET(WILC_WID_TYPE, wid)) {
		case WID_CHAR:
			len = 3;
			if (len + 2  > size)
				return;

			while (cfg->b[i].id != WID_NIL && cfg->b[i].id != wid)
				i++;

			if (cfg->b[i].id == wid)
				cfg->b[i].val = info[4];

			len = 3;
			break;

		case WID_SHORT:
			len = 4;
			if (len + 2  > size)
				return;

			while (cfg->hw[i].id != WID_NIL && cfg->hw[i].id != wid)
				i++;

			if (cfg->hw[i].id == wid)
				cfg->hw[i].val = get_unaligned_le16(&info[4]);

			len = 4;
			break;

		case WID_INT:
			len = 6;
			if (len + 2  > size)
				return;

			while (cfg->w[i].id != WID_NIL && cfg->w[i].id != wid)
				i++;

			if (cfg->w[i].id == wid)
				cfg->w[i].val = get_unaligned_le32(&info[4]);

			len = 6;
			break;

		case WID_STR:
			len = 2 + get_unaligned_le16(&info[2]);

			while (cfg->s[i].id != WID_NIL && cfg->s[i].id != wid)
				i++;

			if (cfg->s[i].id == wid)
			if (cfg->s[i].id == wid) {
				if (len > cfg->s[i].len || (len + 2  > size))
					return;

				memcpy(cfg->s[i].str, &info[2],
				       get_unaligned_le16(&info[2]) + 2);
				       len);
			}

			len = 2 + get_unaligned_le16(&info[2]);
			break;

		default:
@@ -384,12 +398,15 @@ int wilc_wlan_cfg_init(struct wilc *wl)
	/* store the string cfg parameters */
	wl->cfg.s[i].id = WID_FIRMWARE_VERSION;
	wl->cfg.s[i].str = str_vals->firmware_version;
	wl->cfg.s[i].len = sizeof(str_vals->firmware_version);
	i++;
	wl->cfg.s[i].id = WID_MAC_ADDR;
	wl->cfg.s[i].str = str_vals->mac_address;
	wl->cfg.s[i].len = sizeof(str_vals->mac_address);
	i++;
	wl->cfg.s[i].id = WID_ASSOC_RES_INFO;
	wl->cfg.s[i].str = str_vals->assoc_rsp;
	wl->cfg.s[i].len = sizeof(str_vals->assoc_rsp);
	i++;
	wl->cfg.s[i].id = WID_NIL;
	wl->cfg.s[i].str = NULL;
Loading