mirror of
https://github.com/torvalds/linux.git
synced 2026-07-29 02:31:27 +02:00
Just a few updates:
- a set of buffer overflow fixes - ath11k: a fix for GTK rekeying - ath12k: a missed WiFi7 capability -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEpeA8sTs3M8SN2hR410qiO8sPaAAFAmi39DMACgkQ10qiO8sP aABWwQ/7BdU0p9Ud0LHPNS9DWfhuuBvD7yhfCbJb/2Jd8n50D6fp4mq3+eW/GCkC 31e/PMmrawR+/Gtd+Q/GKL7eDsi1O+Fgyv2r2E0Yti54hFcgTSpJ9vh2YOIrFNh8 7V+FedKDF4l5mfv9bsLu8T2ioyzhXQ6NXRupxrULZ+A9eKCu0Ae6OJflfsnvthUR HNTvnrqiS7yY773C4vtZKyXkxKcgxHlBxAAcJGt4xjTUyouxw/wkRU4Z326kHpNB E1gA0WbSWV5/p8i+TM8fkP9/H/wRp7MO6HUMzmHYPXLOgOInVNYYj83wxajhxnn3 quH/+mhO92wmi98zP/rB3juwlFzP5eFzzCiD3L0gB+EGJe+Z0tcb4GHYwWKqA9o+ 3uxMLvDoeASDA3yTRqCOQ3m5Ry1+Y6Imbx1JLDgn9ijx7ylWODPtr0H8TUviIW5n QcTvTECIvdRL88QFzB/lO5LXneOVSdkTmMbpS189sOidVmxjRW4iO1KQAZ27fb9C niU7eAoTDvvYH49xJu/yUWWq6UWKt8O4qXD7PbGnUvTK1TKo4N5os45I5VOXBR9H rjSLgzzWgA46EJTIMrKK9mS8ZY+vwKvahYPVwxrNJlzbjFVEPTKOijX+RHYvTyUY LzY6g00bFVamzqulVKBqxgKH855vWf7KOn59odJ3fDOu0JuDlWc= =XgPl -----END PGP SIGNATURE----- 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: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
c5142df58d
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,16 +4421,57 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||
else
|
||||
flags |= WMI_KEY_GROUP;
|
||||
|
||||
ret = ath11k_install_key(arvif, key, cmd, peer_addr, flags);
|
||||
if (ret) {
|
||||
ath11k_warn(ab, "ath11k_install_key failed (%d)\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
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);
|
||||
|
||||
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);
|
||||
goto exit;
|
||||
/* 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);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
memcpy(cfg->s[i].str, &info[2],
|
||||
get_unaligned_le16(&info[2]) + 2);
|
||||
if (cfg->s[i].id == wid) {
|
||||
if (len > cfg->s[i].len || (len + 2 > size))
|
||||
return;
|
||||
|
||||
memcpy(cfg->s[i].str, &info[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;
|
||||
|
|
|
|||
|
|
@ -24,12 +24,13 @@ struct wilc_cfg_word {
|
|||
|
||||
struct wilc_cfg_str {
|
||||
u16 id;
|
||||
u16 len;
|
||||
u8 *str;
|
||||
};
|
||||
|
||||
struct wilc_cfg_str_vals {
|
||||
u8 mac_address[7];
|
||||
u8 firmware_version[129];
|
||||
u8 mac_address[8];
|
||||
u8 firmware_version[130];
|
||||
u8 assoc_rsp[WILC_MAX_ASSOC_RESP_FRAME_SIZE];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1291,7 +1291,7 @@ static void cw1200_do_join(struct cw1200_common *priv)
|
|||
rcu_read_lock();
|
||||
ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
|
||||
if (ssidie) {
|
||||
join.ssid_len = ssidie[1];
|
||||
join.ssid_len = min(ssidie[1], IEEE80211_MAX_SSID_LEN);
|
||||
memcpy(join.ssid, &ssidie[2], join.ssid_len);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
|
|
|||
|
|
@ -900,13 +900,16 @@ void __cfg80211_connect_result(struct net_device *dev,
|
|||
if (!wdev->u.client.ssid_len) {
|
||||
rcu_read_lock();
|
||||
for_each_valid_link(cr, link) {
|
||||
u32 ssid_len;
|
||||
|
||||
ssid = ieee80211_bss_get_elem(cr->links[link].bss,
|
||||
WLAN_EID_SSID);
|
||||
|
||||
if (!ssid || !ssid->datalen)
|
||||
continue;
|
||||
|
||||
memcpy(wdev->u.client.ssid, ssid->data, ssid->datalen);
|
||||
ssid_len = min(ssid->datalen, IEEE80211_MAX_SSID_LEN);
|
||||
memcpy(wdev->u.client.ssid, ssid->data, ssid_len);
|
||||
wdev->u.client.ssid_len = ssid->datalen;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user