Commit e4c9050a authored by Johannes Berg's avatar Johannes Berg

wifi: mac80211_hwsim: fix address translation for MLO

There are two issues here: we need to do the translation
even in case mac80211 selected a link, and we should only
translate the A3 if it's the BSSID. Fix both.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 1f638944
...@@ -1705,7 +1705,8 @@ static struct ieee80211_bss_conf * ...@@ -1705,7 +1705,8 @@ static struct ieee80211_bss_conf *
mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data, mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct ieee80211_hdr *hdr) struct ieee80211_hdr *hdr,
struct ieee80211_link_sta **link_sta)
{ {
struct hwsim_sta_priv *sp = (void *)sta->drv_priv; struct hwsim_sta_priv *sp = (void *)sta->drv_priv;
int i; int i;
...@@ -1724,30 +1725,20 @@ mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data, ...@@ -1724,30 +1725,20 @@ mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data,
return &vif->bss_conf; return &vif->bss_conf;
for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) {
struct ieee80211_link_sta *link_sta = NULL;
struct ieee80211_bss_conf *bss_conf; struct ieee80211_bss_conf *bss_conf;
unsigned int link_id; unsigned int link_id;
/* round-robin the available link IDs */ /* round-robin the available link IDs */
link_id = (sp->last_link + i + 1) % ARRAY_SIZE(vif->link_conf); link_id = (sp->last_link + i + 1) % ARRAY_SIZE(vif->link_conf);
link_sta = rcu_dereference(sta->link[link_id]); *link_sta = rcu_dereference(sta->link[link_id]);
if (!link_sta) if (!*link_sta)
continue; continue;
bss_conf = rcu_dereference(vif->link_conf[link_id]); bss_conf = rcu_dereference(vif->link_conf[link_id]);
if (WARN_ON_ONCE(!bss_conf)) if (WARN_ON_ONCE(!bss_conf))
continue; continue;
/* address translation to link addresses on TX */
ether_addr_copy(hdr->addr1, link_sta->addr);
ether_addr_copy(hdr->addr2, bss_conf->addr);
if (ether_addr_equal(hdr->addr3, sta->addr))
ether_addr_copy(hdr->addr3, link_sta->addr);
else if (ether_addr_equal(hdr->addr3, vif->addr))
ether_addr_copy(hdr->addr3, bss_conf->addr);
/* no need to look at A4, if present it's SA */
sp->last_link = link_id; sp->last_link = link_id;
return bss_conf; return bss_conf;
} }
...@@ -1780,23 +1771,46 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, ...@@ -1780,23 +1771,46 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
} else if (txi->hw_queue == 4) { } else if (txi->hw_queue == 4) {
channel = data->tmp_chan; channel = data->tmp_chan;
} else { } else {
struct ieee80211_bss_conf *bss_conf;
u8 link = u32_get_bits(IEEE80211_SKB_CB(skb)->control.flags, u8 link = u32_get_bits(IEEE80211_SKB_CB(skb)->control.flags,
IEEE80211_TX_CTRL_MLO_LINK); IEEE80211_TX_CTRL_MLO_LINK);
struct ieee80211_vif *vif = txi->control.vif;
struct ieee80211_link_sta *link_sta = NULL;
struct ieee80211_sta *sta = control->sta;
struct ieee80211_bss_conf *bss_conf;
if (link != IEEE80211_LINK_UNSPECIFIED) if (link != IEEE80211_LINK_UNSPECIFIED) {
bss_conf = rcu_dereference(txi->control.vif->link_conf[link]); bss_conf = rcu_dereference(txi->control.vif->link_conf[link]);
else if (sta)
bss_conf = mac80211_hwsim_select_tx_link(data, link_sta = rcu_dereference(sta->link[link]);
txi->control.vif, } else {
control->sta, bss_conf = mac80211_hwsim_select_tx_link(data, vif, sta,
hdr); hdr, &link_sta);
}
if (WARN_ON(!bss_conf)) { if (WARN_ON(!bss_conf)) {
ieee80211_free_txskb(hw, skb); ieee80211_free_txskb(hw, skb);
return; return;
} }
if (sta && sta->mlo) {
if (WARN_ON(!link_sta)) {
ieee80211_free_txskb(hw, skb);
return;
}
/* address translation to link addresses on TX */
ether_addr_copy(hdr->addr1, link_sta->addr);
ether_addr_copy(hdr->addr2, bss_conf->addr);
/* translate A3 only if it's the BSSID */
if (!ieee80211_has_tods(hdr->frame_control) &&
!ieee80211_has_fromds(hdr->frame_control)) {
if (ether_addr_equal(hdr->addr3, sta->addr))
ether_addr_copy(hdr->addr3, link_sta->addr);
else if (ether_addr_equal(hdr->addr3, vif->addr))
ether_addr_copy(hdr->addr3, bss_conf->addr);
}
/* no need to look at A4, if present it's SA */
}
chanctx_conf = rcu_dereference(bss_conf->chanctx_conf); chanctx_conf = rcu_dereference(bss_conf->chanctx_conf);
if (chanctx_conf) { if (chanctx_conf) {
channel = chanctx_conf->def.chan; channel = chanctx_conf->def.chan;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment