wifi: mt76: route TDLS-peer frames as 3-addr non-DS in HW encap

With HW TX encap offload enabled, the mt76 firmware builds the 802.11
header for the 802.3 frame using the per-WCID context. For a STATION
vif the HDR_TRANS TLV currently sets ToDS=1, which makes the firmware
default to the BSSID as A1 and emit STA->AP-formatted frames
regardless of which peer the WCID points to.

For TDLS-paired peers this is wrong. Data frames go on air addressed
to the AP, the AP MAC-ACKs and silently drops them per IEEE 802.11z
(an AP must not forward to a TDLS-paired peer). Management and
control frames bypass the HW encap path and still reach the peer;
only user data fails.

Add MT_WCID_FLAG_TDLS_PEER, set it in mt7915, mt7921, mt7925 and
mt7996 sta-add paths when sta->tdls is true, and override the
HDR_TRANS TLV in mt76_connac_mcu_wtbl_hdr_trans_tlv() (Connac2 -
mt7915 / mt7921 / mt7922), mt7925_mcu_sta_hdr_trans_tlv() (mt7925)
and mt7996_mcu_sta_hdr_trans_tlv() (mt7996) to set ToDS=0, FromDS=0
when the flag is set. The 3-addr non-DS form matches what 802.11z
uses for direct links; the firmware then constructs the frame with
A1=peer rather than A1=BSSID. HW encap offload remains enabled for
AP and any non-TDLS traffic.

Verified on mt7925e + Samsung S938B over a 5 GHz HE 80 MHz channel
with iperf3 -t 30 to the TDLS peer:

  before fix:  over the TDLS direct link, 7 TDLS Setup action
               frames and 3 RTS frames reach the peer; 0 QoS
               Data frames make it through (mgmt/control paths
               bypass HW encap, the data path does not). iperf3
               stalls.
  after fix:   2.90 GBytes transferred at 830 Mbit/s sustained,
               0 TCP retransmits.

mt7915, mt7921, mt7922 and mt7996 are not regression-tested in this
change for lack of hardware. Their HDR_TRANS handling mirrors the
verified mt7925 change; the firmware behavior is shared across these
chips.

Signed-off-by: ElXreno <[email protected]>
Assisted-by: Claude:claude-opus-4-7 bpftrace tcpdump
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
ElXreno
2026-05-27 13:20:44 +02:00
committed by Felix Fietkau
parent dd1459c0c7
commit 6ae6f2b58c
8 changed files with 28 additions and 0 deletions
+1
View File
@@ -373,6 +373,7 @@ enum mt76_wcid_flags {
MT_WCID_FLAG_PS,
MT_WCID_FLAG_4ADDR,
MT_WCID_FLAG_HDR_TRANS,
MT_WCID_FLAG_TDLS_PEER,
};
#define MT76_N_WCIDS 1088
+5
View File
@@ -491,6 +491,11 @@ void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb,
htr->to_ds = true;
htr->from_ds = true;
}
if (test_bit(MT_WCID_FLAG_TDLS_PEER, &wcid->flags)) {
htr->to_ds = false;
htr->from_ds = false;
}
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_hdr_trans_tlv);
+3
View File
@@ -767,6 +767,9 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
msta->wcid.phy_idx = ext_phy;
msta->jiffies = jiffies;
if (sta->tdls)
set_bit(MT_WCID_FLAG_TDLS_PEER, &msta->wcid.flags);
ewma_avg_signal_init(&msta->avg_ack_signal);
mt7915_mac_wtbl_update(dev, idx,
+3
View File
@@ -828,6 +828,9 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
msta->deflink.last_txs = jiffies;
msta->deflink.sta = msta;
if (sta->tdls)
set_bit(MT_WCID_FLAG_TDLS_PEER, &msta->deflink.wcid.flags);
ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm);
if (ret)
return ret;
+3
View File
@@ -887,6 +887,9 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
mlink->wcid.link_valid = !!link_sta->sta->valid_links;
mlink->sta = msta;
if (link_sta->sta->tdls)
set_bit(MT_WCID_FLAG_TDLS_PEER, &mlink->wcid.flags);
wcid = &mlink->wcid;
ewma_signal_init(&wcid->rssi);
rcu_assign_pointer(dev->mt76.wcid[wcid->idx], wcid);
+5
View File
@@ -1091,6 +1091,11 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,
hdr_trans->to_ds = true;
hdr_trans->from_ds = true;
}
if (test_bit(MT_WCID_FLAG_TDLS_PEER, &wcid->flags)) {
hdr_trans->to_ds = false;
hdr_trans->from_ds = false;
}
}
int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev,
+3
View File
@@ -1162,6 +1162,9 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev,
msta_link->wcid.link_valid = !!sta->valid_links;
msta_link->wcid.def_wcid = &msta->deflink.wcid;
if (link_sta->sta->tdls)
set_bit(MT_WCID_FLAG_TDLS_PEER, &msta_link->wcid.flags);
ewma_avg_signal_init(&msta_link->avg_ack_signal);
ewma_signal_init(&msta_link->wcid.rssi);
+5
View File
@@ -2213,6 +2213,11 @@ mt7996_mcu_sta_hdr_trans_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
hdr_trans->from_ds = true;
hdr_trans->mesh = true;
}
if (test_bit(MT_WCID_FLAG_TDLS_PEER, &wcid->flags)) {
hdr_trans->to_ds = false;
hdr_trans->from_ds = false;
}
}
static enum mcu_mmps_mode