rcu_read_unlock();
}
+static void __rtw89_core_tid_rx_stats_reset(struct rtw89_tid_stats *tid_stats)
+{
+ tid_stats->last_pn = -1LL;
+ tid_stats->last_sn = IEEE80211_SN_MASK;
+}
+
+void rtw89_core_tid_rx_stats_ctrl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+ struct ieee80211_ampdu_params *params, bool enable)
+{
+ struct rtw89_tid_stats *tid_stats;
+ u16 tid = params->tid;
+
+ tid_stats = &rtwsta->tid_rx_stats[tid];
+
+ if (enable) {
+ __rtw89_core_tid_rx_stats_reset(tid_stats);
+ tid_stats->started = true;
+ } else {
+ tid_stats->started = false;
+ }
+}
+
+void rtw89_core_tid_rx_stats_reset(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_tid_stats *tid_stats;
+ struct ieee80211_sta *sta;
+ struct rtw89_sta *rtwsta;
+ u16 tid;
+
+ for_each_station(sta, rtwdev->hw) {
+ rtwsta = sta_to_rtwsta(sta);
+
+ for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
+ tid_stats = &rtwsta->tid_rx_stats[tid];
+
+ if (!tid_stats->started)
+ continue;
+
+ __rtw89_core_tid_rx_stats_reset(tid_stats);
+ }
+ }
+}
+
+static bool rtw89_core_skb_pn_valid(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_desc_info *desc_info,
+ struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_sta_link *rtwsta_link;
+ struct rtw89_tid_stats *tid_stats;
+ struct rtw89_sta *rtwsta;
+ u8 tid, *ccmp_hdr_ptr;
+ s64 pn, last_pn;
+ u16 mpdu_sn;
+ int hdrlen;
+
+ if (chip->chip_gen != RTW89_CHIP_AX)
+ return true;
+
+ if (!ieee80211_is_data_qos(hdr->frame_control))
+ return true;
+
+ if (!desc_info->hw_dec || !desc_info->addr1_match)
+ return true;
+
+ guard(rcu)();
+
+ rtwsta_link = rtw89_assoc_link_rcu_dereference(rtwdev, desc_info->mac_id);
+ if (!rtwsta_link)
+ return true;
+
+ rtwsta = rtwsta_link->rtwsta;
+ tid = ieee80211_get_tid(hdr);
+ tid_stats = &rtwsta->tid_rx_stats[tid];
+
+ if (!tid_stats->started)
+ return true;
+
+ switch (desc_info->sec_type) {
+ case RTW89_SEC_KEY_TYPE_CCMP128:
+ case RTW89_SEC_KEY_TYPE_CCMP256:
+ case RTW89_SEC_KEY_TYPE_GCMP128:
+ case RTW89_SEC_KEY_TYPE_GCMP256:
+ mpdu_sn = ieee80211_get_sn(hdr);
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ ccmp_hdr_ptr = skb->data + hdrlen;
+ ccmp_hdr2pn(&pn, ccmp_hdr_ptr);
+ last_pn = tid_stats->last_pn;
+
+ if (pn > last_pn) {
+ if (ieee80211_sn_less(mpdu_sn, tid_stats->last_sn)) {
+ dev_kfree_skb_any(skb);
+
+ return false;
+ }
+
+ tid_stats->last_sn = mpdu_sn;
+ tid_stats->last_pn = pn;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
static void rtw89_core_rx_to_mac80211(struct rtw89_dev *rtwdev,
struct rtw89_rx_phy_ppdu *phy_ppdu,
struct rtw89_rx_desc_info *desc_info,
desc_info->sec_cam_id = le32_get_bits(rxd_l->dword5, AX_RXD_SEC_CAM_IDX_MASK);
desc_info->mac_id = le32_get_bits(rxd_l->dword5, AX_RXD_MAC_ID_MASK);
desc_info->rx_pl_id = le32_get_bits(rxd_l->dword5, AX_RXD_RX_PL_ID_MASK);
+ desc_info->sec_type = le32_get_bits(rxd_l->dword7, AX_RXD_SEC_TYPE_MASK);
}
EXPORT_SYMBOL(rtw89_core_query_rxdesc);
desc_info->mac_id = le32_get_bits(rxd_s->dword2, BE_RXD_MAC_ID_MASK);
desc_info->addr_cam_valid = le32_get_bits(rxd_s->dword2, BE_RXD_ADDR_CAM_VLD);
+ desc_info->sec_type = le32_get_bits(rxd_s->dword3, BE_RXD_SEC_TYPE_MASK);
desc_info->icv_err = le32_get_bits(rxd_s->dword3, BE_RXD_ICV_ERR);
desc_info->crc32_err = le32_get_bits(rxd_s->dword3, BE_RXD_CRC32_ERR);
desc_info->hw_dec = le32_get_bits(rxd_s->dword3, BE_RXD_HW_DEC);
desc_info->mac_id = le32_get_bits(rxd_s->dword2, BE_RXD_MAC_ID_V1);
desc_info->addr_cam_valid = le32_get_bits(rxd_s->dword2, BE_RXD_ADDR_CAM_VLD);
+ desc_info->sec_type = le32_get_bits(rxd_s->dword3, BE_RXD_SEC_TYPE_MASK);
desc_info->icv_err = le32_get_bits(rxd_s->dword3, BE_RXD_ICV_ERR);
desc_info->crc32_err = le32_get_bits(rxd_s->dword3, BE_RXD_CRC32_ERR);
desc_info->hw_dec = le32_get_bits(rxd_s->dword3, BE_RXD_HW_DEC);
memset(rx_status, 0, sizeof(*rx_status));
rtw89_core_update_rx_status(rtwdev, skb, desc_info, rx_status);
rtw89_core_rx_pkt_hdl(rtwdev, skb, desc_info);
+
+ if (!rtw89_core_skb_pn_valid(rtwdev, desc_info, skb))
+ return;
+
if (desc_info->long_rxdesc &&
BIT(desc_info->frame_type) & PPDU_FILTER_BITMAP)
skb_queue_tail(&ppdu_sts->rx_queue[band], skb);
bool addr_cam_valid;
u8 addr_cam_id;
u8 sec_cam_id;
+ u8 sec_type;
u8 mac_id;
u16 offset;
u16 rxd_len;
u32 tbtt_diff_th;
};
+struct rtw89_tid_stats {
+ s64 last_pn;
+ u16 last_sn;
+ bool started;
+};
+
struct rtw89_dev {
struct ieee80211_hw *hw;
struct device *dev;
struct sk_buff_head roc_queue;
struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS];
+ struct rtw89_tid_stats tid_rx_stats[IEEE80211_NUM_TIDS];
DECLARE_BITMAP(ampdu_map, IEEE80211_NUM_TIDS);
DECLARE_BITMAP(pairwise_sec_cam_map, RTW89_MAX_SEC_CAM_NUM);
void rtw89_core_set_tid_config(struct rtw89_dev *rtwdev,
struct ieee80211_sta *sta,
struct cfg80211_tid_config *tid_config);
+void rtw89_core_tid_rx_stats_ctrl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+ struct ieee80211_ampdu_params *params, bool enable);
+void rtw89_core_tid_rx_stats_reset(struct rtw89_dev *rtwdev);
void rtw89_core_rfkill_poll(struct rtw89_dev *rtwdev, bool force);
void rtw89_check_quirks(struct rtw89_dev *rtwdev, const struct dmi_system_id *quirks);
int rtw89_core_init(struct rtw89_dev *rtwdev);
#include "core.h"
+#define RTW89_KEY_PN_0 GENMASK_ULL(7, 0)
+#define RTW89_KEY_PN_1 GENMASK_ULL(15, 8)
+#define RTW89_KEY_PN_2 GENMASK_ULL(23, 16)
+#define RTW89_KEY_PN_3 GENMASK_ULL(31, 24)
+#define RTW89_KEY_PN_4 GENMASK_ULL(39, 32)
+#define RTW89_KEY_PN_5 GENMASK_ULL(47, 40)
+
#define rtw89_iterate_vifs_bh(rtwdev, iterator, data) \
ieee80211_iterate_active_interfaces_atomic((rtwdev)->hw, \
IEEE80211_IFACE_ITER_NORMAL, iterator, data)
}
}
+static inline void ccmp_hdr2pn(s64 *pn, const u8 *hdr)
+{
+ *pn = u64_encode_bits(hdr[0], RTW89_KEY_PN_0) |
+ u64_encode_bits(hdr[1], RTW89_KEY_PN_1) |
+ u64_encode_bits(hdr[4], RTW89_KEY_PN_2) |
+ u64_encode_bits(hdr[5], RTW89_KEY_PN_3) |
+ u64_encode_bits(hdr[6], RTW89_KEY_PN_4) |
+ u64_encode_bits(hdr[7], RTW89_KEY_PN_5);
+}
+
s32 rtw89_linear_to_db_quarter(u64 val);
s32 rtw89_linear_to_db(u64 val);
u64 rtw89_db_quarter_to_linear(s32 db);