]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mt76: mt7996: Implement MLD address translation for EAPOL
authorShayne Chen <shayne.chen@mediatek.com>
Thu, 4 Sep 2025 07:56:41 +0000 (09:56 +0200)
committerFelix Fietkau <nbd@nbd.name>
Mon, 15 Sep 2025 07:47:40 +0000 (09:47 +0200)
Do the MLD to link address translation for EAPOL frames in driver.

Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20250904-mt7996-mlo-more-fixes-v1-3-89d8fed67f20@kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7996/mac.c

index 45d621f5fe2210b30997a9001334627bd7d6e8bb..8a75d7a7b0c04d12db316e33c22ceadf3e1a61e4 100644 (file)
@@ -966,7 +966,8 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
        txwi[5] = cpu_to_le32(val);
 
        val = MT_TXD6_DAS;
-       if (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)
+       if ((q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0) ||
+           skb->protocol == cpu_to_be16(ETH_P_PAE))
                val |= MT_TXD6_DIS_MAT;
 
        if (is_mt7996(&dev->mt76))
@@ -1053,6 +1054,41 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
        if (id < 0)
                return id;
 
+       /* Since the rules of HW MLD address translation are not fully
+        * compatible with 802.11 EAPOL frame, we do the translation by
+        * software
+        */
+       if (tx_info->skb->protocol == cpu_to_be16(ETH_P_PAE) && sta->mlo) {
+               struct ieee80211_hdr *hdr = (void *)tx_info->skb->data;
+               struct ieee80211_bss_conf *link_conf;
+               struct ieee80211_link_sta *link_sta;
+
+               link_conf = rcu_dereference(vif->link_conf[wcid->link_id]);
+               if (!link_conf)
+                       return -EINVAL;
+
+               link_sta = rcu_dereference(sta->link[wcid->link_id]);
+               if (!link_sta)
+                       return -EINVAL;
+
+               dma_sync_single_for_cpu(mdev->dma_dev, tx_info->buf[1].addr,
+                                       tx_info->buf[1].len, DMA_TO_DEVICE);
+
+               memcpy(hdr->addr1, link_sta->addr, ETH_ALEN);
+               memcpy(hdr->addr2, link_conf->addr, ETH_ALEN);
+               if (ieee80211_has_a4(hdr->frame_control)) {
+                       memcpy(hdr->addr3, sta->addr, ETH_ALEN);
+                       memcpy(hdr->addr4, vif->addr, ETH_ALEN);
+               } else if (ieee80211_has_tods(hdr->frame_control)) {
+                       memcpy(hdr->addr3, sta->addr, ETH_ALEN);
+               } else if (ieee80211_has_fromds(hdr->frame_control)) {
+                       memcpy(hdr->addr3, vif->addr, ETH_ALEN);
+               }
+
+               dma_sync_single_for_device(mdev->dma_dev, tx_info->buf[1].addr,
+                                          tx_info->buf[1].len, DMA_TO_DEVICE);
+       }
+
        pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
        memset(txwi_ptr, 0, MT_TXD_SIZE);
        /* Transmit non qos data by 802.11 header and need to fill txd by host*/