blob: a37e541a264272f1ac4ef7a4a6a7e111b19d1374 [file] [log] [blame]
From 7f0f977e36718a7a827f7d78e6ab578d53aa630b Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Mon, 20 Feb 2023 14:56:55 +0800
Subject: [PATCH 039/104] mtk: hostapd: Add DFS offchan channel switch
Add DFS background chain channel switch command for testing purpose.
This feature is implemented via hostapd_cli command.
Command format:
hostapd_cli -i <interface> raw SET_OFFCHAN_CTRL chan=<dfs_channel>
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
hostapd/ctrl_iface.c | 72 ++++++++++++++++++++++++++++++++++++++++++++
src/ap/dfs.c | 25 ++++++---------
src/ap/dfs.h | 15 +++++++++
3 files changed, 96 insertions(+), 16 deletions(-)
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 71a87459c..68dcc7982 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -4154,6 +4154,76 @@ hostapd_ctrl_iface_set_dfs_detect_mode(struct hostapd_data *hapd, char *value,
}
+static int
+hostapd_ctrl_iface_set_offchan_ctrl(struct hostapd_data *hapd, char *cmd,
+ char *buf, size_t buflen)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ char *pos, *param;
+ enum hostapd_hw_mode hw_mode;
+ bool chan_found = false;
+ int i, num_available_chandefs, channel, chan_width, sec = 0;
+ int sec_chan_idx_80p80 = -1;
+ u8 oper_centr_freq_seg0_idx, oper_centr_freq_seg1_idx;
+ struct hostapd_channel_data *chan;
+ enum dfs_channel_type type = DFS_NO_CAC_YET;
+
+ param = os_strchr(cmd, ' ');
+ if (!param)
+ return -1;
+ *param++ = '\0';
+
+ pos = os_strstr(param, "chan=");
+ if (pos)
+ channel = strtol(pos + 5, NULL, 10);
+ else
+ return -1;
+
+ num_available_chandefs = dfs_find_channel(iface, NULL, 0, type);
+ for (i = 0; i < num_available_chandefs; i++) {
+ dfs_find_channel(iface, &chan, i, type);
+ if (chan->chan == channel) {
+ chan_found = true;
+ break;
+ }
+ }
+
+ if (!chan_found)
+ return -1;
+
+ if (iface->conf->secondary_channel)
+ sec = 1;
+
+ dfs_adjust_center_freq(iface, chan,
+ sec,
+ sec_chan_idx_80p80,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx);
+
+ if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+ chan->freq, chan->chan,
+ iface->conf->ieee80211n,
+ iface->conf->ieee80211ac,
+ iface->conf->ieee80211ax,
+ iface->conf->ieee80211be,
+ sec, hostapd_get_oper_chwidth(iface->conf),
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx, true)) {
+ wpa_printf(MSG_ERROR, "DFS failed to start CAC offchannel");
+ iface->radar_background.channel = -1;
+ return -1;
+ }
+
+ iface->radar_background.channel = chan->chan;
+ iface->radar_background.freq = chan->freq;
+ iface->radar_background.secondary_channel = sec;
+ iface->radar_background.centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
+ iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
+
+ return os_snprintf(buf, buflen, "OK\n");
+}
+
+
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
char *buf, char *reply,
int reply_size,
@@ -4770,6 +4840,8 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "DFS_DETECT_MODE ", 16) == 0) {
reply_len = hostapd_ctrl_iface_set_dfs_detect_mode(hapd, buf + 16,
reply, reply_size);
+ } else if (os_strncmp(buf, "SET_OFFCHAN_CTRL", 16) == 0) {
+ reply_len = hostapd_ctrl_iface_set_offchan_ctrl(hapd, buf + 16, reply, reply_size);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 1df4de6b8..ece27d070 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -19,13 +19,6 @@
#include "dfs.h"
#include "crypto/crypto.h"
-
-enum dfs_channel_type {
- DFS_ANY_CHANNEL,
- DFS_AVAILABLE, /* non-radar or radar-available */
- DFS_NO_CAC_YET, /* radar-not-yet-available */
-};
-
static struct hostapd_channel_data *
dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
u8 *oper_centr_freq_seg0_idx,
@@ -238,9 +231,9 @@ static int is_in_chanlist(struct hostapd_iface *iface,
* - hapd->vht/he_oper_centr_freq_seg0_idx
* - hapd->vht/he_oper_centr_freq_seg1_idx
*/
-static int dfs_find_channel(struct hostapd_iface *iface,
- struct hostapd_channel_data **ret_chan,
- int idx, enum dfs_channel_type type)
+int dfs_find_channel(struct hostapd_iface *iface,
+ struct hostapd_channel_data **ret_chan,
+ int idx, enum dfs_channel_type type)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan;
@@ -300,12 +293,12 @@ static int dfs_find_channel(struct hostapd_iface *iface,
}
-static void dfs_adjust_center_freq(struct hostapd_iface *iface,
- struct hostapd_channel_data *chan,
- int secondary_channel,
- int sec_chan_idx_80p80,
- u8 *oper_centr_freq_seg0_idx,
- u8 *oper_centr_freq_seg1_idx)
+void dfs_adjust_center_freq(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan,
+ int secondary_channel,
+ int sec_chan_idx_80p80,
+ u8 *oper_centr_freq_seg0_idx,
+ u8 *oper_centr_freq_seg1_idx)
{
if (!iface->conf->ieee80211ac && !iface->conf->ieee80211ax)
return;
diff --git a/src/ap/dfs.h b/src/ap/dfs.h
index 606c1b393..c2556d2d9 100644
--- a/src/ap/dfs.h
+++ b/src/ap/dfs.h
@@ -9,6 +9,12 @@
#ifndef DFS_H
#define DFS_H
+enum dfs_channel_type {
+ DFS_ANY_CHANNEL,
+ DFS_AVAILABLE, /* non-radar or radar-available */
+ DFS_NO_CAC_YET, /* radar-not-yet-available */
+};
+
int hostapd_handle_dfs(struct hostapd_iface *iface);
int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
@@ -32,5 +38,14 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
int center_freq);
+int dfs_find_channel(struct hostapd_iface *iface,
+ struct hostapd_channel_data **ret_chan,
+ int idx, enum dfs_channel_type type);
+void dfs_adjust_center_freq(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan,
+ int secondary_channel,
+ int sec_chan_idx_80p80,
+ u8 *oper_centr_freq_seg0_idx,
+ u8 *oper_centr_freq_seg1_idx);
#endif /* DFS_H */
--
2.39.2