]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: mac80211: extend connection monitoring for MLO
authorMaharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
Fri, 18 Jul 2025 06:08:37 +0000 (11:38 +0530)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 18 Jul 2025 12:08:12 +0000 (14:08 +0200)
Currently, reset connection monitor (ieee80211_sta_reset_conn_monitor())
timer is handled only for non-AP non-MLD STA and do not support non-AP MLD
STA. The current implementation checks for the CSA active and update the
monitor timer with the timeout value of deflink and reset the timer based
on the deflink's timeout value else schedule the connection loss work when
the deflink is timed out and it won't work for the non-AP MLD STA.

Handle the reset connection monitor timer for non-AP MLD STA by updating
the monitor timer with the timeout value which is determined based on the
link that will expire last among all the links in MLO. If at least one link
has not timed out, the timer is updated accordingly with the latest timeout
value else schedule the connection loss work when all links have timed out.

Remove the MLO-related WARN_ON() checks in the beacon and connection
monitoring logic code paths as they support MLO now.

Signed-off-by: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250718060837.59371-5-maharaja.kennadyrajan@oss.qualcomm.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/mlme.c

index 86b69bd94b4c744bdfe9cdb8cca83a963cfa4d93..b4b7ea52c65e04cb841cde3d9f175e94b3c4a7dd 100644 (file)
@@ -4367,9 +4367,6 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
 
        lockdep_assert_wiphy(sdata->local->hw.wiphy);
 
-       if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif)))
-               return;
-
        /*
         * Try sending broadcast probe requests for the last three
         * probe requests after the first ones failed since some
@@ -4415,9 +4412,6 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
 
        lockdep_assert_wiphy(sdata->local->hw.wiphy);
 
-       if (WARN_ON_ONCE(ieee80211_vif_is_mld(&sdata->vif)))
-               return;
-
        if (!ieee80211_sdata_running(sdata))
                return;
 
@@ -8524,36 +8518,70 @@ static void ieee80211_sta_bcn_mon_timer(struct timer_list *t)
                         &sdata->u.mgd.beacon_connection_loss_work);
 }
 
+static unsigned long
+ieee80211_latest_active_link_conn_timeout(struct ieee80211_sub_if_data *sdata)
+{
+       unsigned long latest_timeout;
+       unsigned int link_id;
+       struct sta_info *sta;
+
+       guard(rcu)();
+
+       sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
+       if (!sta)
+               return 0;
+
+       for (link_id = 0; link_id < ARRAY_SIZE(sta->link);
+            link_id++) {
+               struct link_sta_info *link_sta;
+               unsigned long timeout;
+
+               link_sta = rcu_dereference(sta->link[link_id]);
+               if (!link_sta)
+                       continue;
+
+               timeout = link_sta->status_stats.last_ack;
+               if (time_before(timeout, link_sta->rx_stats.last_rx))
+                       timeout = link_sta->rx_stats.last_rx;
+
+               timeout += IEEE80211_CONNECTION_IDLE_TIME;
+
+               /*
+                * latest_timeout holds the timeout of the link
+                * that will expire last among all links in an
+                * non-AP MLD STA. This ensures that the connection
+                * monitor timer is only reset if at least one link
+                * is still active, and it is scheduled to fire at
+                * the latest possible timeout.
+                */
+               if (time_is_after_jiffies(timeout) &&
+                   time_after(timeout, latest_timeout))
+                       latest_timeout = timeout;
+       }
+
+       return latest_timeout;
+}
+
 static void ieee80211_sta_conn_mon_timer(struct timer_list *t)
 {
        struct ieee80211_sub_if_data *sdata =
                timer_container_of(sdata, t, u.mgd.conn_mon_timer);
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
-       struct sta_info *sta;
-       unsigned long timeout;
+       unsigned long latest_timeout;
 
-       if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif)))
-               return;
-
-       if (sdata->vif.bss_conf.csa_active &&
-           !sdata->deflink.u.mgd.csa.waiting_bcn)
-               return;
-
-       sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
-       if (!sta)
+       if (ieee80211_is_csa_in_progress(sdata))
                return;
 
-       timeout = sta->deflink.status_stats.last_ack;
-       if (time_before(sta->deflink.status_stats.last_ack, sta->deflink.rx_stats.last_rx))
-               timeout = sta->deflink.rx_stats.last_rx;
-       timeout += IEEE80211_CONNECTION_IDLE_TIME;
+       latest_timeout = ieee80211_latest_active_link_conn_timeout(sdata);
 
-       /* If timeout is after now, then update timer to fire at
+       /*
+        * If latest timeout is after now, then update timer to fire at
         * the later date, but do not actually probe at this time.
         */
-       if (time_is_after_jiffies(timeout)) {
-               mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout));
+       if (latest_timeout) {
+               mod_timer(&ifmgd->conn_mon_timer,
+                         round_jiffies_up(latest_timeout));
                return;
        }