summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mac80211_hwsim.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2022-07-14 21:58:00 +0200
committerJohannes Berg <johannes.berg@intel.com>2022-07-15 11:43:24 +0200
commitaf4f2aa35a4429f75e87c876e05fba84920a152e (patch)
tree639cf1b9017a6a3d51869310b43f1ed1bdd5aa1b /drivers/net/wireless/mac80211_hwsim.c
parent2ab60f49eb4d87998be602ca09c0e88b0808142b (diff)
downloadlinux-af4f2aa35a4429f75e87c876e05fba84920a152e.tar.bz2
wifi: mac80211_hwsim: fix TX link selection
Now that we have a pointer to the TX STA even when it's not authenticated/... yet, fix the TX link selection in hwsim to select only among the valid links for the STA, requiring a STA pointer here. Also implement a simple round-robin between links to make life more interesting. While at it, also consider A3 when translating to link addresses. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless/mac80211_hwsim.c')
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c47
1 files changed, 33 insertions, 14 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 36b8c95150ae..934939aa5fb6 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -228,6 +228,7 @@ static inline void hwsim_clear_magic(struct ieee80211_vif *vif)
struct hwsim_sta_priv {
u32 magic;
+ unsigned int last_link;
};
#define HWSIM_STA_MAGIC 0x6d537749
@@ -1706,30 +1707,48 @@ mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data,
struct ieee80211_sta *sta,
struct ieee80211_hdr *hdr)
{
+ struct hwsim_sta_priv *sp = (void *)sta->drv_priv;
int i;
+ if (!vif->valid_links)
+ return &vif->bss_conf;
+
+ /* FIXME: handle multicast TX properly */
+ if (is_multicast_ether_addr(hdr->addr1) || WARN_ON_ONCE(!sta)) {
+ unsigned int first_link = ffs(vif->valid_links) - 1;
+
+ return rcu_dereference(vif->link_conf[first_link]);
+ }
+
+ if (WARN_ON_ONCE(!sta->valid_links))
+ return &vif->bss_conf;
+
for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) {
struct ieee80211_link_sta *link_sta = NULL;
struct ieee80211_bss_conf *bss_conf;
+ unsigned int link_id;
+
+ /* round-robin the available link IDs */
+ link_id = (sp->last_link + i + 1) % ARRAY_SIZE(vif->link_conf);
- bss_conf = rcu_dereference(vif->link_conf[i]);
- if (!bss_conf)
+ link_sta = rcu_dereference(sta->link[link_id]);
+ if (!link_sta)
continue;
- if (sta) {
- link_sta = rcu_dereference(sta->link[i]);
- if (!link_sta)
- continue;
- }
+ bss_conf = rcu_dereference(vif->link_conf[link_id]);
+ if (WARN_ON_ONCE(!bss_conf))
+ continue;
- if (!is_multicast_ether_addr(hdr->addr1)) {
- if (link_sta)
- ether_addr_copy(hdr->addr1, link_sta->addr);
- ether_addr_copy(hdr->addr2, bss_conf->addr);
- } else {
- /* TODO: Handle multicast frames */
- }
+ /* 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;
return bss_conf;
}