mac80211: upgrade passive scan to active scan on DFS channels after beacon rx
authorFelix Fietkau <nbd@nbd.name>
Wed, 20 Apr 2022 10:49:07 +0000 (12:49 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 4 May 2022 20:49:38 +0000 (22:49 +0200)
In client mode, we can't connect to hidden SSID APs or SSIDs not advertised
in beacons on DFS channels, since we're forced to passive scan. Fix this by
sending out a probe request immediately after the first beacon, if active
scan was requested by the user.

Cc: stable@vger.kernel.org
Reported-by: Catrinel Catrinescu <cc@80211.de>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Link: https://lore.kernel.org/r/20220420104907.36275-1-nbd@nbd.name
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/ieee80211_i.h
net/mac80211/scan.c

index d4a7ba4..e58aa6f 100644 (file)
@@ -1148,6 +1148,9 @@ struct tpt_led_trigger {
  *     a scan complete for an aborted scan.
  * @SCAN_HW_CANCELLED: Set for our scan work function when the scan is being
  *     cancelled.
+ * @SCAN_BEACON_WAIT: Set whenever we're passive scanning because of radar/no-IR
+ *     and could send a probe request after receiving a beacon.
+ * @SCAN_BEACON_DONE: Beacon received, we can now send a probe request
  */
 enum {
        SCAN_SW_SCANNING,
@@ -1156,6 +1159,8 @@ enum {
        SCAN_COMPLETED,
        SCAN_ABORTED,
        SCAN_HW_CANCELLED,
+       SCAN_BEACON_WAIT,
+       SCAN_BEACON_DONE,
 };
 
 /**
index 5e6b275..b698756 100644 (file)
@@ -281,6 +281,16 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
        if (likely(!sdata1 && !sdata2))
                return;
 
+       if (test_and_clear_bit(SCAN_BEACON_WAIT, &local->scanning)) {
+               /*
+                * we were passive scanning because of radar/no-IR, but
+                * the beacon/proberesp rx gives us an opportunity to upgrade
+                * to active scan
+                */
+                set_bit(SCAN_BEACON_DONE, &local->scanning);
+                ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
+       }
+
        if (ieee80211_is_probe_resp(mgmt->frame_control)) {
                struct cfg80211_scan_request *scan_req;
                struct cfg80211_sched_scan_request *sched_scan_req;
@@ -787,6 +797,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
                                                IEEE80211_CHAN_RADAR)) ||
                    !req->n_ssids) {
                        next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+                       if (req->n_ssids)
+                               set_bit(SCAN_BEACON_WAIT, &local->scanning);
                } else {
                        ieee80211_scan_state_send_probe(local, &next_delay);
                        next_delay = IEEE80211_CHANNEL_TIME;
@@ -998,6 +1010,8 @@ set_channel:
            !scan_req->n_ssids) {
                *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
                local->next_scan_state = SCAN_DECISION;
+               if (scan_req->n_ssids)
+                       set_bit(SCAN_BEACON_WAIT, &local->scanning);
                return;
        }
 
@@ -1090,6 +1104,8 @@ void ieee80211_scan_work(struct work_struct *work)
                        goto out;
        }
 
+       clear_bit(SCAN_BEACON_WAIT, &local->scanning);
+
        /*
         * as long as no delay is required advance immediately
         * without scheduling a new work
@@ -1100,6 +1116,10 @@ void ieee80211_scan_work(struct work_struct *work)
                        goto out_complete;
                }
 
+               if (test_and_clear_bit(SCAN_BEACON_DONE, &local->scanning) &&
+                   local->next_scan_state == SCAN_DECISION)
+                       local->next_scan_state = SCAN_SEND_PROBE;
+
                switch (local->next_scan_state) {
                case SCAN_DECISION:
                        /* if no more bands/channels left, complete scan */