]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: rtw89: phy: enable IE-09/IE-10 PHY status report for monitor mode
authorPing-Ke Shih <pkshih@realtek.com>
Wed, 6 May 2026 13:09:51 +0000 (21:09 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Wed, 13 May 2026 03:34:09 +0000 (11:34 +0800)
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 <pkshih@realtek.com>
Link: https://patch.msgid.link/20260506131000.1706298-6-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/mac80211.c
drivers/net/wireless/realtek/rtw89/phy.c
drivers/net/wireless/realtek/rtw89/phy.h
drivers/net/wireless/realtek/rtw89/txrx.h

index caedb2bd21d5daab7dd11c83298ecbc624793406..f877c2707c84c64a42b99283d3405b6fd20b83a7 100644 (file)
@@ -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;
index 66dbb1fc3ca817271ff7055389c2c178ba338c4c..ca716e95cb2c4fa4a9a795c837318c8d64e39045 100644 (file)
@@ -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 {
index 2c6711133c803481a6cbbbb58fef7bea1056c7ee..330ece51286dbb1355a906be316b7ab93bbc9ac9 100644 (file)
@@ -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;
 }
 
index 4f82b1a9fa4c63e62d271e7cbec02006b3e94fb2..15483a86951d77de80b51e2f686955e7617afdcd 100644 (file)
@@ -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)
index d8038ae5ca86977e2553b78dd18ef681ea0cae82..74fbf5baff5869127b6629daa950b5aeb42018a9 100644 (file)
@@ -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,
index 125ba2a9f1450415c010e0368c0bc365a8148e2f..18fe6d3d0f83a183dee835ad68a4f1a634e98801 100644 (file)
@@ -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,