* [PATCH] wifi: mt76: mt7925: fix mt7925_reverse_frag0_hdr_trans() for MLO
@ 2026-11-15 8:02 Ziheng Wei
2026-11-15 19:27 ` Zhao Li
0 siblings, 1 reply; 3+ messages in thread
From: Ziheng Wei @ 2026-11-15 8:02 UTC (permalink / raw)
To: Felix Fietkau, Lorenzo Bianconi
Cc: Ryder Lee, Shayne Chen, Sean Wang, linux-wireless,
linux-mediatek, linux-kernel, stable
For unicast frames mt792x_rx_get_wcid() returns the wcid of the
receiving link. Since commit 43aa4033eb18 ("wifi: mt76: mt7925: add
mt7925_change_sta_links") the wcid of a non-default station link is
embedded in a separately allocated struct mt792x_link_sta, not in
struct mt792x_sta. mt7925_reverse_frag0_hdr_trans() still casts
status->wcid to struct mt792x_sta and derives the ieee80211_sta from
it with container_of(), so for a frame received on such a link it
reads msta->vif past the end of the link allocation, dereferences the
result as a vif, and copies sta->addr from memory in front of it into
the rebuilt 802.11 header.
This path is taken for the first fragment of a header-translated
unicast frame, so it is reached when the AP sends fragmented data on
a secondary link while RX header translation is active there.
Do what commit a3ea1c309bf3 ("wifi: mt76: mt7996: Fix
mt7996_reverse_frag0_hdr_trans for MLO") did for mt7996: get the
station through the sta back pointer of the link and wcid_to_sta(),
and take the BSSID from the bss_conf of the receiving link.
Found by LLM-assisted source review. Not tested on hardware.
Fixes: 43aa4033eb18 ("wifi: mt76: mt7925: add mt7925_change_sta_links")
Cc: stable@vger.kernel.org
Signed-off-by: Ziheng Wei <zihengw03@163.com>
---
Notes:
The changelog was drafted with an AI assistant from my analysis;
I have reviewed the code, the fix and the text.
drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index 7af996abe..e00c04cf5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -184,7 +184,9 @@ static int mt7925_reverse_frag0_hdr_trans(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;
+ struct mt792x_link_sta *mlink = (struct mt792x_link_sta *)status->wcid;
+ struct mt792x_sta *msta = mlink ? mlink->sta : NULL;
+ struct ieee80211_bss_conf *link_conf;
__le32 *rxd = (__le32 *)skb->data;
struct ieee80211_sta *sta;
struct ieee80211_vif *vif;
@@ -201,8 +203,11 @@ static int mt7925_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
if (!msta || !msta->vif)
return -EINVAL;
- sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
+ sta = wcid_to_sta(status->wcid);
vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
+ link_conf = rcu_dereference(vif->link_conf[mlink->wcid.link_id]);
+ if (!sta || !link_conf)
+ return -EINVAL;
/* store the info from RXD and ethhdr to avoid being overridden */
frame_control = le32_get_bits(rxd[8], MT_RXD8_FRAME_CONTROL);
@@ -215,7 +220,7 @@ static int mt7925_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
switch (frame_control & (IEEE80211_FCTL_TODS |
IEEE80211_FCTL_FROMDS)) {
case 0:
- ether_addr_copy(hdr.addr3, vif->bss_conf.bssid);
+ ether_addr_copy(hdr.addr3, link_conf->bssid);
break;
case IEEE80211_FCTL_FROMDS:
ether_addr_copy(hdr.addr3, eth_hdr->h_source);
base-commit: 97d73c8251226cf27cc6656b4c542869bb8c69fa
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] wifi: mt76: mt7925: fix mt7925_reverse_frag0_hdr_trans() for MLO
2026-11-15 8:02 [PATCH] wifi: mt76: mt7925: fix mt7925_reverse_frag0_hdr_trans() for MLO Ziheng Wei
@ 2026-11-15 19:27 ` Zhao Li
2026-11-15 23:18 ` Ziheng Wei
0 siblings, 1 reply; 3+ messages in thread
From: Zhao Li @ 2026-11-15 19:27 UTC (permalink / raw)
To: Ziheng Wei
Cc: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
Sean Wang, linux-wireless, linux-mediatek, linux-kernel
Hi Ziheng,
On Sun, Nov 15, 2026 at 04:02:39PM +0800, Ziheng Wei wrote:
> - struct mt792x_sta *msta = (struct mt792x_sta *)status->wcid;
> + struct mt792x_link_sta *mlink = (struct mt792x_link_sta *)status->wcid;
> + struct mt792x_sta *msta = mlink ? mlink->sta : NULL;
The MLO part is right, but the cast still needs a guard, and the
MT_RXD3_NORMAL_U2M check below does not provide one: it selects the
unguarded path. mt7925_mac_fill_rx() computes unicast from the same
rxd3 comparison, so every frame that gets past that check arrived
through the one branch of mt792x_rx_get_wcid() that returns the WTBL
entry as it found it:
wcid = mt76_wcid_ptr(dev, idx);
if (unicast || !wcid)
return wcid;
if (!wcid->sta)
return NULL;
Not every entry is a station link. mt792x_init_wcid() reserves index 0
for beacons and management frames and installs dev->mt76.global_wcid
there, a bare struct mt76_wcid inside struct mt76_dev, immediately
followed by the wcid[] table. For that entry, mlink->sta reads at the
offset mt792x_link_sta keeps its back pointer at, which lands in that
table, and msta->vif then dereferences whatever it found, so the header
is still built from a type-confused object. I can't say whether the
hardware reports index 0 for a header-translated unicast fragment, but
the non-unicast path in the same helper already guards its container_of()
with wcid->sta.
Doing the same here keeps the conversion valid for every entry, with
mlink and msta left uninitialized in the declarations:
if (!status->wcid || !status->wcid->sta)
return -EINVAL;
mlink = container_of(status->wcid, struct mt792x_link_sta, wcid);
msta = mlink->sta;
if (!msta || !msta->vif)
return -EINVAL;
> + link_conf = rcu_dereference(vif->link_conf[mlink->wcid.link_id]);
> + if (!sta || !link_conf)
> + return -EINVAL;
With status->wcid->sta checked above, wcid_to_sta() cannot return NULL
here, so only !link_conf needs to be tested. The per-link BSSID lookup
matches what a3ea1c309bf3 did for mt7996.
Thanks,
Zhao
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] wifi: mt76: mt7925: fix mt7925_reverse_frag0_hdr_trans() for MLO
2026-11-15 19:27 ` Zhao Li
@ 2026-11-15 23:18 ` Ziheng Wei
0 siblings, 0 replies; 3+ messages in thread
From: Ziheng Wei @ 2026-11-15 23:18 UTC (permalink / raw)
To: Zhao Li
Cc: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
Sean Wang, linux-wireless, linux-mediatek, linux-kernel, stable
On Mon, Nov 16, 2026 at 03:27:25AM +0800, Zhao Li wrote:
> Not every entry is a station link. mt792x_init_wcid() reserves index 0
> for beacons and management frames and installs dev->mt76.global_wcid
> there, a bare struct mt76_wcid inside struct mt76_dev, immediately
> followed by the wcid[] table.
You're right, I missed that the unicast branch returns the entry unchecked.
Only station links set wcid->sta (mt7925_mac_link_sta_add() does, the
global wcid never does), so your check covers every entry. I'll send a
v2 with it and without the redundant !sta test.
Thanks for the review,
Ziheng
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-15 23:19 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-15 8:02 [PATCH] wifi: mt76: mt7925: fix mt7925_reverse_frag0_hdr_trans() for MLO Ziheng Wei
2026-11-15 19:27 ` Zhao Li
2026-11-15 23:18 ` Ziheng Wei
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®