blob: 1d94fe0bb66b657c2e0096cf07fa22d0f8577e63 [file] [log] [blame]
developerc1498a32022-06-07 16:14:30 +08001From e1171aa4bd128d019fc5d53431472abddeb5cca0 Mon Sep 17 00:00:00 2001
2From: dzou <dzou@company.com>
3Date: Sun, 5 Jun 2022 23:20:30 +0800
4Subject: [PATCH 905/911] DFS: Configure background radar/CAC detection
5
6Introduce the capability to perform radar/CAC detection on an offchannel
7radar chain available on some hardware (e.g., mt7915). This feature
8allows to avoid CAC downtime switching on a different channel during CAC
9detection on the selected radar channel.
10
11Tested-by: Owen Peng <owen.peng@mediatek.com>
12Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
13---
14 src/ap/ap_drv_ops.c | 9 ++-
15 src/ap/ap_drv_ops.h | 3 +-
16 src/ap/dfs.c | 181 ++++++++++++++++++++++++++++++++++++++++----
17 src/ap/hostapd.h | 15 ++++
18 4 files changed, 189 insertions(+), 19 deletions(-)
19
20diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
21index 033ad097e..1fc538104 100644
22--- a/src/ap/ap_drv_ops.c
23+++ b/src/ap/ap_drv_ops.c
24@@ -810,7 +810,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
25 int channel, int ht_enabled, int vht_enabled,
26 int he_enabled,
27 int sec_channel_offset, int oper_chwidth,
28- int center_segment0, int center_segment1)
29+ int center_segment0, int center_segment1,
30+ bool radar_background)
31 {
32 struct hostapd_data *hapd = iface->bss[0];
33 struct hostapd_freq_params data;
34@@ -836,10 +837,14 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
35 wpa_printf(MSG_ERROR, "Can't set freq params");
36 return -1;
37 }
38+ data.radar_background = radar_background;
39
40 res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
41 if (!res) {
42- iface->cac_started = 1;
43+ if (radar_background)
44+ iface->radar_background.cac_started = 1;
45+ else
46+ iface->cac_started = 1;
47 os_get_reltime(&iface->dfs_cac_start);
48 }
49
50diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
51index 61c8f64eb..b4d6395ae 100644
52--- a/src/ap/ap_drv_ops.h
53+++ b/src/ap/ap_drv_ops.h
54@@ -130,7 +130,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
55 int channel, int ht_enabled, int vht_enabled,
56 int he_enabled,
57 int sec_channel_offset, int oper_chwidth,
58- int center_segment0, int center_segment1);
59+ int center_segment0, int center_segment1,
60+ bool radar_background);
61 int hostapd_drv_do_acs(struct hostapd_data *hapd);
62 int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
63 u16 reason_code, const u8 *ie, size_t ielen);
64diff --git a/src/ap/dfs.c b/src/ap/dfs.c
65index 05cb63ac4..5dc261589 100644
66--- a/src/ap/dfs.c
67+++ b/src/ap/dfs.c
68@@ -20,6 +20,25 @@
69 #include "crypto/crypto.h"
70
71
72+enum dfs_channel_type {
73+ DFS_ANY_CHANNEL,
74+ DFS_AVAILABLE, /* non-radar or radar-available */
75+ DFS_NO_CAC_YET, /* radar-not-yet-available */
76+};
77+
78+static struct hostapd_channel_data *
79+dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
80+ u8 *oper_centr_freq_seg0_idx,
81+ u8 *oper_centr_freq_seg1_idx,
82+ enum dfs_channel_type *channel_type);
83+
84+
85+static bool dfs_use_radar_background(struct hostapd_iface *iface)
86+{
87+ return iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND;
88+}
89+
90+
91 static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
92 {
93 int n_chans = 1;
94@@ -52,12 +71,6 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
95 }
96
97
98-enum dfs_channel_type {
99- DFS_ANY_CHANNEL,
100- DFS_AVAILABLE, /* non-radar or radar-available */
101- DFS_NO_CAC_YET, /* radar-not-yet-available */
102-};
103-
104 /* dfs_channel_available: select new channel according to type parameter */
105 static int dfs_channel_available(struct hostapd_channel_data *chan,
106 enum dfs_channel_type type)
107@@ -878,7 +891,8 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
108
109 /* Finally start CAC */
110 hostapd_set_state(iface, HAPD_IFACE_DFS);
111- wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
112+ wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz%s", iface->freq,
113+ dfs_use_radar_background(iface) ? " (background)" : "");
114 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
115 "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
116 iface->freq,
117@@ -895,13 +909,37 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
118 iface->conf->secondary_channel,
119 hostapd_get_oper_chwidth(iface->conf),
120 hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
121- hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
122+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
123+ dfs_use_radar_background(iface));
124
125 if (res) {
126 wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
127 return -1;
128 }
129
130+ if (dfs_use_radar_background(iface)) {
131+ /* Cache background radar parameters. */
132+ iface->radar_background.channel = iface->conf->channel;
133+ iface->radar_background.secondary_channel =
134+ iface->conf->secondary_channel;
135+ iface->radar_background.freq = iface->freq;
136+ iface->radar_background.centr_freq_seg0_idx =
137+ hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
138+ iface->radar_background.centr_freq_seg1_idx =
139+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf);
140+
141+ /*
142+ * Let's select a random channel according to the
143+ * regulations and perform CAC on dedicated radar chain.
144+ */
145+ res = dfs_set_valid_channel(iface, 1);
146+ if (res < 0)
147+ return res;
148+
149+ iface->radar_background.temp_ch = 1;
150+ return 1;
151+ }
152+
153 return 0;
154 }
155
156@@ -923,6 +961,86 @@ int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
157 }
158
159
160+static void hostpad_dfs_update_background_chain(struct hostapd_iface *iface)
161+{
162+ int sec = 0;
163+ enum dfs_channel_type channel_type = DFS_NO_CAC_YET;
164+ struct hostapd_channel_data *channel;
165+ u8 oper_centr_freq_seg0_idx = 0;
166+ u8 oper_centr_freq_seg1_idx = 0;
167+
168+ /*
169+ * Allow selection of DFS channel in ETSI to comply with
170+ * uniform spreading.
171+ */
172+ if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
173+ channel_type = DFS_ANY_CHANNEL;
174+
175+ channel = dfs_get_valid_channel(iface, &sec, &oper_centr_freq_seg0_idx,
176+ &oper_centr_freq_seg1_idx,
177+ channel_type);
178+ if (!channel ||
179+ channel->chan == iface->conf->channel ||
180+ channel->chan == iface->radar_background.channel)
181+ channel = dfs_downgrade_bandwidth(iface, &sec,
182+ &oper_centr_freq_seg0_idx,
183+ &oper_centr_freq_seg1_idx,
184+ &channel_type);
185+ if (!channel ||
186+ hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
187+ channel->freq, channel->chan,
188+ iface->conf->ieee80211n,
189+ iface->conf->ieee80211ac,
190+ iface->conf->ieee80211ax,
191+ sec, hostapd_get_oper_chwidth(iface->conf),
192+ oper_centr_freq_seg0_idx,
193+ oper_centr_freq_seg1_idx, true)) {
194+ wpa_printf(MSG_ERROR, "DFS failed to start CAC offchannel");
195+ iface->radar_background.channel = -1;
196+ return;
197+ }
198+
199+ iface->radar_background.channel = channel->chan;
200+ iface->radar_background.freq = channel->freq;
201+ iface->radar_background.secondary_channel = sec;
202+ iface->radar_background.centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
203+ iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
204+
205+ wpa_printf(MSG_DEBUG,
206+ "%s: setting background chain to chan %d (%d MHz)",
207+ __func__, channel->chan, channel->freq);
208+}
209+
210+
211+static bool
212+hostapd_dfs_is_background_event(struct hostapd_iface *iface, int freq)
213+{
214+ return dfs_use_radar_background(iface) &&
215+ iface->radar_background.channel != -1 &&
216+ iface->radar_background.freq == freq;
217+}
218+
219+
220+static int
221+hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface)
222+{
223+ iface->conf->channel = iface->radar_background.channel;
224+ iface->freq = iface->radar_background.freq;
225+ iface->conf->secondary_channel =
226+ iface->radar_background.secondary_channel;
227+ hostapd_set_oper_centr_freq_seg0_idx(
228+ iface->conf, iface->radar_background.centr_freq_seg0_idx);
229+ hostapd_set_oper_centr_freq_seg1_idx(
230+ iface->conf, iface->radar_background.centr_freq_seg1_idx);
231+
232+ hostpad_dfs_update_background_chain(iface);
233+ hostapd_disable_iface(iface);
234+ hostapd_enable_iface(iface);
235+
236+ return 0;
237+}
238+
239+
240 int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
241 int ht_enabled, int chan_offset, int chan_width,
242 int cf1, int cf2)
243@@ -943,6 +1061,22 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
244 set_dfs_state(iface, freq, ht_enabled, chan_offset,
245 chan_width, cf1, cf2,
246 HOSTAPD_CHAN_DFS_AVAILABLE);
247+
248+ /*
249+ * Radar event from background chain for the selected
250+ * channel. Perform CSA, move the main chain to the
251+ * selected channel and configure the background chain
252+ * to a new DFS channel.
253+ */
254+ if (hostapd_dfs_is_background_event(iface, freq)) {
255+ iface->radar_background.cac_started = 0;
256+ if (!iface->radar_background.temp_ch)
257+ return 0;
258+
259+ iface->radar_background.temp_ch = 0;
260+ return hostapd_dfs_start_channel_switch_background(iface);
261+ }
262+
263 /*
264 * Just mark the channel available when CAC completion
265 * event is received in enabled state. CAC result could
266@@ -959,6 +1093,9 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
267 iface->cac_started = 0;
268 }
269 }
270+ } else if (hostapd_dfs_is_background_event(iface, freq)) {
271+ iface->radar_background.cac_started = 0;
272+ hostpad_dfs_update_background_chain(iface);
273 }
274
275 return 0;
276@@ -1269,9 +1406,14 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
277 set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
278 cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
279
280- /* Handle cases where all channels were initially unavailable */
281- if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
282+ if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) {
283+ /* Handle cases where all channels were initially unavailable */
284 hostapd_handle_dfs(iface);
285+ } else if (dfs_use_radar_background(iface) &&
286+ iface->radar_background.channel == -1) {
287+ /* Reset radar background chain if disabled */
288+ hostpad_dfs_update_background_chain(iface);
289+ }
290
291 return 0;
292 }
293@@ -1309,17 +1451,24 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
294 int ht_enabled, int chan_offset, int chan_width,
295 int cf1, int cf2)
296 {
297- /* This is called when the driver indicates that an offloaded DFS has
298- * started CAC. */
299- hostapd_set_state(iface, HAPD_IFACE_DFS);
300+ if (hostapd_dfs_is_background_event(iface, freq)) {
301+ iface->radar_background.cac_started = 1;
302+ } else {
303+ /* This is called when the driver indicates that an offloaded
304+ * DFS has started CAC. */
305+ hostapd_set_state(iface, HAPD_IFACE_DFS);
306+ iface->cac_started = 1;
307+ }
308 /* TODO: How to check CAC time for ETSI weather channels? */
309 iface->dfs_cac_ms = 60000;
310 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
311 "freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
312- "seg1=%d cac_time=%ds",
313+ "seg1=%d cac_time=%ds%s",
314 freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
315- iface->dfs_cac_ms / 1000);
316- iface->cac_started = 1;
317+ iface->dfs_cac_ms / 1000,
318+ hostapd_dfs_is_background_event(iface, freq) ?
319+ " (background)" : "");
320+
321 os_get_reltime(&iface->dfs_cac_start);
322 return 0;
323 }
324diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
325index a4ea32517..095524e49 100644
326--- a/src/ap/hostapd.h
327+++ b/src/ap/hostapd.h
328@@ -541,6 +541,21 @@ struct hostapd_iface {
329 int *basic_rates;
330 int freq;
331
332+ /* Background radar configuration */
333+ struct {
334+ int channel;
335+ int secondary_channel;
336+ int freq;
337+ int centr_freq_seg0_idx;
338+ int centr_freq_seg1_idx;
339+ /* Main chain is on temporary channel during
340+ * CAC detection on radar offchain.
341+ */
342+ unsigned int temp_ch:1;
343+ /* CAC started on radar offchain */
344+ unsigned int cac_started:1;
345+ } radar_background;
346+
347 u16 hw_flags;
348
349 /* Number of associated Non-ERP stations (i.e., stations using 802.11b
350--
3512.29.2
352