Skip to content

Commit c5142df

Browse files
committed
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/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents f63e7c8 + 27893dd commit c5142df

File tree

8 files changed

+146
-26
lines changed

8 files changed

+146
-26
lines changed

drivers/net/wireless/ath/ath11k/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,8 @@ struct ath11k_vif {
411411
bool do_not_send_tmpl;
412412
struct ath11k_arp_ns_offload arp_ns_offload;
413413
struct ath11k_rekey_data rekey_data;
414+
u32 num_stations;
415+
bool reinstall_group_keys;
414416

415417
struct ath11k_reg_tpc_power_info reg_tpc_info;
416418

drivers/net/wireless/ath/ath11k/mac.c

Lines changed: 102 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4317,6 +4317,40 @@ static int ath11k_clear_peer_keys(struct ath11k_vif *arvif,
43174317
return first_errno;
43184318
}
43194319

4320+
static int ath11k_set_group_keys(struct ath11k_vif *arvif)
4321+
{
4322+
struct ath11k *ar = arvif->ar;
4323+
struct ath11k_base *ab = ar->ab;
4324+
const u8 *addr = arvif->bssid;
4325+
int i, ret, first_errno = 0;
4326+
struct ath11k_peer *peer;
4327+
4328+
spin_lock_bh(&ab->base_lock);
4329+
peer = ath11k_peer_find(ab, arvif->vdev_id, addr);
4330+
spin_unlock_bh(&ab->base_lock);
4331+
4332+
if (!peer)
4333+
return -ENOENT;
4334+
4335+
for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
4336+
struct ieee80211_key_conf *key = peer->keys[i];
4337+
4338+
if (!key || (key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
4339+
continue;
4340+
4341+
ret = ath11k_install_key(arvif, key, SET_KEY, addr,
4342+
WMI_KEY_GROUP);
4343+
if (ret < 0 && first_errno == 0)
4344+
first_errno = ret;
4345+
4346+
if (ret < 0)
4347+
ath11k_warn(ab, "failed to set group key of idx %d for vdev %d: %d\n",
4348+
i, arvif->vdev_id, ret);
4349+
}
4350+
4351+
return first_errno;
4352+
}
4353+
43204354
static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
43214355
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
43224356
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,
43264360
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
43274361
struct ath11k_peer *peer;
43284362
struct ath11k_sta *arsta;
4363+
bool is_ap_with_no_sta;
43294364
const u8 *peer_addr;
43304365
int ret = 0;
43314366
u32 flags = 0;
@@ -4386,16 +4421,57 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
43864421
else
43874422
flags |= WMI_KEY_GROUP;
43884423

4389-
ret = ath11k_install_key(arvif, key, cmd, peer_addr, flags);
4390-
if (ret) {
4391-
ath11k_warn(ab, "ath11k_install_key failed (%d)\n", ret);
4392-
goto exit;
4393-
}
4424+
ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
4425+
"%s for peer %pM on vdev %d flags 0x%X, type = %d, num_sta %d\n",
4426+
cmd == SET_KEY ? "SET_KEY" : "DEL_KEY", peer_addr, arvif->vdev_id,
4427+
flags, arvif->vdev_type, arvif->num_stations);
4428+
4429+
/* Allow group key clearing only in AP mode when no stations are
4430+
* associated. There is a known race condition in firmware where
4431+
* group addressed packets may be dropped if the key is cleared
4432+
* and immediately set again during rekey.
4433+
*
4434+
* During GTK rekey, mac80211 issues a clear key (if the old key
4435+
* exists) followed by an install key operation for same key
4436+
* index. This causes ath11k to send two WMI commands in quick
4437+
* succession: one to clear the old key and another to install the
4438+
* new key in the same slot.
4439+
*
4440+
* Under certain conditions—especially under high load or time
4441+
* sensitive scenarios, firmware may process these commands
4442+
* asynchronously in a way that firmware assumes the key is
4443+
* cleared whereas hardware has a valid key. This inconsistency
4444+
* between hardware and firmware leads to group addressed packet
4445+
* drops after rekey.
4446+
* Only setting the same key again can restore a valid key in
4447+
* firmware and allow packets to be transmitted.
4448+
*
4449+
* There is a use case where an AP can transition from Secure mode
4450+
* to open mode without a vdev restart by just deleting all
4451+
* associated peers and clearing key, Hence allow clear key for
4452+
* that case alone. Mark arvif->reinstall_group_keys in such cases
4453+
* and reinstall the same key when the first peer is added,
4454+
* allowing firmware to recover from the race if it had occurred.
4455+
*/
43944456

4395-
ret = ath11k_dp_peer_rx_pn_replay_config(arvif, peer_addr, cmd, key);
4396-
if (ret) {
4397-
ath11k_warn(ab, "failed to offload PN replay detection %d\n", ret);
4398-
goto exit;
4457+
is_ap_with_no_sta = (vif->type == NL80211_IFTYPE_AP &&
4458+
!arvif->num_stations);
4459+
if ((flags & WMI_KEY_PAIRWISE) || cmd == SET_KEY || is_ap_with_no_sta) {
4460+
ret = ath11k_install_key(arvif, key, cmd, peer_addr, flags);
4461+
if (ret) {
4462+
ath11k_warn(ab, "ath11k_install_key failed (%d)\n", ret);
4463+
goto exit;
4464+
}
4465+
4466+
ret = ath11k_dp_peer_rx_pn_replay_config(arvif, peer_addr, cmd, key);
4467+
if (ret) {
4468+
ath11k_warn(ab, "failed to offload PN replay detection %d\n",
4469+
ret);
4470+
goto exit;
4471+
}
4472+
4473+
if ((flags & WMI_KEY_GROUP) && cmd == SET_KEY && is_ap_with_no_sta)
4474+
arvif->reinstall_group_keys = true;
43994475
}
44004476

44014477
spin_lock_bh(&ab->base_lock);
@@ -4994,6 +5070,7 @@ static int ath11k_mac_inc_num_stations(struct ath11k_vif *arvif,
49945070
return -ENOBUFS;
49955071

49965072
ar->num_stations++;
5073+
arvif->num_stations++;
49975074

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

50115088
ar->num_stations--;
5089+
arvif->num_stations--;
50125090
}
50135091

50145092
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,
95409618
goto exit;
95419619
}
95429620

9621+
/* Driver allows the DEL KEY followed by SET KEY sequence for
9622+
* group keys for only when there is no clients associated, if at
9623+
* all firmware has entered the race during that window,
9624+
* reinstalling the same key when the first sta connects will allow
9625+
* firmware to recover from the race.
9626+
*/
9627+
if (arvif->num_stations == 1 && arvif->reinstall_group_keys) {
9628+
ath11k_dbg(ab, ATH11K_DBG_MAC, "set group keys on 1st station add for vdev %d\n",
9629+
arvif->vdev_id);
9630+
ret = ath11k_set_group_keys(arvif);
9631+
if (ret)
9632+
goto dec_num_station;
9633+
arvif->reinstall_group_keys = false;
9634+
}
9635+
95439636
arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL);
95449637
if (!arsta->rx_stats) {
95459638
ret = -ENOMEM;

drivers/net/wireless/ath/ath12k/wmi.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2423,6 +2423,7 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
24232423

24242424
eml_cap = arg->ml.eml_cap;
24252425
if (u16_get_bits(eml_cap, IEEE80211_EML_CAP_EMLSR_SUPP)) {
2426+
ml_params->flags |= cpu_to_le32(ATH12K_WMI_FLAG_MLO_EMLSR_SUPPORT);
24262427
/* Padding delay */
24272428
eml_pad_delay = ieee80211_emlsr_pad_delay_in_us(eml_cap);
24282429
ml_params->emlsr_padding_delay_us = cpu_to_le32(eml_pad_delay);

drivers/net/wireless/marvell/libertas/cfg.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,10 +1151,13 @@ static int lbs_associate(struct lbs_private *priv,
11511151
/* add SSID TLV */
11521152
rcu_read_lock();
11531153
ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
1154-
if (ssid_eid)
1155-
pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]);
1156-
else
1154+
if (ssid_eid) {
1155+
u32 ssid_len = min(ssid_eid[1], IEEE80211_MAX_SSID_LEN);
1156+
1157+
pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_len);
1158+
} else {
11571159
lbs_deb_assoc("no SSID\n");
1160+
}
11581161
rcu_read_unlock();
11591162

