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 --- 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