[PATCH] wifi: mt76: mt792x: fix use-after-free in mt76_rx_poll_complete
JB Tsai
jb.tsai at mediatek.com
Thu Apr 30 01:45:25 PDT 2026
From: Eason Lai <Eason.Lai at 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 at 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
More information about the Linux-mediatek
mailing list