mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [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®