]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 14 Jun 2022 14:53:54 +0000 (16:53 +0200)
commit b041b7b9de6e1d4362de855ab90f9d03ef323edd upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/mac80211/ieee80211_i.h
net/mac80211/scan.c

index 0d4f7258b243b732c4cbf1178758b128c3c7f856..7c8d77d899b6eebb8aff5f6c24cd39efc872d828 100644 (file)
@@ -1067,6 +1067,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,
@@ -1075,6 +1078,8 @@ enum {
        SCAN_COMPLETED,
        SCAN_ABORTED,
        SCAN_HW_CANCELLED,
+       SCAN_BEACON_WAIT,
+       SCAN_BEACON_DONE,
 };
 
 /**
index 47d2ed5704700f110aa6a0f57ecb5af29e0c5db9..dd9d7c4b7f2d12a65115062d770e2d36ae05b54c 100644 (file)
@@ -205,6 +205,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;
@@ -646,6 +656,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;
@@ -826,6 +838,8 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
            !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;
        }
 
@@ -918,6 +932,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
@@ -928,6 +944,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 */