]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
hostapd: Add support for DFS channels in CHAN_SWITCH
authorSergey Matyukevich <sergey.matyukevich.os@quantenna.com>
Tue, 28 Jan 2020 15:09:53 +0000 (15:09 +0000)
committerJouni Malinen <j@w1.fi>
Sun, 29 Mar 2020 18:15:16 +0000 (21:15 +0300)
Enable support for DFS channels in the CHAN_SWITCH command. Perform CAC
instead of CSA if DFS channel is selected. Then restart normal AP
operations.

Note that the current implementation provides a simplified approach. It
does not check if the selected DFS channel block is already in the
HOSTAPD_CHAN_DFS_AVAILABLE state. CAC procedure is restarted anyway.

Signed-off-by: Sergey Matyukevich <sergey.matyukevich.os@quantenna.com>
hostapd/ctrl_iface.c

index f35f87edc25c9d4e2837d276a951c07b4ddb0f5f..d90b5dc8fba26c02710d3cf38bd8792f6cd37af9 100644 (file)
@@ -59,6 +59,7 @@
 #include "ap/neighbor_db.h"
 #include "ap/rrm.h"
 #include "ap/dpp_hostapd.h"
+#include "ap/dfs.h"
 #include "wps/wps_defs.h"
 #include "wps/wps.h"
 #include "fst/fst_ctrl_iface.h"
@@ -2528,7 +2529,10 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
 #ifdef NEED_AP_MLME
        struct csa_settings settings;
        int ret;
+       int dfs_range = 0;
        unsigned int i;
+       int bandwidth;
+       u8 chan;
 
        ret = hostapd_parse_csa_settings(pos, &settings);
        if (ret)
@@ -2541,6 +2545,61 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
                return ret;
        }
 
+       switch (settings.freq_params.bandwidth) {
+       case 40:
+               bandwidth = CHAN_WIDTH_40;
+               break;
+       case 80:
+               if (settings.freq_params.center_freq2)
+                       bandwidth = CHAN_WIDTH_80P80;
+               else
+                       bandwidth = CHAN_WIDTH_80;
+               break;
+       case 160:
+               bandwidth = CHAN_WIDTH_160;
+               break;
+       default:
+               bandwidth = CHAN_WIDTH_20;
+               break;
+       }
+
+       if (settings.freq_params.center_freq1)
+               dfs_range += hostapd_is_dfs_overlap(
+                       iface, bandwidth, settings.freq_params.center_freq1);
+       else
+               dfs_range += hostapd_is_dfs_overlap(
+                       iface, bandwidth, settings.freq_params.freq);
+
+       if (settings.freq_params.center_freq2)
+               dfs_range += hostapd_is_dfs_overlap(
+                       iface, bandwidth, settings.freq_params.center_freq2);
+
+       if (dfs_range) {
+               ret = ieee80211_freq_to_chan(settings.freq_params.freq, &chan);
+               if (ret == NUM_HOSTAPD_MODES) {
+                       wpa_printf(MSG_ERROR,
+                                  "Failed to get channel for (freq=%d, sec_channel_offset=%d, bw=%d)",
+                                  settings.freq_params.freq,
+                                  settings.freq_params.sec_channel_offset,
+                                  settings.freq_params.bandwidth);
+                       return -1;
+               }
+
+               settings.freq_params.channel = chan;
+
+               wpa_printf(MSG_DEBUG,
+                          "DFS/CAC to (channel=%u, freq=%d, sec_channel_offset=%d, bw=%d, center_freq1=%d)",
+                          settings.freq_params.channel,
+                          settings.freq_params.freq,
+                          settings.freq_params.sec_channel_offset,
+                          settings.freq_params.bandwidth,
+                          settings.freq_params.center_freq1);
+
+               /* Perform CAC and switch channel */
+               hostapd_switch_channel_fallback(iface, &settings.freq_params);
+               return 0;
+       }
+
        for (i = 0; i < iface->num_bss; i++) {
 
                /* Save CHAN_SWITCH VHT config */