Commit 27893dd6 authored by Johannes Berg's avatar Johannes Berg
Browse files

Merge tag 'ath-current-20250902' of git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath



Jeff Johnson says:
==================
ath.git update for v6.17-rc5

Fix a long-standing issue with ath11k dropping group data packets
during GTK rekey, and fix an omission in the ath12k multi-link EMLSR
support introduced in v6.16.
==================

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parents fe9e4d0c 97acb025
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);