Allow non-MLD sta to roam between MLD AP links
v2 cover Allow non-MLD sta to roam between MLD AP links
This serie aims to allow non-MLD sta to roam between same MLD AP links as if they were two BSSs belonging to the same ESS.
The first issue is that when a non-MLD STA is connected to one MLD AP link all received management frames are reported to userland with the current associated link id even if STA sent those frames on one of the other links (e.g. offchannel probe request). Because hostapd relies on this link id information to select the proper link for answering those management frames, probe responses to offchannel requests are sent through the wrong link and the sta misses them.
To fix that, the first patch of this serie tries to match reported management frames link id with the received frequency. In case no suitable link is found, frames are reported without link information (link id == -1) and hostapd does the freq to link conversion to respond.
The second issue comes from the fact that hostapd queries a sta removal for the previous association even after the sta has successfully roamed to the new link, causing the current sta to be removed. To avoid that the second patch checks the sta removal link id parameter. If a link id is supplied and the sta is not currently using this link, this removal is ignored. An additionnal hostapd patch is needed so that a link id parameter is added with NL80211_CMD_DEL_STATION requests, and will be sent to hostapd mailing if it appears that this serie makes sense.
The third patch fixes the link id information initialization when tx frame with 802.11 HW offloading, this will be needed later to get sta roaming working with ath12k. An additionnal ath12k fix will also be provided in order to get non-MLD sta roaming working with this driver.
This serie along with the mentionned hostapd patch allowes a non-MLD STA to successfully roam between several MLD AP links with hwsim.
---
Changes v1 -> v2:
- Moving this serie as RFC. I am not fully satisfied with Patch 1/3 but can't find a leaner way to handle off channel mgmt frames.
Remi Pommarel (3):
wifi: mac80211: Get link_id from freq for received management frame
wifi: mac80211: Correctly init MLO link in ieee80211_8023_xmit()
wifi: mac80211: Check link id at station removal
net/mac80211/cfg.c | 3 ++- net/mac80211/rx.c | 41 ++++++++++++++++++++++++++++++++++++++++- net/mac80211/sta_info.c | 7 ++++++- net/mac80211/sta_info.h | 2 +- net/mac80211/tx.c | 2 ++ 5 files changed, 51 insertions(+), 4 deletions(-)
--
2.40.0
RFC v2 1/3 wifi: mac80211: Get link_id from freq for received management frame
A non-MLD sta could want to send offchannel management frame (e.g. to do a offchannel scan). Because ieee80211_rx_for_interface() fills the link_id information with the link the sta is currently using; hostapd would send back management frame responses through wrong link causing the sta to miss them.
To fix that, use link_id that matches the received frame frequency if any or do not fill link_id indication for management frames, relying on hostapd instead to infer the proper link from the received frame frequency.
--- net/mac80211/rx.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-)
net/mac80211/rx.c +40 -1
@@ -5114,6 +5114,37 @@ static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,dev_kfree_skb (skb); } +static int ieee80211_rx_get_link_from_freq (struct ieee80211_rx_data *rx, +struct sk_buff *skb, +struct link_sta_info *link_sta) +{ +struct ieee80211_rx_status *status =IEEE80211_SKB_RXCB (skb); +struct ieee80211_sta *sta = &link_sta->sta->sta; +struct ieee80211_link_data *link; +struct ieee80211_bss_conf *bss_conf; +struct ieee80211_chanctx_conf *conf; + +if (!status->freq) +return link_sta->link_id; + +for_each_link_data (rx->sdata, link) { + bss_conf = link->conf; +if (!bss_conf) +continue ; + conf =rcu_dereference (bss_conf->chanctx_conf); +if (!conf || !conf->def.chan) +continue ; + +if (conf->def.chan->center_freq != status->freq) +continue ; + +if (ieee80211_rx_is_valid_sta_link_id (sta, link->link_id)) +return link->link_id; + } + +return -1 ; +} +static bool ieee80211_rx_for_interface (struct ieee80211_rx_data *rx,struct sk_buff *skb,bool consume) {
@@ -5131,7 +5162,15 @@ static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx, link_sta =link_sta_info_get_bss (rx->sdata, hdr->addr2);if (link_sta) { sta = link_sta->sta; - link_id = link_sta->link_id; + +/* Use freq to get link id information on management frames to +* allow for offchannel scan, roaming, etc. +*/ +if (ieee80211_is_mgmt (hdr->frame_control)) + link_id =ieee80211_rx_get_link_from_freq (rx, skb, + link_sta); +else + link_id = link_sta->link_id; }else {struct ieee80211_rx_status *status =IEEE80211_SKB_RXCB (skb);
Signature · 1 line
2.40.0
Johannes Berg
maintainerRe: [RFC PACTH v2 wireless-next 1/3] wifi: mac80211: Get link_id from freq for received management frame
Quoted 5 lines · Remi Pommarel
net/mac80211/rx.c +4
-0+static int ieee80211_rx_get_link_from_freq (struct ieee80211_rx_data *rx, +struct sk_buff *skb, +struct link_sta_info *link_sta) +{
net/mac80211/rx.c static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw, · line 5130
Quoted 10 lines
net/mac80211/rx.c +10
-0+struct ieee80211_rx_status *status =IEEE80211_SKB_RXCB (skb); +struct ieee80211_sta *sta = &link_sta->sta->sta; +struct ieee80211_link_data *link; +struct ieee80211_bss_conf *bss_conf; +struct ieee80211_chanctx_conf *conf; + +if (!status->freq) +return link_sta->link_id; + +for_each_link_data (rx->sdata, link) {
..._rcu()
net/mac80211/rx.c static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw, · line 5143
Quoted 13 lines
net/mac80211/rx.c +13
-0+ bss_conf = link->conf; +if (!bss_conf) +continue ; + conf =rcu_dereference (bss_conf->chanctx_conf); +if (!conf || !conf->def.chan) +continue ; + +if (conf->def.chan->center_freq != status->freq) +continue ; + +if (ieee80211_rx_is_valid_sta_link_id (sta, link->link_id)) +return link->link_id; + }
But this is now almost the same as the code added via
https://patch.msgid.link/[email protected]
so I think it should be refactored/combined.
net/mac80211/rx.c static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx, · line 5171
Quoted 12 lines
net/mac80211/rx.c +7
-1@@ -5131,7 +5162,15 @@ static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx, link_sta =link_sta_info_get_bss (rx->sdata, hdr->addr2);if (link_sta) { sta = link_sta->sta; - link_id = link_sta->link_id; + +/* Use freq to get link id information on management frames to +* allow for offchannel scan, roaming, etc. +*/ +if (ieee80211_is_mgmt (hdr->frame_control)) + link_id =ieee80211_rx_get_link_from_freq (rx, skb, + link_sta);
It seems to me taht _iff_ the link ID ends up not being link_sta-
Quoted 1 line
link_idhere, we should set link_sta=NULL. Otherwise we think we're
actually receiving from that STA but we aren't really, and if we then use sta->link[link_id] we'd crash, and I'd be very surprised if this were impossible.
I'm not sure what consequences that has, but OTOH it really should not be sending anything other than probe requests, authentication frames and some few public action frames on another link. We need not handle other frames as if we didn't realise the link was different, it's fine to even just drop them because we don't recognise the STA there.
So I think that's what we should do. As written this seems really problematic to have a link_sta != NULL and thus sta != NULL but then sta->link[link_id] == NULL and not == link_sta.
Arguably, given the code we already have, we should perhaps implement this in another way and after doing the link_sta lookup via link_sta_info_get_bss() simply reject the link_sta (set it to NULL) if the RX link doesn't match the link it's expected to be on. Then we'd fall back to the existing code I linked to above anyway, which seems almost better.
johannes
RFC PATCH v2 2/3 wifi: mac80211: Correctly init MLO link in ieee80211_8023_xmit()
In reply to Remi PommarelThe IEEE80211_TX_CTRL_MLO_LINK info is the only part of ieee80211_tx_control where a 0 value has a specific meaning. Thus this should always be initialized with IEEE80211_LINK_UNSPECIFIED if there is no MLO link information associated with the skb, even using when 802.11 hw encap offloading.
--- net/mac80211/tx.c | 2 ++ 1 file changed, 2 insertions(+)
net/mac80211/tx.c +2 -0
@@ -4638,6 +4638,8 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata, info->flags |=IEEE80211_TX_CTL_HW_80211_ENCAP ; info->control.vif = &sdata->vif; + info->control.flags |=u32_encode_bits (IEEE80211_LINK_UNSPECIFIED , +IEEE80211_TX_CTRL_MLO_LINK );if (key) info->control.hw_key = &key->conf;
Signature · 1 line
2.40.0
Johannes Berg
maintainerRe: [RFC PATCH v2 wireless-next 2/3] wifi: mac80211: Correctly init MLO link in ieee80211_8023_xmit()
Quoted 5 lines · Remi Pommarel
The
IEEE80211_TX_CTRL_MLO_LINKinfo is the only part ofieee80211_tx_controlwhere a 0 value has a specific meaning. Thus this should always be initialized withIEEE80211_LINK_UNSPECIFIEDif there is no MLO link information associated with the skb, even using when 802.11 hw encap offloading.
I'm not against this and the patch looks fine, but I guess I'm surprised it even matters to anyone. The encap offloading fundamentally requires that the driver do more work to identify the destination STA, and then anyway the link is picked by driver/FW? Or is there a case of encap offload with _multicast_?
Anyway, looks OK and just sets a few bits that I feel like it's weird that they're even used, so doesn't matter :)
johannes
RFC PATCH v2 3/3 wifi: mac80211: Check link id at station removal
In reply to Remi Pommarelhostapd can remove a non-MLD sta connected to one link of one MLD AP several times. If the sta roamed to another link of the same MLD AP between two of those removals the wrong sta_info could be removed.
To fix that remove sta only if it is currently using the link specified in NL80211_CMD_DEL_STATION if they are any.
--- net/mac80211/cfg.c | 3 ++- net/mac80211/sta_info.c | 7 ++++++- net/mac80211/sta_info.h | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-)
net/mac80211/cfg.c +2 -1
@@ -2217,7 +2217,8 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, sdata =IEEE80211_DEV_TO_SUB_IF (dev);if (params->mac) -return sta_info_destroy_addr_bss (sdata, params->mac); +return sta_info_destroy_addr_bss (sdata, params->mac, + params->link_id);sta_info_flush (sdata, params->link_id);return 0 ;
net/mac80211/sta_info.c +6 -1
@@ -1579,13 +1579,18 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr) }int sta_info_destroy_addr_bss (struct ieee80211_sub_if_data *sdata, -const u8 *addr) +const u8 *addr,int link_id) {struct sta_info *sta;lockdep_assert_wiphy (sdata->local->hw.wiphy); sta =sta_info_get_bss (sdata, addr); + +if (sta && link_id >=0 && sta->sta.valid_links && + !(sta->sta.valid_links &BIT (link_id))) +return -EINVAL ; +return __sta_info_destroy (sta); }
net/mac80211/sta_info.h +1 -1
@@ -932,7 +932,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta);int sta_info_destroy_addr (struct ieee80211_sub_if_data *sdata,const u8 *addr);int sta_info_destroy_addr_bss (struct ieee80211_sub_if_data *sdata, -const u8 *addr); +const u8 *addr,int link_id);void sta_info_recalc_tim (struct sta_info *sta);
Signature · 1 line
2.40.0
Johannes Berg
maintainerRe: [RFC PATCH v2 wireless-next 3/3] wifi: mac80211: Check link id at station removal
Quoted 6 lines · Remi Pommarel
hostapd can remove a non-MLD sta connected to one link of one MLD AP several times. If the sta roamed to another link of the same MLD AP between two of those removals the wrong
sta_infocould be removed.To fix that remove sta only if it is currently using the link specified in
NL80211_CMD_DEL_STATIONif they are any.
That also looks fine.
Would be nice if you could later contribute the hwsim test for it, since it sounded like you had one :)
johannes