* [PATCH] wifi: mt76: mt792x: fix use-after-free in mt76_rx_poll_complete
@ 2026-04-30 8:45 JB Tsai
2026-05-04 19:26 ` Sean Wang
0 siblings, 1 reply; 2+ messages in thread
From: JB Tsai @ 2026-04-30 8:45 UTC (permalink / raw)
To: nbd, lorenzo
Cc: linux-wireless, linux-mediatek, Deren.Wu, Sean.Wang, Quan.Zhou,
Ryder.Lee, Leon.Yen, litien.chang, eason.lai, jb.tsai, Eason Lai
From: Eason Lai <Eason.Lai@mediatek.com>
A use-after-free issue occurs in mt76_rx_poll_complete due to a race
condition. The STA has already been removed, but the rx_status still
had a pointer to the wcid in the STA.
Use wcid_idx instead of storing the wcid pointer, and look up the wcid
via rcu_dereference() by wcid_idx.
BUG: KASAN: invalid-access in mt76_rx_poll_complete+0x280/0x470 [mt76]
Call trace:
dump_backtrace+0xec/0x128
show_stack+0x18/0x28
dump_stack_lvl+0x40/0xc8
print_report+0x1b8/0x710
kasan_report+0xe0/0x144
do_bad_area+0x120/0x260
do_tag_check_fault+0x20/0x34
do_mem_abort+0x54/0xa8
el1_abort+0x3c/0x5c
el1h_64_sync_handler+0x40/0xcc
el1h_64_sync+0x7c/0x80
mt76_rx_poll_complete+0x280/0x470
mt76_dma_rx_poll+0x114/0x51c
mt792x_poll_rx+0x60/0xf8
napi_threaded_poll_loop+0xe0/0x450
napi_threaded_poll+0x80/0x9c
kthread+0x11c/0x158
ret_from_fork+0x10/0x20
Signed-off-by: Eason Lai <Eason.Lai@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/agg-rx.c | 18 ++++---
drivers/net/wireless/mediatek/mt76/mac80211.c | 47 ++++++++-----------
drivers/net/wireless/mediatek/mt76/mt76.h | 7 ++-
.../net/wireless/mediatek/mt76/mt7603/mac.c | 6 ++-
.../net/wireless/mediatek/mt76/mt7615/mac.c | 19 +++++---
.../net/wireless/mediatek/mt76/mt76_connac.h | 3 +-
.../wireless/mediatek/mt76/mt76_connac_mac.c | 12 ++++-
.../net/wireless/mediatek/mt76/mt7915/mac.c | 16 +++++--
.../net/wireless/mediatek/mt76/mt7921/mac.c | 13 +++--
.../net/wireless/mediatek/mt76/mt7925/mac.c | 19 +++++---
.../net/wireless/mediatek/mt76/mt7996/mac.c | 29 ++++++++----
11 files changed, 114 insertions(+), 75 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c
index bf1babac3895..b72d13975466 100644
--- a/drivers/net/wireless/mediatek/mt76/agg-rx.c
+++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c
@@ -116,14 +116,15 @@ mt76_rx_aggr_reorder_work(struct work_struct *work)
}
static void
-mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames)
+mt76_rx_aggr_check_ctl(struct mt76_dev *dev, struct sk_buff *skb,
+ struct sk_buff_head *frames)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
struct ieee80211_bar *bar = mt76_skb_get_hdr(skb);
- struct mt76_wcid *wcid = status->wcid;
struct mt76_rx_tid *tid;
- u8 tidno;
+ struct mt76_wcid *wcid;
u16 seqno;
+ u8 tidno;
if (!ieee80211_is_ctl(bar->frame_control))
return;
@@ -131,6 +132,10 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames)
if (!ieee80211_is_back_req(bar->frame_control))
return;
+ wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
+ if (!wcid)
+ return;
+
status->qos_ctl = tidno = le16_to_cpu(bar->control) >> 12;
seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num));
tid = rcu_dereference(wcid->aggr[tidno]);
@@ -145,10 +150,11 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames)
spin_unlock_bh(&tid->lock);
}
-void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
+void mt76_rx_aggr_reorder(struct mt76_dev *dev, struct sk_buff *skb,
+ struct sk_buff_head *frames)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
- struct mt76_wcid *wcid = status->wcid;
+ struct mt76_wcid *wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
struct ieee80211_sta *sta;
struct mt76_rx_tid *tid;
bool sn_less;
@@ -164,7 +170,7 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
if (!status->aggr) {
if (!(status->flag & RX_FLAG_8023))
- mt76_rx_aggr_check_ctl(skb, frames);
+ mt76_rx_aggr_check_ctl(dev, skb, frames);
return;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 4ae5e4715a9c..2933b29782d3 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -1283,21 +1283,24 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
memcpy(status->chain_signal, mstat.chain_signal,
sizeof(mstat.chain_signal));
- if (mstat.wcid) {
- status->link_valid = mstat.wcid->link_valid;
- status->link_id = mstat.wcid->link_id;
- }
+ if (mstat.wcid_idx != MT76_WCID_IDX_INVALID) {
+ struct mt76_wcid *wcid = __mt76_wcid_ptr(dev, mstat.wcid_idx);
- *sta = wcid_to_sta(mstat.wcid);
+ if (wcid) {
+ status->link_valid = wcid->link_valid;
+ status->link_id = wcid->link_id;
+ *sta = wcid_to_sta(wcid);
+ }
+ }
*hw = mt76_phy_hw(dev, mstat.phy_idx);
}
static void
-mt76_check_ccmp_pn(struct sk_buff *skb)
+mt76_check_ccmp_pn(struct mt76_dev *dev, struct sk_buff *skb)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
- struct mt76_wcid *wcid = status->wcid;
struct ieee80211_hdr *hdr;
+ struct mt76_wcid *wcid;
int security_idx;
int ret;
@@ -1307,6 +1310,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
if (status->flag & RX_FLAG_ONLY_MONITOR)
return;
+ wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
if (!wcid || !wcid->rx_check_pn)
return;
@@ -1354,7 +1358,7 @@ static void
mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
int len)
{
- struct mt76_wcid *wcid = status->wcid;
+ struct mt76_wcid *wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
struct ieee80211_rx_status info = {
.enc_flags = status->enc_flags,
.rate_idx = status->rate_idx,
@@ -1382,19 +1386,9 @@ mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
static void
mt76_airtime_flush_ampdu(struct mt76_dev *dev)
{
- struct mt76_wcid *wcid;
- int wcid_idx;
-
if (!dev->rx_ampdu_len)
return;
- wcid_idx = dev->rx_ampdu_status.wcid_idx;
- if (wcid_idx < ARRAY_SIZE(dev->wcid))
- wcid = rcu_dereference(dev->wcid[wcid_idx]);
- else
- wcid = NULL;
- dev->rx_ampdu_status.wcid = wcid;
-
mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
dev->rx_ampdu_len = 0;
@@ -1405,7 +1399,7 @@ static void
mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
- struct mt76_wcid *wcid = status->wcid;
+ struct mt76_wcid *wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
return;
@@ -1418,8 +1412,6 @@ mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
return;
-
- wcid = NULL;
}
if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
@@ -1430,7 +1422,6 @@ mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
if (!dev->rx_ampdu_len ||
status->ampdu_ref != dev->rx_ampdu_ref) {
dev->rx_ampdu_status = *status;
- dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
dev->rx_ampdu_ref = status->ampdu_ref;
}
@@ -1448,7 +1439,7 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
struct ieee80211_sta *sta;
struct ieee80211_hw *hw;
- struct mt76_wcid *wcid = status->wcid;
+ struct mt76_wcid *wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
bool ps;
@@ -1456,8 +1447,10 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
!(status->flag & RX_FLAG_8023)) {
sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
- if (sta)
- wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
+ if (sta) {
+ wcid = (struct mt76_wcid *)sta->drv_priv;
+ status->wcid_idx = wcid->idx;
+ }
}
mt76_airtime_check(dev, skb);
@@ -1521,7 +1514,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
while ((skb = __skb_dequeue(frames)) != NULL) {
struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
- mt76_check_ccmp_pn(skb);
+ mt76_check_ccmp_pn(dev, skb);
skb_shinfo(skb)->frag_list = NULL;
mt76_rx_convert(dev, skb, &hw, &sta);
ieee80211_rx_list(hw, sta, skb, &list);
@@ -1563,7 +1556,7 @@ void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
mt76_npu_device_active(dev))
__skb_queue_tail(&frames, skb);
else
- mt76_rx_aggr_reorder(skb, &frames);
+ mt76_rx_aggr_reorder(dev, skb, &frames);
}
mt76_rx_complete(dev, &frames, napi);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 527bef97e122..fd449298fb11 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -364,6 +364,7 @@ enum mt76_wcid_flags {
};
#define MT76_N_WCIDS 1088
+#define MT76_WCID_IDX_INVALID 0xffff
#define MT76_BEACON_MON_MAX_MISS 7
/* stored in ieee80211_tx_info::hw_queue */
@@ -728,10 +729,7 @@ struct mt76_mmio {
};
struct mt76_rx_status {
- union {
- struct mt76_wcid *wcid;
u16 wcid_idx;
- };
u32 reorder_time;
@@ -1793,7 +1791,8 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
struct napi_struct *napi);
void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
struct napi_struct *napi);
-void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames);
+void mt76_rx_aggr_reorder(struct mt76_dev *dev, struct sk_buff *skb,
+ struct sk_buff_head *frames);
void mt76_testmode_tx_pending(struct mt76_phy *phy);
void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q,
struct mt76_queue_entry *e);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
index d3110eeb45d7..aeb890df808e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
@@ -513,6 +513,7 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
u32 rxd2 = le32_to_cpu(rxd[2]);
bool unicast = rxd1 & MT_RXD1_NORMAL_U2M;
bool insert_ccmp_hdr = false;
+ struct mt76_wcid *wcid;
bool remove_pad;
int idx;
int i;
@@ -524,7 +525,8 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
i >>= 1;
idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2);
- status->wcid = mt7603_rx_get_wcid(dev, idx, unicast);
+ wcid = mt7603_rx_get_wcid(dev, idx, unicast);
+ status->wcid_idx = wcid ? wcid->idx : MT76_WCID_IDX_INVALID;
status->band = sband->band;
if (i < sband->n_channels)
@@ -672,7 +674,7 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
}
hdr = (struct ieee80211_hdr *)skb->data;
- if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control))
+ if (!wcid || !ieee80211_is_data_qos(hdr->frame_control))
return 0;
status->aggr = unicast &&
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index ce0051468501..84be00a13930 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -246,17 +246,20 @@ static void mt7615_mac_fill_tm_rx(struct mt7615_phy *phy, __le32 *rxv)
}
/* The HW does not translate the mac header to 802.3 for mesh point */
-static int mt7615_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
+static int mt7615_reverse_frag0_hdr_trans(struct mt7615_dev *dev,
+ struct sk_buff *skb, u16 hdr_gap)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);
- struct mt7615_sta *msta = (struct mt7615_sta *)status->wcid;
__le32 *rxd = (__le32 *)skb->data;
struct ieee80211_sta *sta;
struct ieee80211_vif *vif;
struct ieee80211_hdr hdr;
+ struct mt7615_sta *msta;
u16 frame_control;
+ msta = (struct mt7615_sta *)mt76_wcid_ptr(dev, status->wcid_idx);
+
if (le32_get_bits(rxd[1], MT_RXD1_NORMAL_ADDR_TYPE) !=
MT_RXD1_NORMAL_U2M)
return -EINVAL;
@@ -335,6 +338,7 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
struct ieee80211_supported_band *sband;
struct ieee80211_hdr *hdr;
struct mt7615_phy *phy2;
+ struct mt76_wcid *wcid;
__le32 *rxd = (__le32 *)skb->data;
u32 rxd0 = le32_to_cpu(rxd[0]);
u32 rxd1 = le32_to_cpu(rxd[1]);
@@ -378,12 +382,13 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
unicast = (rxd1 & MT_RXD1_NORMAL_ADDR_TYPE) == MT_RXD1_NORMAL_U2M;
idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2);
- status->wcid = mt7615_rx_get_wcid(dev, idx, unicast);
+ wcid = mt7615_rx_get_wcid(dev, idx, unicast);
+ status->wcid_idx = wcid ? wcid->idx : MT76_WCID_IDX_INVALID;
- if (status->wcid) {
+ if (wcid) {
struct mt7615_sta *msta;
- msta = container_of(status->wcid, struct mt7615_sta, wcid);
+ msta = container_of(wcid, struct mt7615_sta, wcid);
mt76_wcid_add_poll(&dev->mt76, &msta->wcid);
}
@@ -590,7 +595,7 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
if (hdr_trans && ieee80211_has_morefrags(fc)) {
- if (mt7615_reverse_frag0_hdr_trans(skb, hdr_gap))
+ if (mt7615_reverse_frag0_hdr_trans(dev, skb, hdr_gap))
return -EINVAL;
hdr_trans = false;
} else {
@@ -638,7 +643,7 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
status->flag |= RX_FLAG_8023;
}
- if (!status->wcid || !ieee80211_is_data_qos(fc))
+ if (!wcid || !ieee80211_is_data_qos(fc))
return 0;
status->aggr = unicast &&
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
index 51423c7740bd..d9ae8d204442 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
@@ -448,7 +448,8 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev,
struct sk_buff *skb,
__le32 *rxv, u32 mode);
-int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif,
+int mt76_connac2_reverse_frag0_hdr_trans(struct mt76_dev *dev,
+ struct ieee80211_vif *vif,
struct sk_buff *skb, u16 hdr_offset);
int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev,
struct mt76_rx_status *status,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
index 0339e2e7ab60..376d59d517cc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
@@ -952,7 +952,8 @@ void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev,
EXPORT_SYMBOL_GPL(mt76_connac2_mac_decode_he_radiotap);
/* The HW does not translate the mac header to 802.3 for mesh point */
-int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif,
+int mt76_connac2_reverse_frag0_hdr_trans(struct mt76_dev *dev,
+ struct ieee80211_vif *vif,
struct sk_buff *skb, u16 hdr_offset)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
@@ -960,6 +961,7 @@ int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif,
__le32 *rxd = (__le32 *)skb->data;
struct ieee80211_sta *sta;
struct ieee80211_hdr hdr;
+ struct mt76_wcid *wcid;
u16 frame_control;
if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=
@@ -969,7 +971,13 @@ int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif,
if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))
return -EINVAL;
- sta = container_of((void *)status->wcid, struct ieee80211_sta, drv_priv);
+ wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
+ if (!wcid)
+ return -EINVAL;
+
+ sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
+ if (!sta)
+ return -EINVAL;
/* store the info from RXD and ethhdr to avoid being overridden */
frame_control = le32_get_bits(rxd[6], MT_RXD6_FRAME_CONTROL);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index cec2c4208255..30672713323f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -280,6 +280,7 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
u8 mode = 0, qos_ctl = 0;
struct mt7915_sta *msta = NULL;
u32 csum_status = *(u32 *)skb->cb;
+ struct mt76_wcid *wcid;
bool hdr_trans;
u16 hdr_gap;
u16 seq_ctrl = 0;
@@ -313,10 +314,13 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
- status->wcid = mt7915_rx_get_wcid(dev, idx, unicast);
- if (status->wcid) {
- msta = container_of(status->wcid, struct mt7915_sta, wcid);
+ wcid = mt7915_rx_get_wcid(dev, idx, unicast);
+
+ status->wcid_idx = wcid ? wcid->idx : MT76_WCID_IDX_INVALID;
+
+ if (wcid) {
+ msta = container_of(wcid, struct mt7915_sta, wcid);
mt76_wcid_add_poll(&dev->mt76, &msta->wcid);
}
@@ -475,7 +479,8 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
vif = container_of((void *)msta->vif, struct ieee80211_vif,
drv_priv);
- err = mt76_connac2_reverse_frag0_hdr_trans(vif, skb, hdr_gap);
+ err = mt76_connac2_reverse_frag0_hdr_trans(&dev->mt76, vif,
+ skb, hdr_gap);
if (err)
return err;
@@ -532,7 +537,8 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv, mode);
- if (!status->wcid || !ieee80211_is_data_qos(fc))
+ if (status->wcid_idx == MT76_WCID_IDX_INVALID ||
+ !ieee80211_is_data_qos(fc))
return 0;
status->aggr = unicast &&
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 03b4960db73f..59c64b951678 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -184,6 +184,7 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
u32 rxd4 = le32_to_cpu(rxd[4]);
struct mt792x_sta *msta = NULL;
struct mt792x_link_sta *mlink;
+ struct mt76_wcid *wcid;
u16 seq_ctrl = 0;
__le16 fc = 0;
u8 mode = 0;
@@ -211,10 +212,11 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3);
unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
- status->wcid = mt792x_rx_get_wcid(dev, idx, unicast);
+ wcid = mt792x_rx_get_wcid(dev, idx, unicast);
+ status->wcid_idx = wcid ? wcid->idx : MT76_WCID_IDX_INVALID;
- if (status->wcid) {
- mlink = container_of(status->wcid, struct mt792x_link_sta, wcid);
+ if (wcid) {
+ mlink = container_of(wcid, struct mt792x_link_sta, wcid);
msta = container_of(mlink, struct mt792x_sta, deflink);
mt76_wcid_add_poll(&dev->mt76, &mlink->wcid);
}
@@ -395,7 +397,8 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
vif = container_of((void *)msta->vif, struct ieee80211_vif,
drv_priv);
- err = mt76_connac2_reverse_frag0_hdr_trans(vif, skb, hdr_gap);
+ err = mt76_connac2_reverse_frag0_hdr_trans(&dev->mt76, vif,
+ skb, hdr_gap);
if (err)
return err;
@@ -433,7 +436,7 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv, mode);
- if (!status->wcid || !ieee80211_is_data_qos(fc))
+ if (!wcid || !ieee80211_is_data_qos(fc))
return 0;
status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index c47bd812b66b..e429f78596e2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -166,17 +166,20 @@ void mt7925_mac_set_fixed_rate_table(struct mt792x_dev *dev,
}
/* The HW does not translate the mac header to 802.3 for mesh point */
-static int mt7925_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
+static int mt7925_reverse_frag0_hdr_trans(struct mt792x_dev *dev,
+ struct sk_buff *skb, u16 hdr_gap)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);
- struct mt792x_sta *msta = (struct mt792x_sta *)status->wcid;
__le32 *rxd = (__le32 *)skb->data;
struct ieee80211_sta *sta;
struct ieee80211_vif *vif;
struct ieee80211_hdr hdr;
+ struct mt792x_sta *msta;
u16 frame_control;
+ msta = (struct mt792x_sta *)mt76_wcid_ptr(dev, status->wcid_idx);
+
if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=
MT_RXD3_NORMAL_U2M)
return -EINVAL;
@@ -368,6 +371,7 @@ mt7925_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
u32 rxd3 = le32_to_cpu(rxd[3]);
u32 rxd4 = le32_to_cpu(rxd[4]);
struct mt792x_link_sta *mlink;
+ struct mt76_wcid *wcid;
u8 mode = 0; /* , band_idx; */
u16 seq_ctrl = 0;
__le16 fc = 0;
@@ -392,10 +396,11 @@ mt7925_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3);
unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
- status->wcid = mt792x_rx_get_wcid(dev, idx, unicast);
+ wcid = mt792x_rx_get_wcid(dev, idx, unicast);
+ status->wcid_idx = wcid ? wcid->idx : MT76_WCID_IDX_INVALID;
- if (status->wcid) {
- mlink = container_of(status->wcid, struct mt792x_link_sta, wcid);
+ if (wcid) {
+ mlink = container_of(wcid, struct mt792x_link_sta, wcid);
mt76_wcid_add_poll(&dev->mt76, &mlink->wcid);
}
@@ -545,7 +550,7 @@ mt7925_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
if (hdr_trans && ieee80211_has_morefrags(fc)) {
- if (mt7925_reverse_frag0_hdr_trans(skb, hdr_gap))
+ if (mt7925_reverse_frag0_hdr_trans(dev, skb, hdr_gap))
return -EINVAL;
hdr_trans = false;
} else {
@@ -608,7 +613,7 @@ mt7925_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
}
}
- if (!status->wcid || !ieee80211_is_data_qos(fc))
+ if (!wcid || !ieee80211_is_data_qos(fc))
return 0;
status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index e2a83da3a09c..98c30957dd76 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -186,17 +186,19 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
}
/* The HW does not translate the mac header to 802.3 for mesh point */
-static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
+static int mt7996_reverse_frag0_hdr_trans(struct mt7996_dev *dev,
+ struct sk_buff *skb, u16 hdr_gap)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);
- struct mt7996_sta_link *msta_link = (void *)status->wcid;
- struct mt7996_sta *msta = msta_link->sta;
+ struct mt76_wcid *wcid = mt76_wcid_ptr(dev, status->wcid_idx);
+ struct mt7996_sta_link *msta_link;
struct ieee80211_bss_conf *link_conf;
__le32 *rxd = (__le32 *)skb->data;
struct ieee80211_sta *sta;
struct ieee80211_vif *vif;
struct ieee80211_hdr hdr;
+ struct mt7996_sta *msta;
u16 frame_control;
if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=
@@ -206,10 +208,16 @@ static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))
return -EINVAL;
+ if (!wcid)
+ return -EINVAL;
+
+ msta_link = container_of(wcid, struct mt7996_sta_link, wcid);
+ msta = msta_link->sta;
+
if (!msta || !msta->vif)
return -EINVAL;
- sta = wcid_to_sta(status->wcid);
+ sta = wcid_to_sta(wcid);
vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
link_conf = rcu_dereference(vif->link_conf[msta_link->wcid.link_id]);
if (!link_conf)
@@ -429,6 +437,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
bool unicast, insert_ccmp_hdr = false;
u8 remove_pad, amsdu_info, band_idx;
u8 mode = 0, qos_ctl = 0;
+ struct mt76_wcid *wcid;
bool hdr_trans;
u16 hdr_gap;
u16 seq_ctrl = 0;
@@ -461,12 +470,14 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
- status->wcid = mt7996_rx_get_wcid(dev, idx, band_idx);
- if (status->wcid) {
+ wcid = mt7996_rx_get_wcid(dev, idx, band_idx);
+ status->wcid_idx = wcid ? wcid->idx : MT76_WCID_IDX_INVALID;
+
+ if (wcid) {
struct mt7996_sta_link *msta_link;
- msta_link = container_of(status->wcid, struct mt7996_sta_link,
+ msta_link = container_of(wcid, struct mt7996_sta_link,
wcid);
msta = msta_link->sta;
mt76_wcid_add_poll(&dev->mt76, &msta_link->wcid);
@@ -620,7 +631,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
if (hdr_trans && ieee80211_has_morefrags(fc)) {
- if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap))
+ if (mt7996_reverse_frag0_hdr_trans(dev, skb, hdr_gap))
return -EINVAL;
hdr_trans = false;
} else {
@@ -697,7 +708,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
}
}
- if (!status->wcid || !ieee80211_is_data_qos(fc) || hw_aggr)
+ if (!wcid || !ieee80211_is_data_qos(fc) || hw_aggr)
return 0;
status->aggr = unicast &&
--
2.45.2
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] wifi: mt76: mt792x: fix use-after-free in mt76_rx_poll_complete
2026-04-30 8:45 [PATCH] wifi: mt76: mt792x: fix use-after-free in mt76_rx_poll_complete JB Tsai
@ 2026-05-04 19:26 ` Sean Wang
0 siblings, 0 replies; 2+ messages in thread
From: Sean Wang @ 2026-05-04 19:26 UTC (permalink / raw)
To: JB Tsai
Cc: nbd, lorenzo, linux-wireless, linux-mediatek, Deren.Wu, Sean.Wang,
Quan.Zhou, Ryder.Lee, Leon.Yen, litien.chang, eason.lai
Hi,
On Thu, Apr 30, 2026 at 3:50 AM JB Tsai <jb.tsai@mediatek.com> wrote:
>
> From: Eason Lai <Eason.Lai@mediatek.com>
>
> A use-after-free issue occurs in mt76_rx_poll_complete due to a race
> condition. The STA has already been removed, but the rx_status still
> had a pointer to the wcid in the STA.
>
> Use wcid_idx instead of storing the wcid pointer, and look up the wcid
> via rcu_dereference() by wcid_idx.
>
> BUG: KASAN: invalid-access in mt76_rx_poll_complete+0x280/0x470 [mt76]
> Call trace:
> dump_backtrace+0xec/0x128
> show_stack+0x18/0x28
> dump_stack_lvl+0x40/0xc8
> print_report+0x1b8/0x710
> kasan_report+0xe0/0x144
> do_bad_area+0x120/0x260
> do_tag_check_fault+0x20/0x34
> do_mem_abort+0x54/0xa8
> el1_abort+0x3c/0x5c
> el1h_64_sync_handler+0x40/0xcc
> el1h_64_sync+0x7c/0x80
> mt76_rx_poll_complete+0x280/0x470
> mt76_dma_rx_poll+0x114/0x51c
> mt792x_poll_rx+0x60/0xf8
> napi_threaded_poll_loop+0xe0/0x450
> napi_threaded_poll+0x80/0x9c
> kthread+0x11c/0x158
> ret_from_fork+0x10/0x20
>
This patch causes a build error:
mt76x02_mac.c: In function ‘mt76x02_mac_process_rx’:
mt76x02_mac.c:804:15: error: ‘struct mt76_rx_status’ has no member
named ‘wcid’
804 | status->wcid = mt76x02_rx_get_sta_wcid(sta, unicast);
| ^~
Please update the mt76x02 RX path as well, since mt76_rx_status no
longer carries a cached wcid pointer.
Also, after dropping the union:
struct mt76_rx_status {
- union {
- struct mt76_wcid *wcid;
u16 wcid_idx;
- };
};
wcid_idx should be shifted left by one tab to match the surrounding
structure indentation.
The underlying issue looks critical for mt76. The KASAN report shows a
use-after-free in mt76_rx_poll_complete() caused by keeping a stale WCID
pointer after the STA has already been removed. Using wcid_idx and doing
the WCID lookup under RCU is the right direction.
Please also add a proper Fixes tag and Cc stable, so this can be
backported to stable kernels.
> Signed-off-by: Eason Lai <Eason.Lai@mediatek.com>
> ---
> drivers/net/wireless/mediatek/mt76/agg-rx.c | 18 ++++---
> drivers/net/wireless/mediatek/mt76/mac80211.c | 47 ++++++++-----------
> drivers/net/wireless/mediatek/mt76/mt76.h | 7 ++-
> .../net/wireless/mediatek/mt76/mt7603/mac.c | 6 ++-
> .../net/wireless/mediatek/mt76/mt7615/mac.c | 19 +++++---
> .../net/wireless/mediatek/mt76/mt76_connac.h | 3 +-
> .../wireless/mediatek/mt76/mt76_connac_mac.c | 12 ++++-
> .../net/wireless/mediatek/mt76/mt7915/mac.c | 16 +++++--
> .../net/wireless/mediatek/mt76/mt7921/mac.c | 13 +++--
> .../net/wireless/mediatek/mt76/mt7925/mac.c | 19 +++++---
> .../net/wireless/mediatek/mt76/mt7996/mac.c | 29 ++++++++----
> 11 files changed, 114 insertions(+), 75 deletions(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c
> index bf1babac3895..b72d13975466 100644
> --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c
> +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c
> @@ -116,14 +116,15 @@ mt76_rx_aggr_reorder_work(struct work_struct *work)
> }
>
> static void
> -mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames)
> +mt76_rx_aggr_check_ctl(struct mt76_dev *dev, struct sk_buff *skb,
> + struct sk_buff_head *frames)
> {
> struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
> struct ieee80211_bar *bar = mt76_skb_get_hdr(skb);
> - struct mt76_wcid *wcid = status->wcid;
> struct mt76_rx_tid *tid;
> - u8 tidno;
> + struct mt76_wcid *wcid;
> u16 seqno;
> + u8 tidno;
>
> if (!ieee80211_is_ctl(bar->frame_control))
> return;
> @@ -131,6 +132,10 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames)
> if (!ieee80211_is_back_req(bar->frame_control))
> return;
>
> + wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
> + if (!wcid)
> + return;
> +
> status->qos_ctl = tidno = le16_to_cpu(bar->control) >> 12;
> seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num));
> tid = rcu_dereference(wcid->aggr[tidno]);
> @@ -145,10 +150,11 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames)
> spin_unlock_bh(&tid->lock);
> }
>
> -void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
> +void mt76_rx_aggr_reorder(struct mt76_dev *dev, struct sk_buff *skb,
> + struct sk_buff_head *frames)
> {
> struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
> - struct mt76_wcid *wcid = status->wcid;
> + struct mt76_wcid *wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
> struct ieee80211_sta *sta;
> struct mt76_rx_tid *tid;
> bool sn_less;
> @@ -164,7 +170,7 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
>
> if (!status->aggr) {
> if (!(status->flag & RX_FLAG_8023))
> - mt76_rx_aggr_check_ctl(skb, frames);
> + mt76_rx_aggr_check_ctl(dev, skb, frames);
> return;
> }
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
> index 4ae5e4715a9c..2933b29782d3 100644
> --- a/drivers/net/wireless/mediatek/mt76/mac80211.c
> +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
> @@ -1283,21 +1283,24 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
> memcpy(status->chain_signal, mstat.chain_signal,
> sizeof(mstat.chain_signal));
>
> - if (mstat.wcid) {
> - status->link_valid = mstat.wcid->link_valid;
> - status->link_id = mstat.wcid->link_id;
> - }
> + if (mstat.wcid_idx != MT76_WCID_IDX_INVALID) {
> + struct mt76_wcid *wcid = __mt76_wcid_ptr(dev, mstat.wcid_idx);
>
> - *sta = wcid_to_sta(mstat.wcid);
> + if (wcid) {
> + status->link_valid = wcid->link_valid;
> + status->link_id = wcid->link_id;
> + *sta = wcid_to_sta(wcid);
> + }
> + }
> *hw = mt76_phy_hw(dev, mstat.phy_idx);
> }
>
> static void
> -mt76_check_ccmp_pn(struct sk_buff *skb)
> +mt76_check_ccmp_pn(struct mt76_dev *dev, struct sk_buff *skb)
> {
> struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
> - struct mt76_wcid *wcid = status->wcid;
> struct ieee80211_hdr *hdr;
> + struct mt76_wcid *wcid;
> int security_idx;
> int ret;
>
> @@ -1307,6 +1310,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
> if (status->flag & RX_FLAG_ONLY_MONITOR)
> return;
>
> + wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
> if (!wcid || !wcid->rx_check_pn)
> return;
>
> @@ -1354,7 +1358,7 @@ static void
> mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
> int len)
> {
> - struct mt76_wcid *wcid = status->wcid;
> + struct mt76_wcid *wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
> struct ieee80211_rx_status info = {
> .enc_flags = status->enc_flags,
> .rate_idx = status->rate_idx,
> @@ -1382,19 +1386,9 @@ mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
> static void
> mt76_airtime_flush_ampdu(struct mt76_dev *dev)
> {
> - struct mt76_wcid *wcid;
> - int wcid_idx;
> -
> if (!dev->rx_ampdu_len)
> return;
>
> - wcid_idx = dev->rx_ampdu_status.wcid_idx;
> - if (wcid_idx < ARRAY_SIZE(dev->wcid))
> - wcid = rcu_dereference(dev->wcid[wcid_idx]);
> - else
> - wcid = NULL;
> - dev->rx_ampdu_status.wcid = wcid;
> -
> mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
>
> dev->rx_ampdu_len = 0;
> @@ -1405,7 +1399,7 @@ static void
> mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
> {
> struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
> - struct mt76_wcid *wcid = status->wcid;
> + struct mt76_wcid *wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
>
> if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
> return;
> @@ -1418,8 +1412,6 @@ mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
>
> if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
> return;
> -
> - wcid = NULL;
> }
>
> if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
> @@ -1430,7 +1422,6 @@ mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
> if (!dev->rx_ampdu_len ||
> status->ampdu_ref != dev->rx_ampdu_ref) {
> dev->rx_ampdu_status = *status;
> - dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
> dev->rx_ampdu_ref = status->ampdu_ref;
> }
>
> @@ -1448,7 +1439,7 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
> struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
> struct ieee80211_sta *sta;
> struct ieee80211_hw *hw;
> - struct mt76_wcid *wcid = status->wcid;
> + struct mt76_wcid *wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
> u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
> bool ps;
>
> @@ -1456,8 +1447,10 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
> if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
> !(status->flag & RX_FLAG_8023)) {
> sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
> - if (sta)
> - wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
> + if (sta) {
> + wcid = (struct mt76_wcid *)sta->drv_priv;
> + status->wcid_idx = wcid->idx;
> + }
> }
>
> mt76_airtime_check(dev, skb);
> @@ -1521,7 +1514,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
> while ((skb = __skb_dequeue(frames)) != NULL) {
> struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
>
> - mt76_check_ccmp_pn(skb);
> + mt76_check_ccmp_pn(dev, skb);
> skb_shinfo(skb)->frag_list = NULL;
> mt76_rx_convert(dev, skb, &hw, &sta);
> ieee80211_rx_list(hw, sta, skb, &list);
> @@ -1563,7 +1556,7 @@ void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
> mt76_npu_device_active(dev))
> __skb_queue_tail(&frames, skb);
> else
> - mt76_rx_aggr_reorder(skb, &frames);
> + mt76_rx_aggr_reorder(dev, skb, &frames);
> }
>
> mt76_rx_complete(dev, &frames, napi);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
> index 527bef97e122..fd449298fb11 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> @@ -364,6 +364,7 @@ enum mt76_wcid_flags {
> };
>
> #define MT76_N_WCIDS 1088
> +#define MT76_WCID_IDX_INVALID 0xffff
> #define MT76_BEACON_MON_MAX_MISS 7
>
> /* stored in ieee80211_tx_info::hw_queue */
> @@ -728,10 +729,7 @@ struct mt76_mmio {
> };
>
> struct mt76_rx_status {
> - union {
> - struct mt76_wcid *wcid;
> u16 wcid_idx;
> - };
>
> u32 reorder_time;
>
> @@ -1793,7 +1791,8 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
> struct napi_struct *napi);
> void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
> struct napi_struct *napi);
> -void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames);
> +void mt76_rx_aggr_reorder(struct mt76_dev *dev, struct sk_buff *skb,
> + struct sk_buff_head *frames);
> void mt76_testmode_tx_pending(struct mt76_phy *phy);
> void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q,
> struct mt76_queue_entry *e);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
> index d3110eeb45d7..aeb890df808e 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
> @@ -513,6 +513,7 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
> u32 rxd2 = le32_to_cpu(rxd[2]);
> bool unicast = rxd1 & MT_RXD1_NORMAL_U2M;
> bool insert_ccmp_hdr = false;
> + struct mt76_wcid *wcid;
> bool remove_pad;
> int idx;
> int i;
> @@ -524,7 +525,8 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
> i >>= 1;
>
> idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2);
> - status->wcid = mt7603_rx_get_wcid(dev, idx, unicast);
> + wcid = mt7603_rx_get_wcid(dev, idx, unicast);
> + status->wcid_idx = wcid ? wcid->idx : MT76_WCID_IDX_INVALID;
>
> status->band = sband->band;
> if (i < sband->n_channels)
> @@ -672,7 +674,7 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
> }
>
> hdr = (struct ieee80211_hdr *)skb->data;
> - if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control))
> + if (!wcid || !ieee80211_is_data_qos(hdr->frame_control))
> return 0;
>
> status->aggr = unicast &&
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
> index ce0051468501..84be00a13930 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
> @@ -246,17 +246,20 @@ static void mt7615_mac_fill_tm_rx(struct mt7615_phy *phy, __le32 *rxv)
> }
>
> /* The HW does not translate the mac header to 802.3 for mesh point */
> -static int mt7615_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
> +static int mt7615_reverse_frag0_hdr_trans(struct mt7615_dev *dev,
> + struct sk_buff *skb, u16 hdr_gap)
> {
> struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
> struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);
> - struct mt7615_sta *msta = (struct mt7615_sta *)status->wcid;
> __le32 *rxd = (__le32 *)skb->data;
> struct ieee80211_sta *sta;
> struct ieee80211_vif *vif;
> struct ieee80211_hdr hdr;
> + struct mt7615_sta *msta;
> u16 frame_control;
>
> + msta = (struct mt7615_sta *)mt76_wcid_ptr(dev, status->wcid_idx);
> +
> if (le32_get_bits(rxd[1], MT_RXD1_NORMAL_ADDR_TYPE) !=
> MT_RXD1_NORMAL_U2M)
> return -EINVAL;
> @@ -335,6 +338,7 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
> struct ieee80211_supported_band *sband;
> struct ieee80211_hdr *hdr;
> struct mt7615_phy *phy2;
> + struct mt76_wcid *wcid;
> __le32 *rxd = (__le32 *)skb->data;
> u32 rxd0 = le32_to_cpu(rxd[0]);
> u32 rxd1 = le32_to_cpu(rxd[1]);
> @@ -378,12 +382,13 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
>
> unicast = (rxd1 & MT_RXD1_NORMAL_ADDR_TYPE) == MT_RXD1_NORMAL_U2M;
> idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2);
> - status->wcid = mt7615_rx_get_wcid(dev, idx, unicast);
> + wcid = mt7615_rx_get_wcid(dev, idx, unicast);
> + status->wcid_idx = wcid ? wcid->idx : MT76_WCID_IDX_INVALID;
>
> - if (status->wcid) {
> + if (wcid) {
> struct mt7615_sta *msta;
>
> - msta = container_of(status->wcid, struct mt7615_sta, wcid);
> + msta = container_of(wcid, struct mt7615_sta, wcid);
> mt76_wcid_add_poll(&dev->mt76, &msta->wcid);
> }
>
> @@ -590,7 +595,7 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
>
> hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
> if (hdr_trans && ieee80211_has_morefrags(fc)) {
> - if (mt7615_reverse_frag0_hdr_trans(skb, hdr_gap))
> + if (mt7615_reverse_frag0_hdr_trans(dev, skb, hdr_gap))
> return -EINVAL;
> hdr_trans = false;
> } else {
> @@ -638,7 +643,7 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
> status->flag |= RX_FLAG_8023;
> }
>
> - if (!status->wcid || !ieee80211_is_data_qos(fc))
> + if (!wcid || !ieee80211_is_data_qos(fc))
> return 0;
>
> status->aggr = unicast &&
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
> index 51423c7740bd..d9ae8d204442 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
> @@ -448,7 +448,8 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
> void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev,
> struct sk_buff *skb,
> __le32 *rxv, u32 mode);
> -int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif,
> +int mt76_connac2_reverse_frag0_hdr_trans(struct mt76_dev *dev,
> + struct ieee80211_vif *vif,
> struct sk_buff *skb, u16 hdr_offset);
> int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev,
> struct mt76_rx_status *status,
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
> index 0339e2e7ab60..376d59d517cc 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
> @@ -952,7 +952,8 @@ void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev,
> EXPORT_SYMBOL_GPL(mt76_connac2_mac_decode_he_radiotap);
>
> /* The HW does not translate the mac header to 802.3 for mesh point */
> -int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif,
> +int mt76_connac2_reverse_frag0_hdr_trans(struct mt76_dev *dev,
> + struct ieee80211_vif *vif,
> struct sk_buff *skb, u16 hdr_offset)
> {
> struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
> @@ -960,6 +961,7 @@ int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif,
> __le32 *rxd = (__le32 *)skb->data;
> struct ieee80211_sta *sta;
> struct ieee80211_hdr hdr;
> + struct mt76_wcid *wcid;
> u16 frame_control;
>
> if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=
> @@ -969,7 +971,13 @@ int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif,
> if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))
> return -EINVAL;
>
> - sta = container_of((void *)status->wcid, struct ieee80211_sta, drv_priv);
> + wcid = __mt76_wcid_ptr(dev, status->wcid_idx);
> + if (!wcid)
> + return -EINVAL;
> +
> + sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
> + if (!sta)
> + return -EINVAL;
>
> /* store the info from RXD and ethhdr to avoid being overridden */
> frame_control = le32_get_bits(rxd[6], MT_RXD6_FRAME_CONTROL);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
> index cec2c4208255..30672713323f 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
> @@ -280,6 +280,7 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
> u8 mode = 0, qos_ctl = 0;
> struct mt7915_sta *msta = NULL;
> u32 csum_status = *(u32 *)skb->cb;
> + struct mt76_wcid *wcid;
> bool hdr_trans;
> u16 hdr_gap;
> u16 seq_ctrl = 0;
> @@ -313,10 +314,13 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
>
> unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
> idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
> - status->wcid = mt7915_rx_get_wcid(dev, idx, unicast);
>
> - if (status->wcid) {
> - msta = container_of(status->wcid, struct mt7915_sta, wcid);
> + wcid = mt7915_rx_get_wcid(dev, idx, unicast);
> +
> + status->wcid_idx = wcid ? wcid->idx : MT76_WCID_IDX_INVALID;
> +
> + if (wcid) {
> + msta = container_of(wcid, struct mt7915_sta, wcid);
> mt76_wcid_add_poll(&dev->mt76, &msta->wcid);
> }
>
> @@ -475,7 +479,8 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
>
> vif = container_of((void *)msta->vif, struct ieee80211_vif,
> drv_priv);
> - err = mt76_connac2_reverse_frag0_hdr_trans(vif, skb, hdr_gap);
> + err = mt76_connac2_reverse_frag0_hdr_trans(&dev->mt76, vif,
> + skb, hdr_gap);
> if (err)
> return err;
>
> @@ -532,7 +537,8 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
> if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
> mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv, mode);
>
> - if (!status->wcid || !ieee80211_is_data_qos(fc))
> + if (status->wcid_idx == MT76_WCID_IDX_INVALID ||
> + !ieee80211_is_data_qos(fc))
> return 0;
>
> status->aggr = unicast &&
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
> index 03b4960db73f..59c64b951678 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
> @@ -184,6 +184,7 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
> u32 rxd4 = le32_to_cpu(rxd[4]);
> struct mt792x_sta *msta = NULL;
> struct mt792x_link_sta *mlink;
> + struct mt76_wcid *wcid;
> u16 seq_ctrl = 0;
> __le16 fc = 0;
> u8 mode = 0;
> @@ -211,10 +212,11 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
> chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3);
> unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
> idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
> - status->wcid = mt792x_rx_get_wcid(dev, idx, unicast);
> + wcid = mt792x_rx_get_wcid(dev, idx, unicast);
> + status->wcid_idx = wcid ? wcid->idx : MT76_WCID_IDX_INVALID;
>
> - if (status->wcid) {
> - mlink = container_of(status->wcid, struct mt792x_link_sta, wcid);
> + if (wcid) {
> + mlink = container_of(wcid, struct mt792x_link_sta, wcid);
> msta = container_of(mlink, struct mt792x_sta, deflink);
> mt76_wcid_add_poll(&dev->mt76, &mlink->wcid);
> }
> @@ -395,7 +397,8 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
>
> vif = container_of((void *)msta->vif, struct ieee80211_vif,
> drv_priv);
> - err = mt76_connac2_reverse_frag0_hdr_trans(vif, skb, hdr_gap);
> + err = mt76_connac2_reverse_frag0_hdr_trans(&dev->mt76, vif,
> + skb, hdr_gap);
> if (err)
> return err;
>
> @@ -433,7 +436,7 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
> if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
> mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv, mode);
>
> - if (!status->wcid || !ieee80211_is_data_qos(fc))
> + if (!wcid || !ieee80211_is_data_qos(fc))
> return 0;
>
> status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
> index c47bd812b66b..e429f78596e2 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
> @@ -166,17 +166,20 @@ void mt7925_mac_set_fixed_rate_table(struct mt792x_dev *dev,
> }
>
> /* The HW does not translate the mac header to 802.3 for mesh point */
> -static int mt7925_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
> +static int mt7925_reverse_frag0_hdr_trans(struct mt792x_dev *dev,
> + struct sk_buff *skb, u16 hdr_gap)
> {
> struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
> struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);
> - struct mt792x_sta *msta = (struct mt792x_sta *)status->wcid;
> __le32 *rxd = (__le32 *)skb->data;
> struct ieee80211_sta *sta;
> struct ieee80211_vif *vif;
> struct ieee80211_hdr hdr;
> + struct mt792x_sta *msta;
> u16 frame_control;
>
> + msta = (struct mt792x_sta *)mt76_wcid_ptr(dev, status->wcid_idx);
> +
> if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=
> MT_RXD3_NORMAL_U2M)
> return -EINVAL;
> @@ -368,6 +371,7 @@ mt7925_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
> u32 rxd3 = le32_to_cpu(rxd[3]);
> u32 rxd4 = le32_to_cpu(rxd[4]);
> struct mt792x_link_sta *mlink;
> + struct mt76_wcid *wcid;
> u8 mode = 0; /* , band_idx; */
> u16 seq_ctrl = 0;
> __le16 fc = 0;
> @@ -392,10 +396,11 @@ mt7925_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
> chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3);
> unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
> idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
> - status->wcid = mt792x_rx_get_wcid(dev, idx, unicast);
> + wcid = mt792x_rx_get_wcid(dev, idx, unicast);
> + status->wcid_idx = wcid ? wcid->idx : MT76_WCID_IDX_INVALID;
>
> - if (status->wcid) {
> - mlink = container_of(status->wcid, struct mt792x_link_sta, wcid);
> + if (wcid) {
> + mlink = container_of(wcid, struct mt792x_link_sta, wcid);
> mt76_wcid_add_poll(&dev->mt76, &mlink->wcid);
> }
>
> @@ -545,7 +550,7 @@ mt7925_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
>
> hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
> if (hdr_trans && ieee80211_has_morefrags(fc)) {
> - if (mt7925_reverse_frag0_hdr_trans(skb, hdr_gap))
> + if (mt7925_reverse_frag0_hdr_trans(dev, skb, hdr_gap))
> return -EINVAL;
> hdr_trans = false;
> } else {
> @@ -608,7 +613,7 @@ mt7925_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
> }
> }
>
> - if (!status->wcid || !ieee80211_is_data_qos(fc))
> + if (!wcid || !ieee80211_is_data_qos(fc))
> return 0;
>
> status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
> index e2a83da3a09c..98c30957dd76 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
> @@ -186,17 +186,19 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
> }
>
> /* The HW does not translate the mac header to 802.3 for mesh point */
> -static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
> +static int mt7996_reverse_frag0_hdr_trans(struct mt7996_dev *dev,
> + struct sk_buff *skb, u16 hdr_gap)
> {
> struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
> struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);
> - struct mt7996_sta_link *msta_link = (void *)status->wcid;
> - struct mt7996_sta *msta = msta_link->sta;
> + struct mt76_wcid *wcid = mt76_wcid_ptr(dev, status->wcid_idx);
> + struct mt7996_sta_link *msta_link;
> struct ieee80211_bss_conf *link_conf;
> __le32 *rxd = (__le32 *)skb->data;
> struct ieee80211_sta *sta;
> struct ieee80211_vif *vif;
> struct ieee80211_hdr hdr;
> + struct mt7996_sta *msta;
> u16 frame_control;
>
> if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=
> @@ -206,10 +208,16 @@ static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
> if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))
> return -EINVAL;
>
> + if (!wcid)
> + return -EINVAL;
> +
> + msta_link = container_of(wcid, struct mt7996_sta_link, wcid);
> + msta = msta_link->sta;
> +
> if (!msta || !msta->vif)
> return -EINVAL;
>
> - sta = wcid_to_sta(status->wcid);
> + sta = wcid_to_sta(wcid);
> vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
> link_conf = rcu_dereference(vif->link_conf[msta_link->wcid.link_id]);
> if (!link_conf)
> @@ -429,6 +437,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
> bool unicast, insert_ccmp_hdr = false;
> u8 remove_pad, amsdu_info, band_idx;
> u8 mode = 0, qos_ctl = 0;
> + struct mt76_wcid *wcid;
> bool hdr_trans;
> u16 hdr_gap;
> u16 seq_ctrl = 0;
> @@ -461,12 +470,14 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
>
> unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
> idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
> - status->wcid = mt7996_rx_get_wcid(dev, idx, band_idx);
>
> - if (status->wcid) {
> + wcid = mt7996_rx_get_wcid(dev, idx, band_idx);
> + status->wcid_idx = wcid ? wcid->idx : MT76_WCID_IDX_INVALID;
> +
> + if (wcid) {
> struct mt7996_sta_link *msta_link;
>
> - msta_link = container_of(status->wcid, struct mt7996_sta_link,
> + msta_link = container_of(wcid, struct mt7996_sta_link,
> wcid);
> msta = msta_link->sta;
> mt76_wcid_add_poll(&dev->mt76, &msta_link->wcid);
> @@ -620,7 +631,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
>
> hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
> if (hdr_trans && ieee80211_has_morefrags(fc)) {
> - if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap))
> + if (mt7996_reverse_frag0_hdr_trans(dev, skb, hdr_gap))
> return -EINVAL;
> hdr_trans = false;
> } else {
> @@ -697,7 +708,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
> }
> }
>
> - if (!status->wcid || !ieee80211_is_data_qos(fc) || hw_aggr)
> + if (!wcid || !ieee80211_is_data_qos(fc) || hw_aggr)
> return 0;
>
> status->aggr = unicast &&
> --
> 2.45.2
>
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-05-04 19:26 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-30 8:45 [PATCH] wifi: mt76: mt792x: fix use-after-free in mt76_rx_poll_complete JB Tsai
2026-05-04 19:26 ` Sean Wang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox