]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - net/mac80211/scan.c
mac80211: reschedule sched scan after HW restart
[mirror_ubuntu-jammy-kernel.git] / net / mac80211 / scan.c
index ee6c8515f97b139620bb3dd1b4dbe85ae77b78ba..88c81616f8f758595e90cced1d503448ce6ba969 100644 (file)
@@ -971,8 +971,8 @@ out:
        mutex_unlock(&local->mtx);
 }
 
-int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
-                                      struct cfg80211_sched_scan_request *req)
+int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
+                                       struct cfg80211_sched_scan_request *req)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_sched_scan_ies sched_scan_ies = {};
@@ -982,17 +982,10 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
        iebufsz = 2 + IEEE80211_MAX_SSID_LEN +
                  local->scan_ies_len + req->ie_len;
 
-       mutex_lock(&local->mtx);
+       lockdep_assert_held(&local->mtx);
 
-       if (rcu_access_pointer(local->sched_scan_sdata)) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       if (!local->ops->sched_scan_start) {
-               ret = -ENOTSUPP;
-               goto out;
-       }
+       if (!local->ops->sched_scan_start)
+               return -ENOTSUPP;
 
        for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
                if (!local->hw.wiphy->bands[i])
@@ -1013,13 +1006,39 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
        }
 
        ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
-       if (ret == 0)
+       if (ret == 0) {
                rcu_assign_pointer(local->sched_scan_sdata, sdata);
+               local->sched_scan_req = req;
+       }
 
 out_free:
        while (i > 0)
                kfree(sched_scan_ies.ie[--i]);
-out:
+
+       if (ret) {
+               /* Clean in case of failure after HW restart or upon resume. */
+               rcu_assign_pointer(local->sched_scan_sdata, NULL);
+               local->sched_scan_req = NULL;
+       }
+
+       return ret;
+}
+
+int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
+                                      struct cfg80211_sched_scan_request *req)
+{
+       struct ieee80211_local *local = sdata->local;
+       int ret;
+
+       mutex_lock(&local->mtx);
+
+       if (rcu_access_pointer(local->sched_scan_sdata)) {
+               mutex_unlock(&local->mtx);
+               return -EBUSY;
+       }
+
+       ret = __ieee80211_request_sched_scan_start(sdata, req);
+
        mutex_unlock(&local->mtx);
        return ret;
 }
@@ -1036,6 +1055,9 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
                goto out;
        }
 
+       /* We don't want to restart sched scan anymore. */
+       local->sched_scan_req = NULL;
+
        if (rcu_access_pointer(local->sched_scan_sdata))
                drv_sched_scan_stop(local, sdata);
 
@@ -1070,6 +1092,9 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)
 
        rcu_assign_pointer(local->sched_scan_sdata, NULL);
 
+       /* If sched scan was aborted by the driver. */
+       local->sched_scan_req = NULL;
+
        mutex_unlock(&local->mtx);
 
        cfg80211_sched_scan_stopped(local->hw.wiphy);