From: Ping-Ke Shih Date: Wed, 6 May 2026 13:09:51 +0000 (+0800) Subject: wifi: rtw89: phy: enable IE-09/IE-10 PHY status report for monitor mode X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=847758f15f466235df9bf64272dbdd3ded14520e;p=thirdparty%2Fkernel%2Flinux.git wifi: rtw89: phy: enable IE-09/IE-10 PHY status report for monitor mode The IE-09/IE-10 of PHY status contain SIG-A/SIG-B respectively, so enable them in monitor mode to have rich information. If the parser detects length invalid, ignore to reference IE-09/IE-10 to prevent accessing out of range. The RTL8922D is generation 2 of PHY status, which doesn't report SIG-B by IE-10, so not enable it. Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20260506131000.1706298-6-pkshih@realtek.com --- diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index caedb2bd21d5d..f877c2707c84c 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2152,14 +2152,38 @@ static void rtw89_core_parse_phy_status_ie00_v2(struct rtw89_dev *rtwdev, rpl_path[i] = tmp_rpl[i] >> 1; } +static void rtw89_core_parse_phy_status_ie09(struct rtw89_dev *rtwdev, + const struct rtw89_phy_sts_iehdr *iehdr, + struct rtw89_rx_phy_ppdu *phy_ppdu) +{ + phy_ppdu->ie09 = (const void *)iehdr; +} + +static void rtw89_core_parse_phy_status_ie10(struct rtw89_dev *rtwdev, + const struct rtw89_phy_sts_iehdr *iehdr, + struct rtw89_rx_phy_ppdu *phy_ppdu) +{ + phy_ppdu->ie10 = (const void *)iehdr; +} + static int rtw89_core_process_phy_status_ie(struct rtw89_dev *rtwdev, const struct rtw89_phy_sts_iehdr *iehdr, struct rtw89_rx_phy_ppdu *phy_ppdu) { + bool accept; u8 ie; ie = le32_get_bits(iehdr->w0, RTW89_PHY_STS_IEHDR_TYPE); + /* + * For normal mode, only parse ppdu_sts that are A1-matched, except for + * scanning that needs to get chan_idx in IE01. + */ + accept = phy_ppdu->to_self || ie == RTW89_PHYSTS_IE01_CMN_OFDM || + rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR; + if (!accept) + return 0; + switch (ie) { case RTW89_PHYSTS_IE00_CMN_CCK: rtw89_core_parse_phy_status_ie00(rtwdev, iehdr, phy_ppdu); @@ -2169,6 +2193,12 @@ static int rtw89_core_process_phy_status_ie(struct rtw89_dev *rtwdev, case RTW89_PHYSTS_IE01_CMN_OFDM: rtw89_core_parse_phy_status_ie01(rtwdev, iehdr, phy_ppdu); break; + case RTW89_PHYSTS_IE09_FTR_0: + rtw89_core_parse_phy_status_ie09(rtwdev, iehdr, phy_ppdu); + break; + case RTW89_PHYSTS_IE10_FTR_PLCP_EXT: + rtw89_core_parse_phy_status_ie10(rtwdev, iehdr, phy_ppdu); + break; default: break; } @@ -2228,11 +2258,14 @@ static int rtw89_core_rx_process_phy_ppdu(struct rtw89_dev *rtwdev, static int rtw89_core_rx_parse_phy_sts(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu) { - u16 ie_len; void *pos, *end; + bool accept; + u16 ie_len; - /* mark invalid reports and bypass them */ - if (phy_ppdu->ie < RTW89_CCK_PKT) + /* for normal mode, mark invalid reports and bypass them */ + accept = phy_ppdu->ie >= RTW89_CCK_PKT || + rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR; + if (!accept) return -EINVAL; pos = phy_ppdu->buf + PHY_STS_HDR_LEN; @@ -2246,6 +2279,10 @@ static int rtw89_core_rx_parse_phy_sts(struct rtw89_dev *rtwdev, rtw89_core_process_phy_status_ie(rtwdev, iehdr, phy_ppdu); pos += ie_len; if (pos > end || ie_len == 0) { + /* clear pointers to prevent accessing out of IE */ + phy_ppdu->ie09 = NULL; + phy_ppdu->ie10 = NULL; + rtw89_debug(rtwdev, RTW89_DBG_TXRX, "phy status parse failed\n"); return -EINVAL; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 66dbb1fc3ca81..ca716e95cb2c4 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -24,6 +24,8 @@ struct rtw89_h2c_rf_tssi; struct rtw89_fw_txpwr_track_cfg; struct rtw89_phy_rfk_log_fmt; struct rtw89_phy_calc_efuse_gain; +struct rtw89_phy_sts_ie09; +struct rtw89_phy_sts_ie10; struct rtw89_debugfs; struct rtw89_regd_data; struct rtw89_wow_cam_info; @@ -840,7 +842,7 @@ struct rtw89_rx_phy_ppdu { u8 mac_id; u8 chan_idx; u8 phy_idx; - u8 ie; + u8 ie; /* enum rtw89_phy_status_bitmap */ u16 rate; u8 rpl_avg; u8 rpl_path[RF_PATH_MAX]; @@ -862,6 +864,8 @@ struct rtw89_rx_phy_ppdu { bool to_self; bool valid; bool hdr_2_en; + const struct rtw89_phy_sts_ie09 *ie09; /* SIG-A */ + const struct rtw89_phy_sts_ie10 *ie10; /* SIG-B */ }; enum rtw89_mac_idx { diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 2c6711133c803..330ece51286db 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -98,6 +98,9 @@ static int rtw89_ops_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) !rtwdev->scanning) rtw89_enter_ips(rtwdev); + if (changed & IEEE80211_CONF_CHANGE_MONITOR) + rtw89_physts_parsing_init(rtwdev); + return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 4f82b1a9fa4c6..15483a86951d7 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -7085,10 +7085,21 @@ static void rtw89_physts_enable_hdr_2(struct rtw89_dev *rtwdev, enum rtw89_phy_i static void __rtw89_physts_parsing_init(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { + const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def; const struct rtw89_chip_info *chip = rtwdev->chip; + u32 monitor_mode_mu_ies = 0; + u32 monitor_mode_su_ies = 0; u32 val; u8 i; + if (rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR) { + monitor_mode_mu_ies = BIT(RTW89_PHYSTS_IE09_FTR_0); + if (phy->physt_gen < 2) + monitor_mode_mu_ies |= BIT(RTW89_PHYSTS_IE10_FTR_PLCP_EXT); + + monitor_mode_su_ies = BIT(RTW89_PHYSTS_IE09_FTR_0); + } + rtw89_physts_enable_fail_report(rtwdev, false, phy_idx); /* enable hdr_2 for 8922D (PHYSTS_BE_GEN2 above) */ @@ -7102,6 +7113,7 @@ static void __rtw89_physts_parsing_init(struct rtw89_dev *rtwdev, val = rtw89_physts_get_ie_bitmap(rtwdev, i, phy_idx); if (i == RTW89_HE_MU || i == RTW89_VHT_MU) { val |= BIT(RTW89_PHYSTS_IE13_DL_MU_DEF); + val |= monitor_mode_mu_ies; } else if (i == RTW89_TRIG_BASE_PPDU) { val |= BIT(RTW89_PHYSTS_IE13_DL_MU_DEF) | BIT(RTW89_PHYSTS_IE01_CMN_OFDM); @@ -7115,11 +7127,14 @@ static void __rtw89_physts_parsing_init(struct rtw89_dev *rtwdev, val |= BIT(RTW89_PHYSTS_IE20_DBG_OFDM_FD_USER_SEG_0); } + if (i == RTW89_HE_PKT || i == RTW89_VHT_PKT) + val |= monitor_mode_su_ies; + rtw89_physts_set_ie_bitmap(rtwdev, i, val, phy_idx); } } -static void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev) +void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev) { __rtw89_physts_parsing_init(rtwdev, RTW89_PHY_0); if (rtwdev->dbcc_en) diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index d8038ae5ca869..74fbf5baff586 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -914,6 +914,7 @@ void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev, void rtw89_phy_dm_init(struct rtw89_dev *rtwdev); void rtw89_phy_dm_reinit(struct rtw89_dev *rtwdev); void rtw89_phy_dm_init_data(struct rtw89_dev *rtwdev); +void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev); void rtw89_phy_write32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u32 data, enum rtw89_phy_idx phy_idx); void rtw89_phy_write32_idx_set(struct rtw89_dev *rtwdev, u32 addr, u32 bits, diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index 125ba2a9f1450..18fe6d3d0f83a 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -658,6 +658,15 @@ struct rtw89_phy_sts_ie01_v2 { #define RTW89_PHY_STS_IE01_V2_W9_RPL_FD_C GENMASK(11, 4) #define RTW89_PHY_STS_IE01_V2_W9_RPL_FD_D GENMASK(23, 16) +struct rtw89_phy_sts_ie09 { + __le64 qw0; +} __packed; + +struct rtw89_phy_sts_ie10 { + __le64 qw0; + u8 sigb[]; +} __packed; + enum rtw89_tx_channel { RTW89_TXCH_ACH0 = 0, RTW89_TXCH_ACH1 = 1,