11601163
/* add DS param TLV */

drivers/net/wireless/microchip/wilc1000/wlan_cfg.c

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ static const struct wilc_cfg_word g_cfg_word[] = {
4141
};
4242

4343
static const struct wilc_cfg_str g_cfg_str[] = {
44-
{WID_FIRMWARE_VERSION, NULL},
45-
{WID_MAC_ADDR, NULL},
46-
{WID_ASSOC_RES_INFO, NULL},
47-
{WID_NIL, NULL}
44+
{WID_FIRMWARE_VERSION, 0, NULL},
45+
{WID_MAC_ADDR, 0, NULL},
46+
{WID_ASSOC_RES_INFO, 0, NULL},
47+
{WID_NIL, 0, NULL}
4848
};
4949

5050
#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)
147147

148148
switch (FIELD_GET(WILC_WID_TYPE, wid)) {
149149
case WID_CHAR:
150+
len = 3;
151+
if (len + 2 > size)
152+
return;
153+
150154
while (cfg->b[i].id != WID_NIL && cfg->b[i].id != wid)
151155
i++;
152156

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

156-
len = 3;
157160
break;
158161

159162
case WID_SHORT:
163+
len = 4;
164+
if (len + 2 > size)
165+
return;
166+
160167
while (cfg->hw[i].id != WID_NIL && cfg->hw[i].id != wid)
161168
i++;
162169

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

166-
len = 4;
167173
break;
168174

169175
case WID_INT:
176+
len = 6;
177+
if (len + 2 > size)
178+
return;
179+
170180
while (cfg->w[i].id != WID_NIL && cfg->w[i].id != wid)
171181
i++;
172182

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

176-
len = 6;
177186
break;
178187

179188
case WID_STR:
189+
len = 2 + get_unaligned_le16(&info[2]);
190+
180191
while (cfg->s[i].id != WID_NIL && cfg->s[i].id != wid)
181192
i++;
182193

183-
if (cfg->s[i].id == wid)
194+
if (cfg->s[i].id == wid) {
195+
if (len > cfg->s[i].len || (len + 2 > size))
196+
return;
197+
184198
memcpy(cfg->s[i].str, &info[2],
185-
get_unaligned_le16(&info[2]) + 2);
199+
len);
200+
}
186201

