]> git.ipfire.org Git - thirdparty/kernel/linux.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)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Wed, 21 Jan 2026 12:23:02 +0000 (14:23 +0200)
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
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c

index 8466345d7f219bc12d9fcf317138dfc913eb7464..411a2d56e5f0098cd948b8b238816e128d39d9fa 100644 (file)
@@ -1052,7 +1052,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);
@@ -1060,10 +1062,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);
@@ -1084,17 +1083,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);