| From 88dd3df28e3736af4cca0daf4f7d19ab888ea6c4 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 11/16] hostapd: mtk: 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 0b4c234..6ea1573 100644 |
| --- a/hostapd/ctrl_iface.c |
| +++ b/hostapd/ctrl_iface.c |
| @@ -3542,6 +3542,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, |
| @@ -4104,6 +4174,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 5cb7799..1c3f678 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; |
| @@ -299,12 +292,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 606c1b3..c2556d2 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.18.0 |
| |