[PATCH] wifi: mt76: mt792x: fix use-after-free in mt76_rx_poll_complete
Sean Wang
sean.wang at kernel.org
Mon May 4 12:26:09 PDT 2026
Hi,
On Thu, Apr 30, 2026 at 3:50 AM JB Tsai <jb.tsai at mediatek.com> wrote:
>
> 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
>
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 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