]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: iwlwifi: mld: Fix primary link selection logic
authorNidhish A N <nidhish.a.n@intel.com>
Sun, 11 Jan 2026 17:39:14 +0000 (19:39 +0200)
committerSasha Levin <sashal@kernel.org>
Wed, 4 Mar 2026 12:20:27 +0000 (07:20 -0500)
[ Upstream commit 7a749db26cab2334d5b356ac31e6f1147c7682da ]

When assigning emlsr.primary with emlsr.selected_primary
we are checking if BIT(mld_vif->emlsr.selected_links) are
a part of vif->active_links. This is incorrect as
emlsr.selected_links is a bitmap of possibly two selected links.
Therefore, performing the BIT() operation on it does not
yield any meaningful result and almost always leads to
incorrect primary link selection.

Additionally, we cannot rely on vif->active_links at this
stage of the link switch flow because it contains both the
removed links and also the newly added links.
For example, if we had selected links in the past (0x11)
and we now select links because of TTLM/debugfs (0x100),
vif->active_links will now be (0x111) and primary link
will be 0, while 0 is not even an active link. Thus,
we create our own bitmap of final active links.

Signed-off-by: Nidhish A N <nidhish.a.n@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260111193638.38b2e14e3a20.Ie81a88dfff0c5d2becedabab8398702808f6b1bf@changeid
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c

index cd0dce8de85690df01f645a33439e326aaf14e31..3a1b5bfb9ed66d112114876103559ec6fb316a69 100644 (file)
@@ -984,7 +984,9 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw,
 {
        struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
        struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
-       unsigned int n_active = iwl_mld_count_active_links(mld, vif);
+       struct iwl_mld_link *temp_mld_link;
+       struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+       u16 final_active_links = 0;
        int ret;
 
        lockdep_assert_wiphy(mld->wiphy);
@@ -992,10 +994,7 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw,
        if (WARN_ON(!mld_link))
                return -EINVAL;
 
-       /* if the assigned one was not counted yet, count it now */
        if (!rcu_access_pointer(mld_link->chan_ctx)) {
-               n_active++;
-
                /* Track addition of non-BSS link */
                if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) {
                        ret = iwl_mld_emlsr_check_non_bss_block(mld, 1);
@@ -1016,17 +1015,25 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw,
 
        rcu_assign_pointer(mld_link->chan_ctx, ctx);
 
-       if (n_active > 1) {
-               struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+       /* We cannot rely on vif->active_links at this stage as it contains
+        * both the removed links and the newly added links.
+        * Therefore, we create our own bitmap of the final active links,
+        * which does not include the removed links.
+        */
+       for_each_mld_vif_valid_link(mld_vif, temp_mld_link) {
+               if (rcu_access_pointer(temp_mld_link->chan_ctx))
+                       final_active_links |= BIT(link_id);
+       }
 
+       if (hweight16(final_active_links) > 1) {
                /* Indicate to mac80211 that EML is enabled */
                vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE;
                mld_vif->emlsr.last_entry_ts = jiffies;
 
-               if (vif->active_links & BIT(mld_vif->emlsr.selected_links))
+               if (final_active_links == mld_vif->emlsr.selected_links)
                        mld_vif->emlsr.primary = mld_vif->emlsr.selected_primary;
                else
-                       mld_vif->emlsr.primary = __ffs(vif->active_links);
+                       mld_vif->emlsr.primary = __ffs(final_active_links);
 
                iwl_dbg_tlv_time_point(&mld->fwrt, IWL_FW_INI_TIME_ESR_LINK_UP,
                                       NULL);