187-
len = 2 + get_unaligned_le16(&info[2]);
188202
break;
189203

190204
default:
@@ -384,12 +398,15 @@ int wilc_wlan_cfg_init(struct wilc *wl)
384398
/* store the string cfg parameters */
385399
wl->cfg.s[i].id = WID_FIRMWARE_VERSION;
386400
wl->cfg.s[i].str = str_vals->firmware_version;
401+
wl->cfg.s[i].len = sizeof(str_vals->firmware_version);
387402
i++;
388403
wl->cfg.s[i].id = WID_MAC_ADDR;
389404
wl->cfg.s[i].str = str_vals->mac_address;
405+
wl->cfg.s[i].len = sizeof(str_vals->mac_address);
390406
i++;
391407
wl->cfg.s[i].id = WID_ASSOC_RES_INFO;
392408
wl->cfg.s[i].str = str_vals->assoc_rsp;
409+
wl->cfg.s[i].len = sizeof(str_vals->assoc_rsp);
393410
i++;
394411
wl->cfg.s[i].id = WID_NIL;
395412
wl->cfg.s[i].str = NULL;

drivers/net/wireless/microchip/wilc1000/wlan_cfg.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@ struct wilc_cfg_word {
2424

2525
struct wilc_cfg_str {
2626
u16 id;
27+
u16 len;
2728
u8 *str;
2829
};
2930

3031
struct wilc_cfg_str_vals {
31-
u8 mac_address[7];
32-
u8 firmware_version[129];
32+
u8 mac_address[8];
33+
u8 firmware_version[130];
3334
u8 assoc_rsp[WILC_MAX_ASSOC_RESP_FRAME_SIZE];
3435
};
3536

drivers/net/wireless/st/cw1200/sta.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1291,7 +1291,7 @@ static void cw1200_do_join(struct cw1200_common *priv)
12911291
rcu_read_lock();
12921292
ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
12931293
if (ssidie) {
1294-
join.ssid_len = ssidie[1];
1294+
join.ssid_len = min(ssidie[1], IEEE80211_MAX_SSID_LEN);
12951295
memcpy(join.ssid, &ssidie[2], join.ssid_len);
12961296
}
12971297
rcu_read_unlock();

net/wireless/sme.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -900,13 +900,16 @@ void __cfg80211_connect_result(struct net_device *dev,
900900
if (!wdev->u.client.ssid_len) {
901901
rcu_read_lock();
902902
for_each_valid_link(cr, link) {
903+
u32 ssid_len;
904+
903905
ssid = ieee80211_bss_get_elem(cr->links[link].bss,
904906
WLAN_EID_SSID);
905907

906908
if (!ssid || !ssid->datalen)
907909
continue;
908910

909-
memcpy(wdev->u.client.ssid, ssid->data, ssid->datalen);
911+
ssid_len = min(ssid->datalen, IEEE80211_MAX_SSID_LEN);
912+
memcpy(wdev->u.client.ssid, ssid->data, ssid_len);
910913
wdev->u.client.ssid_len = ssid->datalen;
911914
break;
912915
}

0 commit comments

Comments
 (0)