blob: 8a387a73d376efdf18b9f76aa30d6f6e1b50f444 [file] [log] [blame]
developerb8853042023-02-17 11:50:45 +08001From 4e7c861c971ca49ea162bd908fef6021a62b9018 Mon Sep 17 00:00:00 2001
developere1262222022-10-25 12:20:54 +08002From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Fri, 7 Oct 2022 10:46:29 +0800
developerb8853042023-02-17 11:50:45 +08004Subject: [PATCH 10/15] hostapd: mtk: Add DFS and ZWDFS support
developere1262222022-10-25 12:20:54 +08005
6Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
7---
8 hostapd/config_file.c | 4 ++
9 hostapd/ctrl_iface.c | 95 ++++++++++++++++++++++++++++++++++++
10 src/ap/ap_config.h | 13 +++++
11 src/ap/dfs.c | 35 +++++++------
12 src/ap/dfs.h | 15 ++++++
13 src/ap/hostapd.c | 4 +-
14 src/drivers/driver.h | 7 +++
15 src/drivers/driver_nl80211.c | 29 +++++++++++
16 src/drivers/nl80211_copy.h | 1 +
17 9 files changed, 186 insertions(+), 17 deletions(-)
18
19diff --git a/hostapd/config_file.c b/hostapd/config_file.c
developerb8853042023-02-17 11:50:45 +080020index 63c9d40be..cd1534952 100644
developere1262222022-10-25 12:20:54 +080021--- a/hostapd/config_file.c
22+++ b/hostapd/config_file.c
developerb8853042023-02-17 11:50:45 +080023@@ -4803,6 +4803,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
developerbdc8eab2022-11-21 11:36:55 +080024 } else if (os_strcmp(buf, "ibf_enable") == 0) { /*ibf setting is per device*/
25 int val = atoi(pos);
26 conf->ibf_enable = !!val;
developere1262222022-10-25 12:20:54 +080027+ } else if (os_strcmp(buf, "dfs_detect_mode") == 0) { /*bypass channel switch*/
28+ u8 en = strtol(pos, NULL, 10);
29+
30+ conf->dfs_detect_mode = en;
31 } else {
32 wpa_printf(MSG_ERROR,
33 "Line %d: unknown configuration item '%s'",
34diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
developerb8853042023-02-17 11:50:45 +080035index c881d3717..6ea1573b8 100644
developere1262222022-10-25 12:20:54 +080036--- a/hostapd/ctrl_iface.c
37+++ b/hostapd/ctrl_iface.c
developerbdc8eab2022-11-21 11:36:55 +080038@@ -3522,6 +3522,96 @@ hostapd_ctrl_iface_get_ibf(struct hostapd_data *hapd, char *buf,
developere1262222022-10-25 12:20:54 +080039 }
40
41
42+static int
43+hostapd_ctrl_iface_set_dfs_detect_mode(struct hostapd_data *hapd, char *value,
44+ char *buf, size_t buflen)
45+{
46+ u8 dfs_detect_mode;
47+
48+ if (!value)
49+ return -1;
50+
51+ dfs_detect_mode = strtol(value, NULL, 10);
52+ if (dfs_detect_mode > DFS_DETECT_MODE_MAX) {
53+ wpa_printf(MSG_ERROR, "Invalid value for dfs detect mode");
54+ return -1;
55+ }
56+ hapd->iconf->dfs_detect_mode = dfs_detect_mode;
57+
58+ return os_snprintf(buf, buflen, "OK\n");
59+}
60+
61+
62+static int
63+hostapd_ctrl_iface_set_offchan_ctrl(struct hostapd_data *hapd, char *cmd,
64+ char *buf, size_t buflen)
65+{
66+ struct hostapd_iface *iface = hapd->iface;
67+ char *pos, *param;
68+ enum hostapd_hw_mode hw_mode;
69+ bool chan_found = false;
70+ int i, num_available_chandefs, channel, chan_width, sec = 0;
71+ int sec_chan_idx_80p80 = -1;
72+ u8 oper_centr_freq_seg0_idx, oper_centr_freq_seg1_idx;
73+ struct hostapd_channel_data *chan;
74+ enum dfs_channel_type type = DFS_NO_CAC_YET;
75+
76+ param = os_strchr(cmd, ' ');
77+ if (!param)
78+ return -1;
79+ *param++ = '\0';
80+
81+ pos = os_strstr(param, "chan=");
82+ if (pos)
83+ channel = strtol(pos + 5, NULL, 10);
84+ else
85+ return -1;
86+
87+ num_available_chandefs = dfs_find_channel(iface, NULL, 0, type);
88+ for (i = 0; i < num_available_chandefs; i++) {
89+ dfs_find_channel(iface, &chan, i, type);
90+ if (chan->chan == channel) {
91+ chan_found = true;
92+ break;
93+ }
94+ }
95+
96+ if (!chan_found)
97+ return -1;
98+
99+ if (iface->conf->secondary_channel)
100+ sec = 1;
101+
102+ dfs_adjust_center_freq(iface, chan,
103+ sec,
104+ sec_chan_idx_80p80,
105+ &oper_centr_freq_seg0_idx,
106+ &oper_centr_freq_seg1_idx);
107+
108+ if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
109+ chan->freq, chan->chan,
110+ iface->conf->ieee80211n,
111+ iface->conf->ieee80211ac,
112+ iface->conf->ieee80211ax,
113+ iface->conf->ieee80211be,
114+ sec, hostapd_get_oper_chwidth(iface->conf),
115+ oper_centr_freq_seg0_idx,
116+ oper_centr_freq_seg1_idx, true)) {
117+ wpa_printf(MSG_ERROR, "DFS failed to start CAC offchannel");
118+ iface->radar_background.channel = -1;
119+ return -1;
120+ }
121+
122+ iface->radar_background.channel = chan->chan;
123+ iface->radar_background.freq = chan->freq;
124+ iface->radar_background.secondary_channel = sec;
125+ iface->radar_background.centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
126+ iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
127+
128+ return os_snprintf(buf, buflen, "OK\n");
129+}
130+
131+
132 static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
133 char *buf, char *reply,
134 int reply_size,
developerbdc8eab2022-11-21 11:36:55 +0800135@@ -4081,6 +4171,11 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
136 reply_len = hostapd_ctrl_iface_get_hemu(hapd, reply, reply_size);
137 } else if (os_strncmp(buf, "GET_IBF", 7) == 0) {
developere1262222022-10-25 12:20:54 +0800138 reply_len = hostapd_ctrl_iface_get_ibf(hapd, reply, reply_size);
developere1262222022-10-25 12:20:54 +0800139+ } else if (os_strncmp(buf, "DFS_DETECT_MODE ", 16) == 0) {
140+ reply_len = hostapd_ctrl_iface_set_dfs_detect_mode(hapd, buf + 16,
141+ reply, reply_size);
142+ } else if (os_strncmp(buf, "SET_OFFCHAN_CTRL", 16) == 0) {
143+ reply_len = hostapd_ctrl_iface_set_offchan_ctrl(hapd, buf + 16, reply, reply_size);
144 } else {
145 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
146 reply_len = 16;
147diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
developerb8853042023-02-17 11:50:45 +0800148index a9e3d2aeb..77f6169d2 100644
developere1262222022-10-25 12:20:54 +0800149--- a/src/ap/ap_config.h
150+++ b/src/ap/ap_config.h
developerb8853042023-02-17 11:50:45 +0800151@@ -1160,6 +1160,7 @@ struct hostapd_config {
developerbdc8eab2022-11-21 11:36:55 +0800152 int *edcca_threshold;
153 u8 three_wire_enable;
developere1262222022-10-25 12:20:54 +0800154 u8 ibf_enable;
developere1262222022-10-25 12:20:54 +0800155+ u8 dfs_detect_mode;
156 };
157
158 enum three_wire_mode {
developerb8853042023-02-17 11:50:45 +0800159@@ -1174,6 +1175,18 @@ enum three_wire_mode {
developere1262222022-10-25 12:20:54 +0800160 NUM_THREE_WIRE_MODE - 1
161 };
162
163+enum dfs_mode {
164+ DFS_DETECT_MODE_DISABLE,
165+ DFS_DETECT_MODE_AP_ENABLE,
166+ DFS_DETECT_MODE_BACKGROUND_ENABLE,
167+ DFS_DETECT_MODE_ALL_ENABLE,
168+
169+ /* keep last */
170+ NUM_DFS_DETECT_MODE,
171+ DFS_DETECT_MODE_MAX =
172+ NUM_DFS_DETECT_MODE - 1
173+};
174+
175 enum edcca_mode {
176 EDCCA_MODE_FORCE_DISABLE = 0,
177 EDCCA_MODE_AUTO = 1,
178diff --git a/src/ap/dfs.c b/src/ap/dfs.c
developerb8853042023-02-17 11:50:45 +0800179index b5d105d6a..1c3f6785b 100644
developere1262222022-10-25 12:20:54 +0800180--- a/src/ap/dfs.c
181+++ b/src/ap/dfs.c
182@@ -19,13 +19,6 @@
183 #include "dfs.h"
184 #include "crypto/crypto.h"
185
186-
187-enum dfs_channel_type {
188- DFS_ANY_CHANNEL,
189- DFS_AVAILABLE, /* non-radar or radar-available */
190- DFS_NO_CAC_YET, /* radar-not-yet-available */
191-};
192-
193 static struct hostapd_channel_data *
194 dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
195 u8 *oper_centr_freq_seg0_idx,
196@@ -238,9 +231,9 @@ static int is_in_chanlist(struct hostapd_iface *iface,
197 * - hapd->vht/he_oper_centr_freq_seg0_idx
198 * - hapd->vht/he_oper_centr_freq_seg1_idx
199 */
200-static int dfs_find_channel(struct hostapd_iface *iface,
201- struct hostapd_channel_data **ret_chan,
202- int idx, enum dfs_channel_type type)
203+int dfs_find_channel(struct hostapd_iface *iface,
204+ struct hostapd_channel_data **ret_chan,
205+ int idx, enum dfs_channel_type type)
206 {
207 struct hostapd_hw_modes *mode;
208 struct hostapd_channel_data *chan;
209@@ -299,12 +292,12 @@ static int dfs_find_channel(struct hostapd_iface *iface,
210 }
211
212
213-static void dfs_adjust_center_freq(struct hostapd_iface *iface,
214- struct hostapd_channel_data *chan,
215- int secondary_channel,
216- int sec_chan_idx_80p80,
217- u8 *oper_centr_freq_seg0_idx,
218- u8 *oper_centr_freq_seg1_idx)
219+void dfs_adjust_center_freq(struct hostapd_iface *iface,
220+ struct hostapd_channel_data *chan,
221+ int secondary_channel,
222+ int sec_chan_idx_80p80,
223+ u8 *oper_centr_freq_seg0_idx,
224+ u8 *oper_centr_freq_seg1_idx)
225 {
226 if (!iface->conf->ieee80211ac && !iface->conf->ieee80211ax)
227 return;
228@@ -1317,6 +1310,11 @@ hostapd_dfs_background_start_channel_switch(struct hostapd_iface *iface,
229 __func__, iface->radar_background.cac_started ? "yes" : "no",
230 hostapd_csa_in_progress(iface) ? "yes" : "no");
231
232+ /* Skip channel switch when background dfs detect mode is on */
233+ if (iface->conf->dfs_detect_mode == DFS_DETECT_MODE_BACKGROUND_ENABLE ||
234+ iface->conf->dfs_detect_mode == DFS_DETECT_MODE_ALL_ENABLE)
235+ return 0;
236+
237 /* Check if CSA in progress */
238 if (hostapd_csa_in_progress(iface))
239 return 0;
240@@ -1365,6 +1363,11 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
241 __func__, iface->cac_started ? "yes" : "no",
242 hostapd_csa_in_progress(iface) ? "yes" : "no");
243
244+ /* Skip channel switch when dfs detect mode is on */
245+ if (iface->conf->dfs_detect_mode == DFS_DETECT_MODE_AP_ENABLE ||
246+ iface->conf->dfs_detect_mode == DFS_DETECT_MODE_ALL_ENABLE)
247+ return 0;
248+
249 /* Check if CSA in progress */
250 if (hostapd_csa_in_progress(iface))
251 return 0;
252diff --git a/src/ap/dfs.h b/src/ap/dfs.h
developerb8853042023-02-17 11:50:45 +0800253index 606c1b393..c2556d2d9 100644
developere1262222022-10-25 12:20:54 +0800254--- a/src/ap/dfs.h
255+++ b/src/ap/dfs.h
256@@ -9,6 +9,12 @@
257 #ifndef DFS_H
258 #define DFS_H
259
260+enum dfs_channel_type {
261+ DFS_ANY_CHANNEL,
262+ DFS_AVAILABLE, /* non-radar or radar-available */
263+ DFS_NO_CAC_YET, /* radar-not-yet-available */
264+};
265+
266 int hostapd_handle_dfs(struct hostapd_iface *iface);
267
268 int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
269@@ -32,5 +38,14 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
270 int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
271 int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
272 int center_freq);
273+int dfs_find_channel(struct hostapd_iface *iface,
274+ struct hostapd_channel_data **ret_chan,
275+ int idx, enum dfs_channel_type type);
276+void dfs_adjust_center_freq(struct hostapd_iface *iface,
277+ struct hostapd_channel_data *chan,
278+ int secondary_channel,
279+ int sec_chan_idx_80p80,
280+ u8 *oper_centr_freq_seg0_idx,
281+ u8 *oper_centr_freq_seg1_idx);
282
283 #endif /* DFS_H */
284diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
developerb8853042023-02-17 11:50:45 +0800285index da7f7d87b..a0229c9ca 100644
developere1262222022-10-25 12:20:54 +0800286--- a/src/ap/hostapd.c
287+++ b/src/ap/hostapd.c
developerb8853042023-02-17 11:50:45 +0800288@@ -1464,7 +1464,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
developere1262222022-10-25 12:20:54 +0800289 return -1;
290 }
291
292- if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
293+ if (conf->start_disabled)
294+ hapd->driver->start_disabled(hapd->drv_priv);
295+ else if (ieee802_11_set_beacon(hapd) < 0)
296 return -1;
297
298 if (flush_old_stations && !conf->start_disabled &&
299diff --git a/src/drivers/driver.h b/src/drivers/driver.h
developerb8853042023-02-17 11:50:45 +0800300index 71ded617f..aa23fbdb3 100644
developere1262222022-10-25 12:20:54 +0800301--- a/src/drivers/driver.h
302+++ b/src/drivers/driver.h
developerbdc8eab2022-11-21 11:36:55 +0800303@@ -4720,6 +4720,13 @@ struct wpa_driver_ops {
304 *
305 */
306 int (*ibf_dump)(void *priv, u8 *ibf_enable);
developere1262222022-10-25 12:20:54 +0800307+
308+ /**
309+ * start_disabled - set start_disabled to cfg80211
310+ * @priv: Private driver interface data
311+ *
312+ */
313+ int (*start_disabled)(void *priv);
314 };
315
316 /**
317diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
developerb8853042023-02-17 11:50:45 +0800318index 5c2a291ca..7472542cc 100644
developere1262222022-10-25 12:20:54 +0800319--- a/src/drivers/driver_nl80211.c
320+++ b/src/drivers/driver_nl80211.c
developerbdc8eab2022-11-21 11:36:55 +0800321@@ -12776,6 +12776,34 @@ fail:
developere1262222022-10-25 12:20:54 +0800322 return -ENOBUFS;
323 }
324
325+static int nl80211_start_disabled(void *priv)
326+{
327+ struct i802_bss *bss = priv;
328+ struct wpa_driver_nl80211_data *drv = bss->drv;
329+ struct nl_msg *msg;
330+ struct nlattr *data;
331+ int ret;
332+
333+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_NEW_BEACON);
334+ if (!msg)
335+ goto fail;
336+
337+ if (nla_put_flag(msg, NL80211_ATTR_START_DISABLED))
338+ goto fail;
339+
340+ ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
341+
342+ if (ret)
343+ wpa_printf(MSG_ERROR, "Failed to set start_disabled. ret=%d (%s)",
344+ ret, strerror(-ret));
345+
346+ return ret;
347+
348+fail:
349+ nlmsg_free(msg);
350+ return ret;
351+}
352+
353 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
354 .name = "nl80211",
355 .desc = "Linux nl80211/cfg80211",
developerbdc8eab2022-11-21 11:36:55 +0800356@@ -12930,4 +12958,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
357 .three_wire_ctrl = nl80211_enable_three_wire,
358 .ibf_ctrl = nl80211_ibf_enable,
359 .ibf_dump = nl80211_ibf_dump,
developere1262222022-10-25 12:20:54 +0800360+ .start_disabled = nl80211_start_disabled,
361 };
362diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
developerb8853042023-02-17 11:50:45 +0800363index c4bf3ad35..79bc76c57 100644
developere1262222022-10-25 12:20:54 +0800364--- a/src/drivers/nl80211_copy.h
365+++ b/src/drivers/nl80211_copy.h
366@@ -3176,6 +3176,7 @@ enum nl80211_attrs {
367 NL80211_ATTR_EHT_CAPABILITY,
368
369 /* add attributes here, update the policy in nl80211.c */
370+ NL80211_ATTR_START_DISABLED = 999,
371
372 __NL80211_ATTR_AFTER_LAST,
373 NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
374--
developerb8853042023-02-17 11:50:45 +08003752.25.1
developere1262222022-10-25 12:20:54 +0800376