mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
wifi: iwlwif: fixes - 2026-07-21
This PR contains quite a few fixes, mostly found by LLMs. Notably: - missing validation of TLVs length - missing validation on the revision of BIOS tables - missing validation of fw responses length - protect against double free of RX pointers - avoid double deregistration of the tzone core - validate fields in FW responses before using them - fix off-by-one in WLAN_EID_EXT_CAPABILITY parsing - Add missing support for UNII-9 -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQQM3A3Pv7vbm9vtjWbacY7uyt+OfQUCal9OxwAKCRDacY7uyt+O fWfkAQDb/MrxlM6sihTSHBQ+lrLPgp0JYTkSHYGI606/CFO4swD+PLcMPeDvUm1+ fIP1NybrXA3jVfmt4EEm6VVF1LL8bwI= =wkfs -----END PGP SIGNATURE----- Merge tag 'iwlwifi-fixes-2026-07-21' of https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next Miri Korenblit says: ==================== wifi: iwlwif: fixes - 2026-07-21 This PR contains quite a few fixes, mostly found by LLMs. Notably: - missing validation of TLVs length - missing validation on the revision of BIOS tables - missing validation of fw responses length - protect against double free of RX pointers - avoid double deregistration of the tzone core - validate fields in FW responses before using them - fix off-by-one in WLAN_EID_EXT_CAPABILITY parsing - Add missing support for UNII-9 ==================== Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
commit
531f47495a
|
|
@ -15,6 +15,7 @@
|
|||
.non_shared_ant = ANT_B, \
|
||||
.vht_mu_mimo_supported = true, \
|
||||
.uhb_supported = true, \
|
||||
.unii9_supported = true, \
|
||||
.eht_supported = true, \
|
||||
.uhr_supported = true, \
|
||||
.num_rbds = IWL_NUM_RBDS_EHT, \
|
||||
|
|
|
|||
|
|
@ -865,6 +865,11 @@ int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt)
|
|||
min_size, max_size,
|
||||
&tbl_rev);
|
||||
if (!IS_ERR(wifi_pkg)) {
|
||||
if (tbl_rev < 0 ||
|
||||
tbl_rev >= BITS_PER_BYTE *
|
||||
sizeof(rev_data[idx].revisions))
|
||||
continue;
|
||||
|
||||
if (!(BIT(tbl_rev) & rev_data[idx].revisions))
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@ struct iwl_nvm_get_info_phy {
|
|||
|
||||
#define IWL_NUM_CHANNELS_V1 51
|
||||
#define IWL_NUM_CHANNELS_V2 110
|
||||
#define IWL_NUM_CHANNELS_V3 115
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_get_info_regulatory_v1 - regulatory information
|
||||
|
|
@ -219,12 +220,12 @@ struct iwl_nvm_get_info_regulatory_v1 {
|
|||
} __packed; /* REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_get_info_regulatory - regulatory information
|
||||
* struct iwl_nvm_get_info_regulatory_v2 - regulatory information
|
||||
* @lar_enabled: is LAR enabled
|
||||
* @n_channels: number of valid channels in the array
|
||||
* @channel_profile: regulatory data of this channel
|
||||
*/
|
||||
struct iwl_nvm_get_info_regulatory {
|
||||
struct iwl_nvm_get_info_regulatory_v2 {
|
||||
__le32 lar_enabled;
|
||||
__le32 n_channels;
|
||||
__le32 channel_profile[IWL_NUM_CHANNELS_V2];
|
||||
|
|
@ -244,6 +245,32 @@ struct iwl_nvm_get_info_rsp_v3 {
|
|||
struct iwl_nvm_get_info_regulatory_v1 regulatory;
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_RSP_API_S_VER_3 */
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_get_info_rsp_v4 - response to get NVM data
|
||||
* @general: general NVM data
|
||||
* @mac_sku: data relating to MAC sku
|
||||
* @phy_sku: data relating to PHY sku
|
||||
* @regulatory: regulatory data
|
||||
*/
|
||||
struct iwl_nvm_get_info_rsp_v4 {
|
||||
struct iwl_nvm_get_info_general general;
|
||||
struct iwl_nvm_get_info_sku mac_sku;
|
||||
struct iwl_nvm_get_info_phy phy_sku;
|
||||
struct iwl_nvm_get_info_regulatory_v2 regulatory;
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_RSP_API_S_VER_4 */
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_get_info_regulatory - regulatory information
|
||||
* @lar_enabled: is LAR enabled
|
||||
* @n_channels: number of valid channels in the array
|
||||
* @channel_profile: regulatory data of this channel
|
||||
*/
|
||||
struct iwl_nvm_get_info_regulatory {
|
||||
__le32 lar_enabled;
|
||||
__le32 n_channels;
|
||||
__le32 channel_profile[IWL_NUM_CHANNELS_V3];
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_3 */
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_get_info_rsp - response to get NVM data
|
||||
* @general: general NVM data
|
||||
|
|
@ -256,7 +283,7 @@ struct iwl_nvm_get_info_rsp {
|
|||
struct iwl_nvm_get_info_sku mac_sku;
|
||||
struct iwl_nvm_get_info_phy phy_sku;
|
||||
struct iwl_nvm_get_info_regulatory regulatory;
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_RSP_API_S_VER_4 */
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_RSP_API_S_VER_5 */
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_access_complete_cmd - NVM_ACCESS commands are completed
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2026 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -1319,7 +1319,7 @@ struct iwl_scan_offload_match_info {
|
|||
u8 resume_while_scanning;
|
||||
u8 self_recovery;
|
||||
__le16 reserved;
|
||||
struct iwl_scan_offload_profile_match matches[];
|
||||
struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES_V2];
|
||||
} __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_3 and
|
||||
* SCAN_OFFLOAD_MATCH_INFO_NOTIFICATION_S_VER_1
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright(c) 2020-2025 Intel Corporation
|
||||
* Copyright(c) 2020-2026 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "iwl-drv.h"
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
#include "fw/api/alive.h"
|
||||
#include "fw/uefi.h"
|
||||
#include "fw/img.h"
|
||||
#include "fw/dbg.h"
|
||||
|
||||
#define IWL_PNVM_REDUCED_CAP_BIT BIT(25)
|
||||
|
||||
|
|
@ -26,6 +27,12 @@ static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait,
|
|||
struct iwl_trans *trans = (struct iwl_trans *)data;
|
||||
struct iwl_pnvm_init_complete_ntfy *pnvm_ntf = (void *)pkt->data;
|
||||
|
||||
if (IWL_FW_CHECK(trans,
|
||||
iwl_rx_packet_payload_len(pkt) < sizeof(*pnvm_ntf),
|
||||
"Bad notif len: %d\n",
|
||||
iwl_rx_packet_payload_len(pkt)))
|
||||
return true;
|
||||
|
||||
IWL_DEBUG_FW(trans,
|
||||
"PNVM complete notification received with status 0x%0x\n",
|
||||
le32_to_cpu(pnvm_ntf->status));
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ bool iwl_add_mcc_to_tas_block_list(u16 *list, u8 *size, u16 mcc)
|
|||
if (*size >= IWL_WTAS_BLACK_LIST_MAX)
|
||||
return false;
|
||||
|
||||
list[*size++] = mcc;
|
||||
list[(*size)++] = mcc;
|
||||
return true;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_add_mcc_to_tas_block_list);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2021, 2025 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2021, 2025-2026 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -14,9 +14,17 @@ static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt,
|
|||
{
|
||||
struct iwl_shared_mem_cfg *mem_cfg = (void *)pkt->data;
|
||||
int i, lmac;
|
||||
int lmac_num = le32_to_cpu(mem_cfg->lmac_num);
|
||||
u8 api_ver = iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP,
|
||||
SHARED_MEM_CFG_CMD, 0);
|
||||
int lmac_num;
|
||||
u8 api_ver;
|
||||
|
||||
if (IWL_FW_CHECK(fwrt, iwl_rx_packet_payload_len(pkt) <
|
||||
offsetofend(struct iwl_shared_mem_cfg, lmac_smem[1]),
|
||||
"bad shared mem notification size\n"))
|
||||
return;
|
||||
|
||||
lmac_num = le32_to_cpu(mem_cfg->lmac_num);
|
||||
api_ver = iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP,
|
||||
SHARED_MEM_CFG_CMD, 0);
|
||||
|
||||
/* Note: notification has 3 entries, but we only expect 2 */
|
||||
if (IWL_FW_CHECK(fwrt, lmac_num > ARRAY_SIZE(fwrt->smem_cfg.lmac),
|
||||
|
|
@ -30,7 +38,7 @@ static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt,
|
|||
|
||||
if (api_ver >= 4 &&
|
||||
!IWL_FW_CHECK(fwrt, iwl_rx_packet_payload_len(pkt) < sizeof(*mem_cfg),
|
||||
"bad shared mem notification size\n")) {
|
||||
"bad shared mem notification size (v4)\n")) {
|
||||
fwrt->smem_cfg.rxfifo2_control_size =
|
||||
le32_to_cpu(mem_cfg->rxfifo2_control_size);
|
||||
}
|
||||
|
|
@ -53,6 +61,11 @@ static void iwl_parse_shared_mem(struct iwl_fw_runtime *fwrt,
|
|||
struct iwl_shared_mem_cfg_v2 *mem_cfg = (void *)pkt->data;
|
||||
int i;
|
||||
|
||||
if (IWL_FW_CHECK(fwrt, iwl_rx_packet_payload_len(pkt) <
|
||||
offsetof(struct iwl_shared_mem_cfg_v2, rxfifo_addr),
|
||||
"bad shared mem notification size\n"))
|
||||
return;
|
||||
|
||||
fwrt->smem_cfg.num_lmacs = 1;
|
||||
|
||||
fwrt->smem_cfg.num_txfifo_entries = ARRAY_SIZE(mem_cfg->txfifo_size);
|
||||
|
|
@ -67,6 +80,11 @@ static void iwl_parse_shared_mem(struct iwl_fw_runtime *fwrt,
|
|||
/* new API has more data, from rxfifo_addr field and on */
|
||||
if (fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) {
|
||||
if (IWL_FW_CHECK(fwrt, iwl_rx_packet_payload_len(pkt) <
|
||||
sizeof(*mem_cfg),
|
||||
"bad shared mem notification size (extend)\n"))
|
||||
return;
|
||||
|
||||
BUILD_BUG_ON(sizeof(fwrt->smem_cfg.internal_txfifo_size) !=
|
||||
sizeof(mem_cfg->internal_txfifo_size));
|
||||
|
||||
|
|
|
|||
|
|
@ -700,7 +700,7 @@ int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt)
|
|||
return -EINVAL;
|
||||
|
||||
parse_table:
|
||||
if (!(BIT(data->revision) & valid_rev)) {
|
||||
if (data->revision >= 32 || !(BIT(data->revision) & valid_rev)) {
|
||||
ret = -EINVAL;
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"Unsupported UEFI PPAG revision:%d\n",
|
||||
|
|
|
|||
|
|
@ -415,6 +415,7 @@ struct iwl_mac_cfg {
|
|||
* @vht_mu_mimo_supported: VHT MU-MIMO support
|
||||
* @nvm_type: see &enum iwl_nvm_type
|
||||
* @uhb_supported: ultra high band channels supported
|
||||
* @unii9_supported: UNII-9 channels supported
|
||||
* @eht_supported: EHT supported
|
||||
* @uhr_supported: UHR supported
|
||||
* @num_rbds: number of receive buffer descriptors to use
|
||||
|
|
@ -450,6 +451,7 @@ struct iwl_rf_cfg {
|
|||
lp_xtal_workaround:1,
|
||||
vht_mu_mimo_supported:1,
|
||||
uhb_supported:1,
|
||||
unii9_supported:1,
|
||||
eht_supported:1,
|
||||
uhr_supported:1;
|
||||
u8 valid_tx_ant;
|
||||
|
|
|
|||
|
|
@ -475,6 +475,7 @@ static int iwl_dbg_tlv_parse_bin(struct iwl_trans *trans, const u8 *data,
|
|||
{
|
||||
const struct iwl_ucode_tlv *tlv;
|
||||
u32 tlv_len;
|
||||
size_t aligned_tlv_len;
|
||||
|
||||
while (len >= sizeof(*tlv)) {
|
||||
len -= sizeof(*tlv);
|
||||
|
|
@ -487,8 +488,16 @@ static int iwl_dbg_tlv_parse_bin(struct iwl_trans *trans, const u8 *data,
|
|||
len, tlv_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
len -= ALIGN(tlv_len, 4);
|
||||
data += sizeof(*tlv) + ALIGN(tlv_len, 4);
|
||||
|
||||
aligned_tlv_len = ALIGN(tlv_len, 4);
|
||||
if (len < aligned_tlv_len) {
|
||||
IWL_ERR(trans, "invalid aligned TLV len: %zd/%zu\n",
|
||||
len, aligned_tlv_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len -= aligned_tlv_len;
|
||||
data += sizeof(*tlv) + aligned_tlv_len;
|
||||
|
||||
iwl_dbg_tlv_alloc(trans, tlv, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ static void set_sec_offset(struct iwl_firmware_pieces *pieces,
|
|||
* Gets uCode section from tlv.
|
||||
*/
|
||||
static int iwl_store_ucode_sec(struct fw_img_parsing *img,
|
||||
const void *data, int size)
|
||||
const void *data, size_t size)
|
||||
{
|
||||
struct fw_sec *sec;
|
||||
const struct fw_sec_parsing *sec_parse;
|
||||
|
|
@ -501,6 +501,9 @@ static int iwl_store_ucode_sec(struct fw_img_parsing *img,
|
|||
if (WARN_ON(!img || !data))
|
||||
return -EINVAL;
|
||||
|
||||
if (size < sizeof(sec_parse->offset))
|
||||
return -EINVAL;
|
||||
|
||||
sec_parse = (const struct fw_sec_parsing *)data;
|
||||
|
||||
alloc_size = sizeof(*img->sec) * (img->sec_counter + 1);
|
||||
|
|
@ -804,6 +807,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
u32 build, paging_mem_size;
|
||||
int num_of_cpus;
|
||||
bool usniffer_req = false;
|
||||
size_t aligned_tlv_len;
|
||||
|
||||
if (len < sizeof(*ucode)) {
|
||||
IWL_ERR(drv, "uCode has invalid length: %zd\n", len);
|
||||
|
|
@ -852,8 +856,16 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
len, tlv_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
len -= ALIGN(tlv_len, 4);
|
||||
data += sizeof(*tlv) + ALIGN(tlv_len, 4);
|
||||
|
||||
aligned_tlv_len = ALIGN(tlv_len, 4);
|
||||
if (len < aligned_tlv_len) {
|
||||
IWL_ERR(drv, "invalid aligned TLV len: %zd/%zu\n",
|
||||
len, aligned_tlv_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len -= aligned_tlv_len;
|
||||
data += sizeof(*tlv) + aligned_tlv_len;
|
||||
|
||||
switch (tlv_type) {
|
||||
case IWL_UCODE_TLV_INST:
|
||||
|
|
|
|||
|
|
@ -85,16 +85,7 @@ static const u16 iwl_nvm_channels[] = {
|
|||
149, 153, 157, 161, 165
|
||||
};
|
||||
|
||||
static const u16 iwl_ext_nvm_channels[] = {
|
||||
/* 2.4 GHz */
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
/* 5 GHz */
|
||||
36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92,
|
||||
96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
|
||||
149, 153, 157, 161, 165, 169, 173, 177, 181
|
||||
};
|
||||
|
||||
static const u16 iwl_uhb_nvm_channels[] = {
|
||||
static const u16 iwl_unii9_nvm_channels[] = {
|
||||
/* 2.4 GHz */
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
/* 5 GHz */
|
||||
|
|
@ -105,12 +96,16 @@ static const u16 iwl_uhb_nvm_channels[] = {
|
|||
1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69,
|
||||
73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129,
|
||||
133, 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, 181, 185,
|
||||
189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233
|
||||
189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233,
|
||||
|
||||
/* UNII-9 */
|
||||
237, 241, 245, 249, 253
|
||||
};
|
||||
|
||||
#define IWL_NVM_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels)
|
||||
#define IWL_NVM_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels)
|
||||
#define IWL_NVM_NUM_CHANNELS_UHB ARRAY_SIZE(iwl_uhb_nvm_channels)
|
||||
#define IWL_NVM_NUM_CHANNELS_EXT 51
|
||||
#define IWL_NVM_NUM_CHANNELS_UHB 110
|
||||
#define IWL_NVM_NUM_CHANNELS_UNII9 ARRAY_SIZE(iwl_unii9_nvm_channels)
|
||||
#define NUM_2GHZ_CHANNELS 14
|
||||
#define NUM_5GHZ_CHANNELS 37
|
||||
#define FIRST_2GHZ_HT_MINUS 5
|
||||
|
|
@ -351,12 +346,15 @@ static int iwl_init_channel_map(struct iwl_trans *trans,
|
|||
int num_of_ch;
|
||||
const u16 *nvm_chan;
|
||||
|
||||
if (cfg->uhb_supported) {
|
||||
if (cfg->unii9_supported) {
|
||||
num_of_ch = IWL_NVM_NUM_CHANNELS_UNII9;
|
||||
nvm_chan = iwl_unii9_nvm_channels;
|
||||
} else if (cfg->uhb_supported) {
|
||||
num_of_ch = IWL_NVM_NUM_CHANNELS_UHB;
|
||||
nvm_chan = iwl_uhb_nvm_channels;
|
||||
nvm_chan = iwl_unii9_nvm_channels;
|
||||
} else if (cfg->nvm_type == IWL_NVM_EXT) {
|
||||
num_of_ch = IWL_NVM_NUM_CHANNELS_EXT;
|
||||
nvm_chan = iwl_ext_nvm_channels;
|
||||
nvm_chan = iwl_unii9_nvm_channels;
|
||||
} else {
|
||||
num_of_ch = IWL_NVM_NUM_CHANNELS;
|
||||
nvm_chan = iwl_nvm_channels;
|
||||
|
|
@ -1441,7 +1439,9 @@ iwl_parse_mei_nvm_data(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
|
|||
u8 rx_chains = fw->valid_rx_ant;
|
||||
u8 tx_chains = fw->valid_rx_ant;
|
||||
|
||||
if (cfg->uhb_supported)
|
||||
if (cfg->unii9_supported)
|
||||
data = kzalloc_flex(*data, channels, IWL_NVM_NUM_CHANNELS_UNII9);
|
||||
else if (cfg->uhb_supported)
|
||||
data = kzalloc_flex(*data, channels, IWL_NVM_NUM_CHANNELS_UHB);
|
||||
else
|
||||
data = kzalloc_flex(*data, channels, IWL_NVM_NUM_CHANNELS_EXT);
|
||||
|
|
@ -1506,7 +1506,9 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
|
|||
u16 lar_config;
|
||||
const __le16 *ch_section;
|
||||
|
||||
if (cfg->uhb_supported)
|
||||
if (cfg->unii9_supported)
|
||||
data = kzalloc_flex(*data, channels, IWL_NVM_NUM_CHANNELS_UNII9);
|
||||
else if (cfg->uhb_supported)
|
||||
data = kzalloc_flex(*data, channels, IWL_NVM_NUM_CHANNELS_UHB);
|
||||
else if (cfg->nvm_type != IWL_NVM_EXT)
|
||||
data = kzalloc_flex(*data, channels, IWL_NVM_NUM_CHANNELS);
|
||||
|
|
@ -1727,12 +1729,15 @@ iwl_parse_nvm_mcc_info(struct iwl_trans *trans,
|
|||
int max_num_ch;
|
||||
struct iwl_reg_capa reg_capa;
|
||||
|
||||
if (cfg->uhb_supported) {
|
||||
if (cfg->unii9_supported) {
|
||||
max_num_ch = IWL_NVM_NUM_CHANNELS_UNII9;
|
||||
nvm_chan = iwl_unii9_nvm_channels;
|
||||
} else if (cfg->uhb_supported) {
|
||||
max_num_ch = IWL_NVM_NUM_CHANNELS_UHB;
|
||||
nvm_chan = iwl_uhb_nvm_channels;
|
||||
nvm_chan = iwl_unii9_nvm_channels;
|
||||
} else if (cfg->nvm_type == IWL_NVM_EXT) {
|
||||
max_num_ch = IWL_NVM_NUM_CHANNELS_EXT;
|
||||
nvm_chan = iwl_ext_nvm_channels;
|
||||
nvm_chan = iwl_unii9_nvm_channels;
|
||||
} else {
|
||||
max_num_ch = IWL_NVM_NUM_CHANNELS;
|
||||
nvm_chan = iwl_nvm_channels;
|
||||
|
|
@ -2087,13 +2092,26 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
|
|||
struct iwl_nvm_get_info_rsp_v3 *rsp_v3;
|
||||
bool v4 = fw_has_api(&fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_REGULATORY_NVM_INFO);
|
||||
size_t rsp_size = v4 ? sizeof(*rsp) : sizeof(*rsp_v3);
|
||||
size_t rsp_size;
|
||||
void *channel_profile;
|
||||
|
||||
ret = iwl_trans_send_cmd(trans, &hcmd);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
switch (iwl_fw_lookup_notif_ver(fw, REGULATORY_AND_NVM_GROUP,
|
||||
NVM_GET_INFO, 0)) {
|
||||
case 5:
|
||||
rsp_size = sizeof(struct iwl_nvm_get_info_rsp);
|
||||
break;
|
||||
case 4:
|
||||
rsp_size = sizeof(struct iwl_nvm_get_info_rsp_v4);
|
||||
break;
|
||||
default:
|
||||
rsp_size = sizeof(struct iwl_nvm_get_info_rsp_v3);
|
||||
break;
|
||||
}
|
||||
|
||||
if (WARN(iwl_rx_packet_payload_len(hcmd.resp_pkt) != rsp_size,
|
||||
"Invalid payload len in NVM response from FW %d",
|
||||
iwl_rx_packet_payload_len(hcmd.resp_pkt))) {
|
||||
|
|
@ -2107,7 +2125,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
|
|||
if (empty_otp)
|
||||
IWL_INFO(trans, "OTP is empty\n");
|
||||
|
||||
nvm = kzalloc_flex(*nvm, channels, IWL_NUM_CHANNELS_V2);
|
||||
nvm = kzalloc_flex(*nvm, channels, IWL_NUM_CHANNELS_V3);
|
||||
if (!nvm) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
* Copyright (C) 2024-2026 Intel Corporation
|
||||
*/
|
||||
#include "agg.h"
|
||||
#include "sta.h"
|
||||
|
|
@ -222,6 +222,11 @@ iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
|
|||
if (baid == IWL_RX_REORDER_DATA_INVALID_BAID)
|
||||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
if (IWL_FW_CHECK(mld, baid >= ARRAY_SIZE(mld->fw_id_to_ba),
|
||||
"Got out-of-range BAID %u in reorder_data=0x%x\n",
|
||||
baid, reorder))
|
||||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
/* no sta yet */
|
||||
if (WARN_ONCE(!sta,
|
||||
"Got valid BAID without a valid station assigned\n"))
|
||||
|
|
|
|||
|
|
@ -1708,7 +1708,7 @@ static void iwl_mld_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,
|
|||
elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, ies->data,
|
||||
ies->len);
|
||||
|
||||
if (!elem || elem->datalen < 10 ||
|
||||
if (!elem || elem->datalen < 11 ||
|
||||
!(elem->data[10] &
|
||||
WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) {
|
||||
*tolerated = false;
|
||||
|
|
|
|||
|
|
@ -18,9 +18,15 @@ static struct iwl_mcc_update_resp_v8 *
|
|||
iwl_mld_copy_mcc_resp(const struct iwl_rx_packet *pkt)
|
||||
{
|
||||
const struct iwl_mcc_update_resp_v8 *mcc_resp_v8 = (const void *)pkt->data;
|
||||
int n_channels = __le32_to_cpu(mcc_resp_v8->n_channels);
|
||||
struct iwl_mcc_update_resp_v8 *resp_cp;
|
||||
int notif_len = struct_size(resp_cp, channels, n_channels);
|
||||
int n_channels;
|
||||
int notif_len;
|
||||
|
||||
if (iwl_rx_packet_payload_len(pkt) < sizeof(*mcc_resp_v8))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
n_channels = __le32_to_cpu(mcc_resp_v8->n_channels);
|
||||
notif_len = struct_size(resp_cp, channels, n_channels);
|
||||
|
||||
if (iwl_rx_packet_payload_len(pkt) != notif_len)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
* Copyright (C) 2024-2026 Intel Corporation
|
||||
*/
|
||||
#ifdef CONFIG_THERMAL
|
||||
#include <linux/sort.h>
|
||||
|
|
@ -272,6 +272,7 @@ static void iwl_mld_thermal_zone_register(struct iwl_mld *mld)
|
|||
if (ret) {
|
||||
IWL_DEBUG_TEMP(mld, "Failed to enable thermal zone\n");
|
||||
thermal_zone_device_unregister(mld->tzone);
|
||||
mld->tzone = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -385,10 +386,8 @@ static void iwl_mld_thermal_zone_unregister(struct iwl_mld *mld)
|
|||
return;
|
||||
|
||||
IWL_DEBUG_TEMP(mld, "Thermal zone device unregister\n");
|
||||
if (mld->tzone) {
|
||||
thermal_zone_device_unregister(mld->tzone);
|
||||
mld->tzone = NULL;
|
||||
}
|
||||
thermal_zone_device_unregister(mld->tzone);
|
||||
mld->tzone = NULL;
|
||||
}
|
||||
|
||||
static void iwl_mld_cooling_device_unregister(struct iwl_mld *mld)
|
||||
|
|
|
|||
|
|
@ -1120,6 +1120,10 @@ void iwl_mld_handle_tx_resp_notif(struct iwl_mld *mld,
|
|||
ssn = le32_to_cpup((__le32 *)agg_status +
|
||||
tx_resp->frame_count) & 0xFFFF;
|
||||
|
||||
if (IWL_FW_CHECK(mld, txq_id >= ARRAY_SIZE(mld->fw_id_to_txq),
|
||||
"Invalid txq id %d\n", txq_id))
|
||||
return;
|
||||
|
||||
__skb_queue_head_init(&skbs);
|
||||
|
||||
/* we can free until ssn % q.n_bd not inclusive */
|
||||
|
|
|
|||
|
|
@ -1509,6 +1509,10 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
if (WARN_ON_ONCE(truncated < 0))
|
||||
truncated = 0;
|
||||
|
||||
/* this would be a firmware bug */
|
||||
if (WARN_ON_ONCE(pktsize < sizeof(*hdr)))
|
||||
return;
|
||||
|
||||
if (ieee80211_is_data(hdr->frame_control)) {
|
||||
int hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
int ivlen = 0, icvlen = 4; /* also FCS */
|
||||
|
|
@ -1517,10 +1521,6 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
if (!pkt)
|
||||
goto report;
|
||||
|
||||
skb_put_data(pkt, pktdata, hdrlen);
|
||||
pktdata += hdrlen;
|
||||
pktsize -= hdrlen;
|
||||
|
||||
if (ieee80211_has_protected(hdr->frame_control)) {
|
||||
/*
|
||||
* This is unlocked and using gtk_i(c)vlen,
|
||||
|
|
@ -1539,13 +1539,24 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
|
||||
/* if truncated, FCS/ICV is (partially) gone */
|
||||
if (truncated >= icvlen) {
|
||||
icvlen = 0;
|
||||
truncated -= icvlen;
|
||||
icvlen = 0;
|
||||
} else {
|
||||
icvlen -= truncated;
|
||||
truncated = 0;
|
||||
}
|
||||
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
pktsize <= hdrlen + ivlen + icvlen,
|
||||
"pktsize is too small %d\n",
|
||||
pktsize)) {
|
||||
kfree_skb(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
skb_put_data(pkt, pktdata, hdrlen);
|
||||
pktdata += hdrlen;
|
||||
pktsize -= hdrlen;
|
||||
pktsize -= ivlen + icvlen;
|
||||
pktdata += ivlen;
|
||||
|
||||
|
|
@ -2123,16 +2134,16 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
|
|||
struct iwl_wowlan_status_data *status,
|
||||
u32 len)
|
||||
{
|
||||
if (IWL_FW_CHECK(mvm, data->num_mlo_link_keys,
|
||||
"MLO is not supported, shouldn't receive MLO keys\n"))
|
||||
return;
|
||||
|
||||
if (len < sizeof(*data)) {
|
||||
IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");
|
||||
status = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IWL_FW_CHECK(mvm, data->num_mlo_link_keys,
|
||||
"MLO is not supported, shouldn't receive MLO keys\n"))
|
||||
return;
|
||||
|
||||
if (mvm->fast_resume)
|
||||
return;
|
||||
|
||||
|
|
@ -2448,13 +2459,15 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,
|
|||
|
||||
if (fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) {
|
||||
query_len = sizeof(struct iwl_scan_offload_match_info);
|
||||
matches_len = sizeof(struct iwl_scan_offload_profile_match) *
|
||||
max_profiles;
|
||||
query_len = offsetof(struct iwl_scan_offload_match_info,
|
||||
matches) + matches_len;
|
||||
} else {
|
||||
query_len = sizeof(struct iwl_scan_offload_profiles_query_v1);
|
||||
matches_len = sizeof(struct iwl_scan_offload_profile_match_v1) *
|
||||
max_profiles;
|
||||
query_len = sizeof(struct iwl_scan_offload_profiles_query_v1) +
|
||||
matches_len;
|
||||
}
|
||||
|
||||
len = iwl_rx_packet_payload_len(cmd.resp_pkt);
|
||||
|
|
@ -2756,7 +2769,7 @@ static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm,
|
|||
struct iwl_wowlan_status_data *status,
|
||||
u32 len)
|
||||
{
|
||||
u32 data_size, packet_len = le32_to_cpu(notif->wake_packet_length);
|
||||
u32 data_size, packet_len;
|
||||
|
||||
if (len < sizeof(*notif)) {
|
||||
IWL_ERR(mvm, "Invalid WoWLAN wake packet notification!\n");
|
||||
|
|
@ -2775,6 +2788,7 @@ static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
packet_len = le32_to_cpu(notif->wake_packet_length);
|
||||
data_size = len - offsetof(struct iwl_wowlan_wake_pkt_notif, wake_packet);
|
||||
|
||||
/* data_size got the padding from the notification, remove it. */
|
||||
|
|
@ -2807,7 +2821,8 @@ static void iwl_mvm_nd_match_info_handler(struct iwl_mvm *mvm,
|
|||
if (IS_ERR_OR_NULL(vif))
|
||||
return;
|
||||
|
||||
if (len < sizeof(struct iwl_scan_offload_match_info) + matches_len) {
|
||||
if (len < offsetof(struct iwl_scan_offload_match_info, matches) +
|
||||
matches_len) {
|
||||
IWL_ERR(mvm, "Invalid scan match info notification\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -2942,6 +2957,11 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait,
|
|||
case WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION): {
|
||||
struct iwl_d3_end_notif *notif = (void *)pkt->data;
|
||||
|
||||
if (len < sizeof(*notif)) {
|
||||
IWL_ERR(mvm, "Invalid D3 end notification size\n");
|
||||
break;
|
||||
}
|
||||
|
||||
d3_data->d3_end_flags = __le32_to_cpu(notif->flags);
|
||||
d3_data->notif_received |= IWL_D3_NOTIF_D3_END_NOTIF;
|
||||
|
||||
|
|
|
|||
|
|
@ -646,7 +646,8 @@ static void iter(struct ieee80211_hw *hw,
|
|||
WARN_ON(*target->cipher == IWL_LOCATION_CIPHER_INVALID);
|
||||
}
|
||||
|
||||
static void
|
||||
/* The tk buffer is assumed to be exactly TK_11AZ_LEN bytes */
|
||||
static int
|
||||
iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
u8 *bssid, u8 *cipher, u8 *hltk, u8 *tk,
|
||||
u8 *rx_pn, u8 *tx_pn, __le32 *flags)
|
||||
|
|
@ -656,12 +657,12 @@ iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
||||
if (mvmvif->ftm_unprotected)
|
||||
return;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (!(le32_to_cpu(*flags) & (IWL_INITIATOR_AP_FLAGS_NON_TB |
|
||||
IWL_INITIATOR_AP_FLAGS_TB)))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
|
|
@ -679,14 +680,31 @@ iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
if (vif->cfg.assoc &&
|
||||
!memcmp(vif->bss_conf.bssid, bssid, ETH_ALEN)) {
|
||||
struct iwl_mvm_ftm_iter_data target;
|
||||
u32 key_len;
|
||||
|
||||
target.bssid = bssid;
|
||||
target.cipher = cipher;
|
||||
target.tk = NULL;
|
||||
ieee80211_iter_keys(mvm->hw, vif, iter, &target);
|
||||
|
||||
if (!WARN_ON(!target.tk))
|
||||
memcpy(tk, target.tk, TK_11AZ_LEN);
|
||||
if (WARN_ON(!target.tk))
|
||||
return -EINVAL;
|
||||
|
||||
switch (*target.cipher) {
|
||||
case IWL_LOCATION_CIPHER_CCMP_128:
|
||||
case IWL_LOCATION_CIPHER_GCMP_128:
|
||||
key_len = WLAN_KEY_LEN_CCMP;
|
||||
break;
|
||||
case IWL_LOCATION_CIPHER_GCMP_256:
|
||||
key_len = WLAN_KEY_LEN_GCMP_256;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(tk, 0, TK_11AZ_LEN);
|
||||
memcpy(tk, target.tk, key_len);
|
||||
} else {
|
||||
memcpy(tk, entry->tk, sizeof(entry->tk));
|
||||
}
|
||||
|
|
@ -695,8 +713,10 @@ iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
memcpy(tx_pn, entry->tx_pn, sizeof(entry->tx_pn));
|
||||
|
||||
FTM_SET_FLAG(SECURED);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -708,12 +728,11 @@ iwl_mvm_ftm_put_target_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
iwl_mvm_ftm_set_secured_ranging(mvm, vif, target->bssid,
|
||||
&target->cipher, target->hltk,
|
||||
target->tk, target->rx_pn,
|
||||
target->tx_pn,
|
||||
&target->initiator_ap_flags);
|
||||
return err;
|
||||
return iwl_mvm_ftm_set_secured_ranging(mvm, vif, target->bssid,
|
||||
&target->cipher, target->hltk,
|
||||
target->tk, target->rx_pn,
|
||||
target->tx_pn,
|
||||
&target->initiator_ap_flags);
|
||||
}
|
||||
|
||||
static int iwl_mvm_ftm_start_v11(struct iwl_mvm *mvm,
|
||||
|
|
@ -881,11 +900,13 @@ iwl_mvm_ftm_put_target_v10(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
iwl_mvm_ftm_set_target_flags(mvm, peer, &target->initiator_ap_flags);
|
||||
iwl_mvm_ftm_set_sta(mvm, vif, peer, &target->sta_id,
|
||||
&target->initiator_ap_flags);
|
||||
iwl_mvm_ftm_set_secured_ranging(mvm, vif, target->bssid,
|
||||
&target->cipher, target->hltk,
|
||||
target->tk, target->rx_pn,
|
||||
target->tx_pn,
|
||||
&target->initiator_ap_flags);
|
||||
ret = iwl_mvm_ftm_set_secured_ranging(mvm, vif, target->bssid,
|
||||
&target->cipher, target->hltk,
|
||||
target->tk, target->rx_pn,
|
||||
target->tx_pn,
|
||||
&target->initiator_ap_flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
i2r_max_sts = IWL_MVM_FTM_I2R_MAX_STS > 1 ? 1 :
|
||||
IWL_MVM_FTM_I2R_MAX_STS;
|
||||
|
|
|
|||
|
|
@ -964,12 +964,22 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
iwl_rx_packet_payload_len(cmd.resp_pkt) !=
|
||||
sizeof(*resp),
|
||||
"Wrong size for iwl_geo_tx_power_profiles_resp: %d\n",
|
||||
iwl_rx_packet_payload_len(cmd.resp_pkt))) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
resp = (void *)cmd.resp_pkt->data;
|
||||
ret = le32_to_cpu(resp->profile_idx);
|
||||
|
||||
if (WARN_ON(ret > BIOS_GEO_MAX_PROFILE_NUM))
|
||||
ret = -EIO;
|
||||
|
||||
out:
|
||||
iwl_free_resp(&cmd);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1493,49 +1493,54 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
|
|||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
unsigned int pkt_len = iwl_rx_packet_payload_len(pkt);
|
||||
struct iwl_extended_beacon_notif *beacon = (void *)pkt->data;
|
||||
struct iwl_extended_beacon_notif_v5 *beacon_v5 = (void *)pkt->data;
|
||||
struct ieee80211_vif *csa_vif;
|
||||
struct ieee80211_vif *tx_blocked_vif;
|
||||
struct agg_tx_status *agg_status;
|
||||
u32 beacon_gp2;
|
||||
u16 status;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2);
|
||||
|
||||
if (!iwl_mvm_is_short_beacon_notif_supported(mvm)) {
|
||||
struct iwl_extended_beacon_notif_v5 *beacon = (void *)pkt->data;
|
||||
struct iwl_tx_resp *beacon_notify_hdr =
|
||||
&beacon_v5->beacon_notify_hdr;
|
||||
&beacon->beacon_notify_hdr;
|
||||
|
||||
if (unlikely(pkt_len < sizeof(*beacon_v5)))
|
||||
if (unlikely(pkt_len < sizeof(*beacon)))
|
||||
return;
|
||||
|
||||
mvm->ibss_manager = beacon_v5->ibss_mgr_status != 0;
|
||||
beacon_gp2 = le32_to_cpu(beacon->gp2);
|
||||
|
||||
mvm->ibss_manager = beacon->ibss_mgr_status != 0;
|
||||
agg_status = iwl_mvm_get_agg_status(mvm, beacon_notify_hdr);
|
||||
status = le16_to_cpu(agg_status->status) & TX_STATUS_MSK;
|
||||
IWL_DEBUG_RX(mvm,
|
||||
"beacon status %#x retries:%d tsf:0x%016llX gp2:0x%X rate:%d\n",
|
||||
status, beacon_notify_hdr->failure_frame,
|
||||
le64_to_cpu(beacon->tsf),
|
||||
mvm->ap_last_beacon_gp2,
|
||||
beacon_gp2,
|
||||
le32_to_cpu(beacon_notify_hdr->initial_rate));
|
||||
} else {
|
||||
const struct iwl_extended_beacon_notif *beacon =
|
||||
(void *)pkt->data;
|
||||
|
||||
if (unlikely(pkt_len < sizeof(*beacon)))
|
||||
return;
|
||||
|
||||
beacon_gp2 = le32_to_cpu(beacon->gp2);
|
||||
|
||||
mvm->ibss_manager = beacon->ibss_mgr_status != 0;
|
||||
status = le32_to_cpu(beacon->status) & TX_STATUS_MSK;
|
||||
IWL_DEBUG_RX(mvm,
|
||||
"beacon status %#x tsf:0x%016llX gp2:0x%X\n",
|
||||
status, le64_to_cpu(beacon->tsf),
|
||||
mvm->ap_last_beacon_gp2);
|
||||
beacon_gp2);
|
||||
}
|
||||
|
||||
csa_vif = rcu_dereference_protected(mvm->csa_vif,
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
if (unlikely(csa_vif && csa_vif->bss_conf.csa_active))
|
||||
iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2,
|
||||
iwl_mvm_csa_count_down(mvm, csa_vif, beacon_gp2,
|
||||
(status == TX_STATUS_SUCCESS));
|
||||
|
||||
tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif,
|
||||
|
|
|
|||
|
|
@ -625,9 +625,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
|||
hw->wiphy->max_sched_scan_reqs = 1;
|
||||
hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
|
||||
hw->wiphy->max_match_sets = iwl_umac_scan_get_max_profiles(mvm->fw);
|
||||
/* we create the 802.11 header and zero length SSID IE. */
|
||||
hw->wiphy->max_sched_scan_ie_len =
|
||||
SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
|
||||
hw->wiphy->max_sched_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm);
|
||||
hw->wiphy->max_sched_scan_plans = IWL_MAX_SCHED_SCAN_PLANS;
|
||||
hw->wiphy->max_sched_scan_plan_interval = U16_MAX;
|
||||
|
||||
|
|
@ -3061,7 +3059,6 @@ void iwl_mvm_stop_ap_ibss_common(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
mvmvif->ap_ibss_active = false;
|
||||
mvm->ap_last_beacon_gp2 = 0;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP && !vif->p2p) {
|
||||
iwl_mvm_vif_set_low_latency(mvmvif, false,
|
||||
|
|
@ -3490,7 +3487,7 @@ static void iwl_mvm_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,
|
|||
elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, ies->data,
|
||||
ies->len);
|
||||
|
||||
if (!elem || elem->datalen < 10 ||
|
||||
if (!elem || elem->datalen < 11 ||
|
||||
!(elem->data[10] &
|
||||
WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) {
|
||||
data->tolerated = false;
|
||||
|
|
|
|||
|
|
@ -1168,9 +1168,6 @@ struct iwl_mvm {
|
|||
struct ieee80211_vif __rcu *csa_tx_blocked_vif;
|
||||
u8 csa_tx_block_bcn_timeout;
|
||||
|
||||
/* system time of last beacon (for AP/GO interface) */
|
||||
u32 ap_last_beacon_gp2;
|
||||
|
||||
/* indicates that we transmitted the last beacon */
|
||||
bool ibss_manager;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2019, 2021-2025 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2019, 2021-2026 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -416,6 +416,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
|||
int ret, resp_ver;
|
||||
u32 status;
|
||||
int resp_len, n_channels;
|
||||
unsigned int pkt_len;
|
||||
u16 mcc;
|
||||
|
||||
if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm)))
|
||||
|
|
@ -431,6 +432,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
|||
return ERR_PTR(ret);
|
||||
|
||||
pkt = cmd.resp_pkt;
|
||||
pkt_len = iwl_rx_packet_payload_len(pkt);
|
||||
|
||||
resp_ver = iwl_fw_lookup_notif_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP,
|
||||
MCC_UPDATE_CMD, 0);
|
||||
|
|
@ -439,9 +441,18 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
|||
if (resp_ver >= 8) {
|
||||
struct iwl_mcc_update_resp_v8 *mcc_resp_v8 = (void *)pkt->data;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, pkt_len < sizeof(*mcc_resp_v8),
|
||||
"MCC v8 response too short: %u\n", pkt_len)) {
|
||||
resp_cp = ERR_PTR(-EINVAL);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
n_channels = __le32_to_cpu(mcc_resp_v8->n_channels);
|
||||
if (iwl_rx_packet_payload_len(pkt) !=
|
||||
struct_size(mcc_resp_v8, channels, n_channels)) {
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
pkt_len !=
|
||||
struct_size(mcc_resp_v8, channels, n_channels),
|
||||
"invalid MCC v8 response size: %u (n_channels=%d)\n",
|
||||
pkt_len, n_channels)) {
|
||||
resp_cp = ERR_PTR(-EINVAL);
|
||||
goto exit;
|
||||
}
|
||||
|
|
@ -464,9 +475,18 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
|||
IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) {
|
||||
struct iwl_mcc_update_resp_v4 *mcc_resp_v4 = (void *)pkt->data;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, pkt_len < sizeof(*mcc_resp_v4),
|
||||
"MCC v4 response too short: %u\n", pkt_len)) {
|
||||
resp_cp = ERR_PTR(-EINVAL);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
n_channels = __le32_to_cpu(mcc_resp_v4->n_channels);
|
||||
if (iwl_rx_packet_payload_len(pkt) !=
|
||||
struct_size(mcc_resp_v4, channels, n_channels)) {
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
pkt_len !=
|
||||
struct_size(mcc_resp_v4, channels, n_channels),
|
||||
"invalid MCC v4 response size: %u (n_channels=%d)\n",
|
||||
pkt_len, n_channels)) {
|
||||
resp_cp = ERR_PTR(-EINVAL);
|
||||
goto exit;
|
||||
}
|
||||
|
|
@ -489,9 +509,18 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
|||
} else {
|
||||
struct iwl_mcc_update_resp_v3 *mcc_resp_v3 = (void *)pkt->data;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, pkt_len < sizeof(*mcc_resp_v3),
|
||||
"MCC v3 response too short: %u\n", pkt_len)) {
|
||||
resp_cp = ERR_PTR(-EINVAL);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
n_channels = __le32_to_cpu(mcc_resp_v3->n_channels);
|
||||
if (iwl_rx_packet_payload_len(pkt) !=
|
||||
struct_size(mcc_resp_v3, channels, n_channels)) {
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
pkt_len !=
|
||||
struct_size(mcc_resp_v3, channels, n_channels),
|
||||
"invalid MCC v3 response size: %u (n_channels=%d)\n",
|
||||
pkt_len, n_channels)) {
|
||||
resp_cp = ERR_PTR(-EINVAL);
|
||||
goto exit;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2021 - 2023, 2025 Intel Corporation
|
||||
* Copyright (C) 2021 - 2023, 2025-2026 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "mvm.h"
|
||||
|
|
@ -121,6 +121,8 @@ iwl_mvm_get_crosstimestamp_fw(struct iwl_mvm *mvm, u32 *gp2, u64 *sys_time)
|
|||
*sys_time = (u64)le32_to_cpu(resp->platform_timestamp_hi) << 32 |
|
||||
le32_to_cpu(resp->platform_timestamp_lo);
|
||||
|
||||
iwl_free_resp(&cmd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2018-2026 Intel Corporation
|
||||
*/
|
||||
#include "rs.h"
|
||||
#include "fw-api.h"
|
||||
|
|
@ -423,9 +423,14 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
|
|||
struct iwl_lq_sta_rs_fw *lq_sta;
|
||||
u32 flags;
|
||||
|
||||
notif = (void *)pkt->data;
|
||||
if (IWL_FW_CHECK(mvm, notif->sta_id >= mvm->fw->ucode_capa.num_stations,
|
||||
"Invalid sta id (%d) in TLC notification\n",
|
||||
notif->sta_id))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
notif = (void *)pkt->data;
|
||||
link_sta = rcu_dereference(mvm->fw_id_to_link_sta[notif->sta_id]);
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[notif->sta_id]);
|
||||
if (IS_ERR_OR_NULL(sta) || !link_sta) {
|
||||
|
|
|
|||
|
|
@ -1227,6 +1227,11 @@ void iwl_mvm_window_status_notif(struct iwl_mvm *mvm,
|
|||
/* get the station */
|
||||
sta_id = (ratid & BA_WINDOW_STATUS_STA_ID_MSK)
|
||||
>> BA_WINDOW_STATUS_STA_ID_POS;
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
sta_id >= mvm->fw->ucode_capa.num_stations,
|
||||
"Invalid sta id (%d) in BA window status notification\n",
|
||||
sta_id))
|
||||
continue;
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
|
||||
if (IS_ERR_OR_NULL(sta))
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2026 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -3144,8 +3144,6 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms);
|
||||
|
||||
/* for 6 GHZ band only PSC channels need to be added */
|
||||
for (i = 0; i < params.n_channels; i++) {
|
||||
struct ieee80211_channel *channel = params.channels[i];
|
||||
|
|
@ -3179,6 +3177,8 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
|
|||
goto out;
|
||||
}
|
||||
|
||||
iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms);
|
||||
|
||||
uid = iwl_mvm_build_scan_cmd(mvm, vif, &hcmd, ¶ms, type);
|
||||
if (uid < 0) {
|
||||
ret = uid;
|
||||
|
|
@ -3217,6 +3217,10 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
|
|||
|
||||
mvm->mei_scan_filter.is_mei_limited_scan = false;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, uid >= ARRAY_SIZE(mvm->scan_uid_status),
|
||||
"FW reports out-of-range scan UID %d\n", uid))
|
||||
return;
|
||||
|
||||
IWL_DEBUG_SCAN(mvm,
|
||||
"Scan completed: uid=%u type=%u, status=%s, EBS=%s\n",
|
||||
uid, mvm->scan_uid_status[uid],
|
||||
|
|
|
|||
|
|
@ -951,6 +951,11 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,
|
|||
struct ieee80211_vif *vif;
|
||||
struct iwl_mvm_vif *mvmvif;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, id >= ARRAY_SIZE(mvm->vif_id_to_mac),
|
||||
"Invalid mac_link_id (%d) in session protect notif\n",
|
||||
id))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* note we use link ID == MAC ID */
|
||||
|
|
|
|||
|
|
@ -1544,6 +1544,17 @@ static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm *mvm,
|
|||
return val & 0xFFF;
|
||||
}
|
||||
|
||||
static inline size_t iwl_mvm_tx_resp_min_len(struct iwl_mvm *mvm,
|
||||
struct iwl_tx_resp *tx_resp)
|
||||
{
|
||||
struct agg_tx_status *agg_status =
|
||||
iwl_mvm_get_agg_status(mvm, tx_resp);
|
||||
|
||||
/* The aggregate response ends with a trailing SCD SSN __le32 word. */
|
||||
return (u8 *)(agg_status + tx_resp->frame_count) - (u8 *)tx_resp +
|
||||
sizeof(__le32);
|
||||
}
|
||||
|
||||
static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
|
|
@ -1847,6 +1858,9 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
|
|||
int queue = SEQ_TO_QUEUE(sequence);
|
||||
struct ieee80211_sta *sta;
|
||||
|
||||
if (WARN_ON_ONCE(iwl_mvm_has_new_tx_api(mvm)))
|
||||
return;
|
||||
|
||||
if (WARN_ON_ONCE(queue < IWL_MVM_DQA_MIN_DATA_QUEUE &&
|
||||
(queue != IWL_MVM_DQA_BSS_CLIENT_QUEUE)))
|
||||
return;
|
||||
|
|
@ -1881,6 +1895,26 @@ void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
|
|||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_tx_resp *tx_resp = (void *)pkt->data;
|
||||
size_t min_len;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, !tx_resp->frame_count,
|
||||
"invalid TX_CMD frame_count %u\n",
|
||||
tx_resp->frame_count))
|
||||
return;
|
||||
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
iwl_mvm_has_new_tx_api(mvm) &&
|
||||
tx_resp->frame_count != 1,
|
||||
"invalid TX_CMD frame_count %u for new TX API\n",
|
||||
tx_resp->frame_count))
|
||||
return;
|
||||
|
||||
min_len = iwl_mvm_tx_resp_min_len(mvm, tx_resp);
|
||||
if (IWL_FW_CHECK(mvm, iwl_rx_packet_payload_len(pkt) < min_len,
|
||||
"invalid TX_CMD len %u (frame_count %u, min %zu)\n",
|
||||
iwl_rx_packet_payload_len(pkt), tx_resp->frame_count,
|
||||
min_len))
|
||||
return;
|
||||
|
||||
if (tx_resp->frame_count == 1)
|
||||
iwl_mvm_rx_tx_cmd_single(mvm, pkt);
|
||||
|
|
@ -2100,8 +2134,14 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
|
|||
if (tid == IWL_MGMT_TID)
|
||||
tid = IWL_MAX_TID_COUNT;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, tid >=
|
||||
ARRAY_SIZE(mvmsta->tid_data),
|
||||
"invalid TID %d in compressed BA\n",
|
||||
tid))
|
||||
continue;
|
||||
|
||||
if (mvmsta)
|
||||
mvmsta->tid_data[i].lq_color = lq_color;
|
||||
mvmsta->tid_data[tid].lq_color = lq_color;
|
||||
|
||||
iwl_mvm_tx_reclaim(mvm, sta_id, tid,
|
||||
(int)(le16_to_cpu(ba_tfd->q_num)),
|
||||
|
|
@ -2121,6 +2161,9 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
|
|||
ba_notif = (void *)pkt->data;
|
||||
sta_id = ba_notif->sta_id;
|
||||
tid = ba_notif->tid;
|
||||
if (IWL_FW_CHECK(mvm, tid >= ARRAY_SIZE(mvmsta->tid_data),
|
||||
"invalid TID %d in BA notif\n", tid))
|
||||
return;
|
||||
/* "flow" corresponds to Tx queue */
|
||||
txq = le16_to_cpu(ba_notif->scd_flow);
|
||||
/* "ssn" is start of block-ack Tx window, corresponds to index
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2018-2026 Intel Corporation
|
||||
*/
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-fh.h"
|
||||
|
|
@ -99,6 +99,11 @@ int iwl_pcie_init_fw_sec(struct iwl_trans *trans,
|
|||
/* add 2 due to separators */
|
||||
paging_cnt = iwl_pcie_get_num_sections(fw, lmac_cnt + umac_cnt + 2);
|
||||
|
||||
if (WARN_ON(lmac_cnt > ARRAY_SIZE(ctxt_dram->lmac_img) ||
|
||||
umac_cnt > ARRAY_SIZE(ctxt_dram->umac_img) ||
|
||||
paging_cnt > ARRAY_SIZE(ctxt_dram->virtual_img)))
|
||||
return -EINVAL;
|
||||
|
||||
dram->fw = kzalloc_objs(*dram->fw, umac_cnt + lmac_cnt);
|
||||
if (!dram->fw)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2003-2014, 2018-2024 Intel Corporation
|
||||
* Copyright (C) 2003-2014, 2018-2024, 2026 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -1238,11 +1238,16 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
|
|||
}
|
||||
}
|
||||
kfree(trans_pcie->rx_pool);
|
||||
trans_pcie->rx_pool = NULL;
|
||||
kfree(trans_pcie->global_table);
|
||||
trans_pcie->global_table = NULL;
|
||||
kfree(trans_pcie->rxq);
|
||||
trans_pcie->rxq = NULL;
|
||||
|
||||
if (trans_pcie->alloc_page)
|
||||
if (trans_pcie->alloc_page) {
|
||||
__free_pages(trans_pcie->alloc_page, trans_pcie->rx_page_order);
|
||||
trans_pcie->alloc_page = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_pcie_rx_move_to_allocator(struct iwl_rxq *rxq,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user