]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mac80211: handle HW restart during ROC
authorJohannes Berg <johannes.berg@intel.com>
Thu, 23 May 2024 10:03:52 +0000 (12:03 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 29 May 2024 08:38:53 +0000 (10:38 +0200)
If we have a HW restart in the middle of a ROC period,
then there are two cases:
 - if it's a software ROC, we really don't need to do
   anything, since the ROC work will still be queued
   and will run later, albeit with the interruption
   due to the restart;
 - if it's a hardware ROC, then it may have begun or
   not, if it did begin already we can only remove it
   and tell userspace about that.

In both cases, this fixes the warning that would appear
in ieee80211_start_next_roc() in this case.

In the case of some drivers such as iwlwifi, the part of
restarting is never going to happen since the driver will
cancel the ROC, but flushing the work to ensure nothing
is pending here will also result in no longer being able
to trigger the warning in this case.

Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://msgid.link/20240523120352.f1924b5411ea.Ifc02a45a5ce23868dc7e428bad8d0e6996dd10f4@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/ieee80211_i.h
net/mac80211/offchannel.c
net/mac80211/util.c

index 76965d64a0faee2a8374c82a51c969aa453c17bc..3fd7b1adbfab1d16d329ee33a041c396a799a4b7 100644 (file)
@@ -1978,6 +1978,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local);
 void ieee80211_offchannel_return(struct ieee80211_local *local);
 void ieee80211_roc_setup(struct ieee80211_local *local);
 void ieee80211_start_next_roc(struct ieee80211_local *local);
+void ieee80211_reconfig_roc(struct ieee80211_local *local);
 void ieee80211_roc_purge(struct ieee80211_local *local,
                         struct ieee80211_sub_if_data *sdata);
 int ieee80211_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
index 65e1e9e971fd69893b5231185a397756a9d9bbf7..28d03196ef75a7c15f5244684c6d11202c96d9db 100644 (file)
@@ -8,7 +8,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2009      Johannes Berg <johannes@sipsolutions.net>
- * Copyright (C) 2019, 2022-2023 Intel Corporation
+ * Copyright (C) 2019, 2022-2024 Intel Corporation
  */
 #include <linux/export.h>
 #include <net/mac80211.h>
@@ -413,6 +413,39 @@ void ieee80211_start_next_roc(struct ieee80211_local *local)
        }
 }
 
+void ieee80211_reconfig_roc(struct ieee80211_local *local)
+{
+       struct ieee80211_roc_work *roc, *tmp;
+
+       /*
+        * In the software implementation can just continue with the
+        * interruption due to reconfig, roc_work is still queued if
+        * needed.
+        */
+       if (!local->ops->remain_on_channel)
+               return;
+
+       /* flush work so nothing from the driver is still pending */
+       wiphy_work_flush(local->hw.wiphy, &local->hw_roc_start);
+       wiphy_work_flush(local->hw.wiphy, &local->hw_roc_done);
+
+       list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
+               if (!roc->started)
+                       break;
+
+               if (!roc->hw_begun) {
+                       /* it didn't start in HW yet, so we can restart it */
+                       roc->started = false;
+                       continue;
+               }
+
+               /* otherwise destroy it and tell userspace */
+               ieee80211_roc_notify_destroy(roc);
+       }
+
+       ieee80211_start_next_roc(local);
+}
+
 static void __ieee80211_roc_work(struct ieee80211_local *local)
 {
        struct ieee80211_roc_work *roc;
index 43625ca87d5e8a4d1e9ee801e13619fa6a99c611..927f752a02093c167db6aa1ffe48ccd62fc97d5f 100644 (file)
@@ -2175,8 +2175,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                local->in_reconfig = false;
                barrier();
 
-               /* Restart deferred ROCs */
-               ieee80211_start_next_roc(local);
+               ieee80211_reconfig_roc(local);
 
                /* Requeue all works */
                list_for_each_entry(sdata, &local->interfaces, list)