blob: 0030edc2a90f1271bb9d8d690dbf3d01bf39499b [file] [log] [blame]
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001/*
2 * ACS - Automatic Channel Selection module
3 * Copyright (c) 2011, Atheros Communications
4 * Copyright (c) 2013, Qualcomm Atheros, Inc.
5 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10#include "utils/includes.h"
11#include <math.h>
12
13#include "utils/common.h"
14#include "utils/list.h"
15#include "common/ieee802_11_defs.h"
Hai Shalom74f70d42019-02-11 14:42:39 -080016#include "common/hw_features_common.h"
Dmitry Shmidtcce06662013-11-04 18:44:24 -080017#include "common/wpa_ctrl.h"
Dmitry Shmidt391c59f2013-09-03 12:16:28 -070018#include "drivers/driver.h"
19#include "hostapd.h"
20#include "ap_drv_ops.h"
21#include "ap_config.h"
22#include "hw_features.h"
23#include "acs.h"
24
25/*
26 * Automatic Channel Selection
27 * ===========================
28 *
29 * More info at
30 * ------------
31 * http://wireless.kernel.org/en/users/Documentation/acs
32 *
33 * How to use
34 * ----------
35 * - make sure you have CONFIG_ACS=y in hostapd's .config
36 * - use channel=0 or channel=acs to enable ACS
37 *
38 * How does it work
39 * ----------------
40 * 1. passive scans are used to collect survey data
41 * (it is assumed that scan trigger collection of survey data in driver)
42 * 2. interference factor is calculated for each channel
43 * 3. ideal channel is picked depending on channel width by using adjacent
44 * channel interference factors
45 *
46 * Known limitations
47 * -----------------
48 * - Current implementation depends heavily on the amount of time willing to
49 * spend gathering survey data during hostapd startup. Short traffic bursts
50 * may be missed and a suboptimal channel may be picked.
51 * - Ideal channel may end up overlapping a channel with 40 MHz intolerant BSS
52 *
53 * Todo / Ideas
54 * ------------
55 * - implement other interference computation methods
56 * - BSS/RSSI based
57 * - spectral scan based
58 * (should be possibly to hook this up with current ACS scans)
59 * - add wpa_supplicant support (for P2P)
60 * - collect a histogram of interference over time allowing more educated
61 * guess about an ideal channel (perhaps CSA could be used to migrate AP to a
62 * new "better" channel while running)
63 * - include neighboring BSS scan to avoid conflicts with 40 MHz intolerant BSSs
64 * when choosing the ideal channel
65 *
66 * Survey interference factor implementation details
67 * -------------------------------------------------
68 * Generic interference_factor in struct hostapd_channel_data is used.
69 *
70 * The survey interference factor is defined as the ratio of the
71 * observed busy time over the time we spent on the channel,
72 * this value is then amplified by the observed noise floor on
73 * the channel in comparison to the lowest noise floor observed
74 * on the entire band.
75 *
76 * This corresponds to:
77 * ---
78 * (busy time - tx time) / (active time - tx time) * 2^(chan_nf + band_min_nf)
79 * ---
80 *
81 * The coefficient of 2 reflects the way power in "far-field"
82 * radiation decreases as the square of distance from the antenna [1].
83 * What this does is it decreases the observed busy time ratio if the
84 * noise observed was low but increases it if the noise was high,
85 * proportionally to the way "far field" radiation changes over
86 * distance.
87 *
88 * If channel busy time is not available the fallback is to use channel RX time.
89 *
90 * Since noise floor is in dBm it is necessary to convert it into Watts so that
91 * combined channel interference (e.g., HT40, which uses two channels) can be
92 * calculated easily.
93 * ---
94 * (busy time - tx time) / (active time - tx time) *
95 * 2^(10^(chan_nf/10) + 10^(band_min_nf/10))
96 * ---
97 *
98 * However to account for cases where busy/rx time is 0 (channel load is then
99 * 0%) channel noise floor signal power is combined into the equation so a
100 * channel with lower noise floor is preferred. The equation becomes:
101 * ---
102 * 10^(chan_nf/5) + (busy time - tx time) / (active time - tx time) *
103 * 2^(10^(chan_nf/10) + 10^(band_min_nf/10))
104 * ---
105 *
106 * All this "interference factor" is purely subjective and only time
107 * will tell how usable this is. By using the minimum noise floor we
108 * remove any possible issues due to card calibration. The computation
109 * of the interference factor then is dependent on what the card itself
110 * picks up as the minimum noise, not an actual real possible card
111 * noise value.
112 *
113 * Total interference computation details
114 * --------------------------------------
115 * The above channel interference factor is calculated with no respect to
116 * target operational bandwidth.
117 *
118 * To find an ideal channel the above data is combined by taking into account
119 * the target operational bandwidth and selected band. E.g., on 2.4 GHz channels
120 * overlap with 20 MHz bandwidth, but there is no overlap for 20 MHz bandwidth
121 * on 5 GHz.
122 *
123 * Each valid and possible channel spec (i.e., channel + width) is taken and its
124 * interference factor is computed by summing up interferences of each channel
125 * it overlaps. The one with least total interference is picked up.
126 *
127 * Note: This implies base channel interference factor must be non-negative
128 * allowing easy summing up.
129 *
130 * Example ACS analysis printout
131 * -----------------------------
132 *
133 * ACS: Trying survey-based ACS
134 * ACS: Survey analysis for channel 1 (2412 MHz)
135 * ACS: 1: min_nf=-113 interference_factor=0.0802469 nf=-113 time=162 busy=0 rx=13
136 * ACS: 2: min_nf=-113 interference_factor=0.0745342 nf=-113 time=161 busy=0 rx=12
137 * ACS: 3: min_nf=-113 interference_factor=0.0679012 nf=-113 time=162 busy=0 rx=11
138 * ACS: 4: min_nf=-113 interference_factor=0.0310559 nf=-113 time=161 busy=0 rx=5
139 * ACS: 5: min_nf=-113 interference_factor=0.0248447 nf=-113 time=161 busy=0 rx=4
140 * ACS: * interference factor average: 0.0557166
141 * ACS: Survey analysis for channel 2 (2417 MHz)
142 * ACS: 1: min_nf=-113 interference_factor=0.0185185 nf=-113 time=162 busy=0 rx=3
143 * ACS: 2: min_nf=-113 interference_factor=0.0246914 nf=-113 time=162 busy=0 rx=4
144 * ACS: 3: min_nf=-113 interference_factor=0.037037 nf=-113 time=162 busy=0 rx=6
145 * ACS: 4: min_nf=-113 interference_factor=0.149068 nf=-113 time=161 busy=0 rx=24
146 * ACS: 5: min_nf=-113 interference_factor=0.0248447 nf=-113 time=161 busy=0 rx=4
147 * ACS: * interference factor average: 0.050832
148 * ACS: Survey analysis for channel 3 (2422 MHz)
149 * ACS: 1: min_nf=-113 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0
150 * ACS: 2: min_nf=-113 interference_factor=0.0185185 nf=-113 time=162 busy=0 rx=3
151 * ACS: 3: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3
152 * ACS: 4: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3
153 * ACS: 5: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3
154 * ACS: * interference factor average: 0.0148838
155 * ACS: Survey analysis for channel 4 (2427 MHz)
156 * ACS: 1: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
157 * ACS: 2: min_nf=-114 interference_factor=0.0555556 nf=-114 time=162 busy=0 rx=9
158 * ACS: 3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0
159 * ACS: 4: min_nf=-114 interference_factor=0.0186335 nf=-114 time=161 busy=0 rx=3
160 * ACS: 5: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
161 * ACS: * interference factor average: 0.0160801
162 * ACS: Survey analysis for channel 5 (2432 MHz)
163 * ACS: 1: min_nf=-114 interference_factor=0.409938 nf=-113 time=161 busy=0 rx=66
164 * ACS: 2: min_nf=-114 interference_factor=0.0432099 nf=-113 time=162 busy=0 rx=7
165 * ACS: 3: min_nf=-114 interference_factor=0.0124224 nf=-113 time=161 busy=0 rx=2
166 * ACS: 4: min_nf=-114 interference_factor=0.677019 nf=-113 time=161 busy=0 rx=109
167 * ACS: 5: min_nf=-114 interference_factor=0.0186335 nf=-114 time=161 busy=0 rx=3
168 * ACS: * interference factor average: 0.232244
169 * ACS: Survey analysis for channel 6 (2437 MHz)
170 * ACS: 1: min_nf=-113 interference_factor=0.552795 nf=-113 time=161 busy=0 rx=89
171 * ACS: 2: min_nf=-113 interference_factor=0.0807453 nf=-112 time=161 busy=0 rx=13
172 * ACS: 3: min_nf=-113 interference_factor=0.0310559 nf=-113 time=161 busy=0 rx=5
173 * ACS: 4: min_nf=-113 interference_factor=0.434783 nf=-112 time=161 busy=0 rx=70
174 * ACS: 5: min_nf=-113 interference_factor=0.0621118 nf=-113 time=161 busy=0 rx=10
175 * ACS: * interference factor average: 0.232298
176 * ACS: Survey analysis for channel 7 (2442 MHz)
177 * ACS: 1: min_nf=-113 interference_factor=0.440994 nf=-112 time=161 busy=0 rx=71
178 * ACS: 2: min_nf=-113 interference_factor=0.385093 nf=-113 time=161 busy=0 rx=62
179 * ACS: 3: min_nf=-113 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6
180 * ACS: 4: min_nf=-113 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6
181 * ACS: 5: min_nf=-113 interference_factor=0.0745342 nf=-113 time=161 busy=0 rx=12
182 * ACS: * interference factor average: 0.195031
183 * ACS: Survey analysis for channel 8 (2447 MHz)
184 * ACS: 1: min_nf=-114 interference_factor=0.0496894 nf=-112 time=161 busy=0 rx=8
185 * ACS: 2: min_nf=-114 interference_factor=0.0496894 nf=-114 time=161 busy=0 rx=8
186 * ACS: 3: min_nf=-114 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6
187 * ACS: 4: min_nf=-114 interference_factor=0.12963 nf=-113 time=162 busy=0 rx=21
188 * ACS: 5: min_nf=-114 interference_factor=0.166667 nf=-114 time=162 busy=0 rx=27
189 * ACS: * interference factor average: 0.0865885
190 * ACS: Survey analysis for channel 9 (2452 MHz)
191 * ACS: 1: min_nf=-114 interference_factor=0.0124224 nf=-114 time=161 busy=0 rx=2
192 * ACS: 2: min_nf=-114 interference_factor=0.0310559 nf=-114 time=161 busy=0 rx=5
193 * ACS: 3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0
194 * ACS: 4: min_nf=-114 interference_factor=0.00617284 nf=-114 time=162 busy=0 rx=1
195 * ACS: 5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
196 * ACS: * interference factor average: 0.00993022
197 * ACS: Survey analysis for channel 10 (2457 MHz)
198 * ACS: 1: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
199 * ACS: 2: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
200 * ACS: 3: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
201 * ACS: 4: min_nf=-114 interference_factor=0.0493827 nf=-114 time=162 busy=0 rx=8
202 * ACS: 5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
203 * ACS: * interference factor average: 0.0136033
204 * ACS: Survey analysis for channel 11 (2462 MHz)
205 * ACS: 1: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0
206 * ACS: 2: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=161 busy=0 rx=0
207 * ACS: 3: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=161 busy=0 rx=0
208 * ACS: 4: min_nf=-114 interference_factor=0.0432099 nf=-114 time=162 busy=0 rx=7
209 * ACS: 5: min_nf=-114 interference_factor=0.0925926 nf=-114 time=162 busy=0 rx=15
210 * ACS: * interference factor average: 0.0271605
211 * ACS: Survey analysis for channel 12 (2467 MHz)
212 * ACS: 1: min_nf=-114 interference_factor=0.0621118 nf=-113 time=161 busy=0 rx=10
213 * ACS: 2: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
214 * ACS: 3: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0
215 * ACS: 4: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0
216 * ACS: 5: min_nf=-114 interference_factor=0.00617284 nf=-113 time=162 busy=0 rx=1
217 * ACS: * interference factor average: 0.0148992
218 * ACS: Survey analysis for channel 13 (2472 MHz)
219 * ACS: 1: min_nf=-114 interference_factor=0.0745342 nf=-114 time=161 busy=0 rx=12
220 * ACS: 2: min_nf=-114 interference_factor=0.0555556 nf=-114 time=162 busy=0 rx=9
221 * ACS: 3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
222 * ACS: 4: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
223 * ACS: 5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
224 * ACS: * interference factor average: 0.0260179
225 * ACS: Survey analysis for selected bandwidth 20MHz
226 * ACS: * channel 1: total interference = 0.121432
227 * ACS: * channel 2: total interference = 0.137512
228 * ACS: * channel 3: total interference = 0.369757
229 * ACS: * channel 4: total interference = 0.546338
230 * ACS: * channel 5: total interference = 0.690538
231 * ACS: * channel 6: total interference = 0.762242
232 * ACS: * channel 7: total interference = 0.756092
233 * ACS: * channel 8: total interference = 0.537451
234 * ACS: * channel 9: total interference = 0.332313
235 * ACS: * channel 10: total interference = 0.152182
236 * ACS: * channel 11: total interference = 0.0916111
237 * ACS: * channel 12: total interference = 0.0816809
238 * ACS: * channel 13: total interference = 0.0680776
239 * ACS: Ideal channel is 13 (2472 MHz) with total interference factor of 0.0680776
240 *
241 * [1] http://en.wikipedia.org/wiki/Near_and_far_field
242 */
243
244
245static int acs_request_scan(struct hostapd_iface *iface);
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800246static int acs_survey_is_sufficient(struct freq_survey *survey);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700247
248
249static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
250{
251 struct freq_survey *survey, *tmp;
252
253 if (dl_list_empty(&chan->survey_list))
254 return;
255
256 dl_list_for_each_safe(survey, tmp, &chan->survey_list,
257 struct freq_survey, list) {
258 dl_list_del(&survey->list);
259 os_free(survey);
260 }
261}
262
263
Hai Shalomfdcde762020-04-02 11:19:20 -0700264static void acs_cleanup_mode(struct hostapd_hw_modes *mode)
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700265{
266 int i;
267 struct hostapd_channel_data *chan;
268
Hai Shalomfdcde762020-04-02 11:19:20 -0700269 for (i = 0; i < mode->num_channels; i++) {
270 chan = &mode->channels[i];
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700271
272 if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED)
273 acs_clean_chan_surveys(chan);
274
275 dl_list_init(&chan->survey_list);
276 chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
277 chan->min_nf = 0;
278 }
Hai Shalomfdcde762020-04-02 11:19:20 -0700279}
280
281
282void acs_cleanup(struct hostapd_iface *iface)
283{
284 int i;
285
286 for (i = 0; i < iface->num_hw_features; i++)
287 acs_cleanup_mode(&iface->hw_features[i]);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700288
289 iface->chans_surveyed = 0;
290 iface->acs_num_completed_scans = 0;
291}
292
293
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800294static void acs_fail(struct hostapd_iface *iface)
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700295{
296 wpa_printf(MSG_ERROR, "ACS: Failed to start");
297 acs_cleanup(iface);
Dmitry Shmidt2ac5f602014-03-07 10:08:21 -0800298 hostapd_disable_iface(iface);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700299}
300
301
302static long double
303acs_survey_interference_factor(struct freq_survey *survey, s8 min_nf)
304{
305 long double factor, busy, total;
306
307 if (survey->filled & SURVEY_HAS_CHAN_TIME_BUSY)
308 busy = survey->channel_time_busy;
309 else if (survey->filled & SURVEY_HAS_CHAN_TIME_RX)
310 busy = survey->channel_time_rx;
311 else {
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700312 wpa_printf(MSG_ERROR, "ACS: Survey data missing");
313 return 0;
314 }
315
316 total = survey->channel_time;
317
318 if (survey->filled & SURVEY_HAS_CHAN_TIME_TX) {
319 busy -= survey->channel_time_tx;
320 total -= survey->channel_time_tx;
321 }
322
323 /* TODO: figure out the best multiplier for noise floor base */
324 factor = pow(10, survey->nf / 5.0L) +
Roshan Pius3a1667e2018-07-03 15:17:14 -0700325 (total ? (busy / total) : 0) *
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700326 pow(2, pow(10, (long double) survey->nf / 10.0L) -
327 pow(10, (long double) min_nf / 10.0L));
328
329 return factor;
330}
331
332
333static void
334acs_survey_chan_interference_factor(struct hostapd_iface *iface,
335 struct hostapd_channel_data *chan)
336{
337 struct freq_survey *survey;
338 unsigned int i = 0;
339 long double int_factor = 0;
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800340 unsigned count = 0;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700341
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700342 if (dl_list_empty(&chan->survey_list) ||
343 (chan->flag & HOSTAPD_CHAN_DISABLED))
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700344 return;
345
346 chan->interference_factor = 0;
347
348 dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list)
349 {
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800350 i++;
351
352 if (!acs_survey_is_sufficient(survey)) {
353 wpa_printf(MSG_DEBUG, "ACS: %d: insufficient data", i);
354 continue;
355 }
356
357 count++;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700358 int_factor = acs_survey_interference_factor(survey,
359 iface->lowest_nf);
360 chan->interference_factor += int_factor;
361 wpa_printf(MSG_DEBUG, "ACS: %d: min_nf=%d interference_factor=%Lg nf=%d time=%lu busy=%lu rx=%lu",
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800362 i, chan->min_nf, int_factor,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700363 survey->nf, (unsigned long) survey->channel_time,
364 (unsigned long) survey->channel_time_busy,
365 (unsigned long) survey->channel_time_rx);
366 }
367
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700368 if (count)
369 chan->interference_factor /= count;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700370}
371
372
Hai Shaloma20dcd72022-02-04 13:43:00 -0800373static int acs_usable_bw40_chan(const struct hostapd_channel_data *chan)
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700374{
Hai Shaloma20dcd72022-02-04 13:43:00 -0800375 const int allowed[] = { 5180, 5220, 5260, 5300, 5500, 5540, 5580, 5620,
376 5660, 5745, 5785, 4920, 4960, 5955, 5995, 6035,
377 6075, 6115, 6155, 6195, 6235, 6275, 6315, 6355,
378 6395, 6435, 6475, 6515, 6555, 6595, 6635, 6675,
379 6715, 6755, 6795, 6835, 6875, 6915, 6955, 6995,
380 7035, 7075 };
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700381 unsigned int i;
382
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700383 for (i = 0; i < ARRAY_SIZE(allowed); i++)
Hai Shaloma20dcd72022-02-04 13:43:00 -0800384 if (chan->freq == allowed[i])
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700385 return 1;
386
387 return 0;
388}
389
390
Hai Shaloma20dcd72022-02-04 13:43:00 -0800391static int acs_usable_bw80_chan(const struct hostapd_channel_data *chan)
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800392{
Hai Shaloma20dcd72022-02-04 13:43:00 -0800393 const int allowed[] = { 5180, 5260, 5500, 5580, 5660, 5745, 5955, 6035,
394 6115, 6195, 6275, 6355, 6435, 6515, 6595, 6675,
395 6755, 6835, 6915, 6995 };
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800396 unsigned int i;
397
398 for (i = 0; i < ARRAY_SIZE(allowed); i++)
Hai Shaloma20dcd72022-02-04 13:43:00 -0800399 if (chan->freq == allowed[i])
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800400 return 1;
401
402 return 0;
403}
404
405
Hai Shaloma20dcd72022-02-04 13:43:00 -0800406static int acs_usable_bw160_chan(const struct hostapd_channel_data *chan)
Hai Shalom74f70d42019-02-11 14:42:39 -0800407{
Hai Shaloma20dcd72022-02-04 13:43:00 -0800408 const int allowed[] = { 5180, 5500, 5955, 6115, 6275, 6435, 6595, 6755,
409 6915 };
Hai Shalom74f70d42019-02-11 14:42:39 -0800410 unsigned int i;
411
412 for (i = 0; i < ARRAY_SIZE(allowed); i++)
Hai Shaloma20dcd72022-02-04 13:43:00 -0800413 if (chan->freq == allowed[i])
Hai Shalom74f70d42019-02-11 14:42:39 -0800414 return 1;
415
416 return 0;
417}
418
419
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700420static int acs_survey_is_sufficient(struct freq_survey *survey)
421{
422 if (!(survey->filled & SURVEY_HAS_NF)) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800423 wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor");
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700424 return 0;
425 }
426
427 if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800428 wpa_printf(MSG_INFO, "ACS: Survey is missing channel time");
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700429 return 0;
430 }
431
432 if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) &&
433 !(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800434 wpa_printf(MSG_INFO,
435 "ACS: Survey is missing RX and busy time (at least one is required)");
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700436 return 0;
437 }
438
439 return 1;
440}
441
442
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700443static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
444{
445 struct freq_survey *survey;
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800446 int ret = -1;
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700447
448 dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list)
449 {
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800450 if (acs_survey_is_sufficient(survey)) {
451 ret = 1;
452 break;
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700453 }
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800454 ret = 0;
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700455 }
456
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800457 if (ret == -1)
458 ret = 1; /* no survey list entries */
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700459
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800460 if (!ret) {
461 wpa_printf(MSG_INFO,
462 "ACS: Channel %d has insufficient survey data",
463 chan->chan);
464 }
465
466 return ret;
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700467}
468
469
Hai Shalomfdcde762020-04-02 11:19:20 -0700470static int acs_surveys_are_sufficient_mode(struct hostapd_hw_modes *mode)
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700471{
472 int i;
473 struct hostapd_channel_data *chan;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700474
Hai Shalomfdcde762020-04-02 11:19:20 -0700475 for (i = 0; i < mode->num_channels; i++) {
476 chan = &mode->channels[i];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700477 if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
478 acs_survey_list_is_sufficient(chan))
Hai Shalomfdcde762020-04-02 11:19:20 -0700479 return 1;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700480 }
481
Hai Shalomfdcde762020-04-02 11:19:20 -0700482 return 0;
483}
484
485
486static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
487{
488 int i;
489 struct hostapd_hw_modes *mode;
490
491 for (i = 0; i < iface->num_hw_features; i++) {
492 mode = &iface->hw_features[i];
493 if (!hostapd_hw_skip_mode(iface, mode) &&
494 acs_surveys_are_sufficient_mode(mode))
495 return 1;
496 }
497
498 return 0;
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700499}
500
501
502static int acs_usable_chan(struct hostapd_channel_data *chan)
503{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700504 return !dl_list_empty(&chan->survey_list) &&
505 !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
506 acs_survey_list_is_sufficient(chan);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700507}
508
509
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800510static int is_in_chanlist(struct hostapd_iface *iface,
511 struct hostapd_channel_data *chan)
512{
Dmitry Shmidtdda10c22015-03-24 16:05:01 -0700513 if (!iface->conf->acs_ch_list.num)
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800514 return 1;
515
Dmitry Shmidtdda10c22015-03-24 16:05:01 -0700516 return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800517}
518
519
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700520static int is_in_freqlist(struct hostapd_iface *iface,
521 struct hostapd_channel_data *chan)
522{
523 if (!iface->conf->acs_freq_list.num)
524 return 1;
525
526 return freq_range_list_includes(&iface->conf->acs_freq_list,
527 chan->freq);
528}
529
530
Hai Shalomfdcde762020-04-02 11:19:20 -0700531static void acs_survey_mode_interference_factor(
532 struct hostapd_iface *iface, struct hostapd_hw_modes *mode)
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700533{
534 int i;
535 struct hostapd_channel_data *chan;
536
Hai Shalomfdcde762020-04-02 11:19:20 -0700537 for (i = 0; i < mode->num_channels; i++) {
538 chan = &mode->channels[i];
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700539
540 if (!acs_usable_chan(chan))
541 continue;
542
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800543 if (!is_in_chanlist(iface, chan))
544 continue;
545
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700546 if (!is_in_freqlist(iface, chan))
547 continue;
548
Hai Shaloma20dcd72022-02-04 13:43:00 -0800549 if (chan->max_tx_power < iface->conf->min_tx_power)
550 continue;
551
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700552 wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
553 chan->chan, chan->freq);
554
555 acs_survey_chan_interference_factor(iface, chan);
556
557 wpa_printf(MSG_DEBUG, "ACS: * interference factor average: %Lg",
558 chan->interference_factor);
559 }
560}
561
562
Hai Shalomfdcde762020-04-02 11:19:20 -0700563static void acs_survey_all_chans_interference_factor(
564 struct hostapd_iface *iface)
565{
566 int i;
567 struct hostapd_hw_modes *mode;
568
569 for (i = 0; i < iface->num_hw_features; i++) {
570 mode = &iface->hw_features[i];
571 if (!hostapd_hw_skip_mode(iface, mode))
572 acs_survey_mode_interference_factor(iface, mode);
573 }
574}
575
576
577static struct hostapd_channel_data *
578acs_find_chan_mode(struct hostapd_hw_modes *mode, int freq)
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700579{
580 struct hostapd_channel_data *chan;
581 int i;
582
Hai Shalomfdcde762020-04-02 11:19:20 -0700583 for (i = 0; i < mode->num_channels; i++) {
584 chan = &mode->channels[i];
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700585
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700586 if (chan->flag & HOSTAPD_CHAN_DISABLED)
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700587 continue;
588
589 if (chan->freq == freq)
590 return chan;
591 }
592
593 return NULL;
594}
595
596
Hai Shalomfdcde762020-04-02 11:19:20 -0700597static struct hostapd_channel_data *
598acs_find_chan(struct hostapd_iface *iface, int freq)
599{
600 int i;
601 struct hostapd_hw_modes *mode;
602 struct hostapd_channel_data *chan;
603
604 for (i = 0; i < iface->num_hw_features; i++) {
605 mode = &iface->hw_features[i];
606 if (!hostapd_hw_skip_mode(iface, mode)) {
607 chan = acs_find_chan_mode(mode, freq);
608 if (chan)
609 return chan;
610 }
611 }
612
613 return NULL;
614}
615
616
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800617static int is_24ghz_mode(enum hostapd_hw_mode mode)
618{
619 return mode == HOSTAPD_MODE_IEEE80211B ||
620 mode == HOSTAPD_MODE_IEEE80211G;
621}
622
623
624static int is_common_24ghz_chan(int chan)
625{
626 return chan == 1 || chan == 6 || chan == 11;
627}
628
629
630#ifndef ACS_ADJ_WEIGHT
631#define ACS_ADJ_WEIGHT 0.85
632#endif /* ACS_ADJ_WEIGHT */
633
634#ifndef ACS_NEXT_ADJ_WEIGHT
635#define ACS_NEXT_ADJ_WEIGHT 0.55
636#endif /* ACS_NEXT_ADJ_WEIGHT */
637
638#ifndef ACS_24GHZ_PREFER_1_6_11
639/*
640 * Select commonly used channels 1, 6, 11 by default even if a neighboring
641 * channel has a smaller interference factor as long as it is not better by more
642 * than this multiplier.
643 */
644#define ACS_24GHZ_PREFER_1_6_11 0.8
645#endif /* ACS_24GHZ_PREFER_1_6_11 */
646
Hai Shalomfdcde762020-04-02 11:19:20 -0700647static void
648acs_find_ideal_chan_mode(struct hostapd_iface *iface,
649 struct hostapd_hw_modes *mode,
650 int n_chans, u32 bw,
651 struct hostapd_channel_data **rand_chan,
652 struct hostapd_channel_data **ideal_chan,
653 long double *ideal_factor)
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700654{
Hai Shalomfdcde762020-04-02 11:19:20 -0700655 struct hostapd_channel_data *chan, *adj_chan = NULL;
656 long double factor;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700657 int i, j;
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800658 unsigned int k;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700659
Hai Shalomfdcde762020-04-02 11:19:20 -0700660 for (i = 0; i < mode->num_channels; i++) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800661 double total_weight;
662 struct acs_bias *bias, tmp_bias;
663
Hai Shalomfdcde762020-04-02 11:19:20 -0700664 chan = &mode->channels[i];
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700665
Hai Shalom74f70d42019-02-11 14:42:39 -0800666 /* Since in the current ACS implementation the first channel is
667 * always a primary channel, skip channels not available as
668 * primary until more sophisticated channel selection is
669 * implemented. */
670 if (!chan_pri_allowed(chan))
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700671 continue;
672
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800673 if (!is_in_chanlist(iface, chan))
674 continue;
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700675
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700676 if (!is_in_freqlist(iface, chan))
677 continue;
678
Hai Shaloma20dcd72022-02-04 13:43:00 -0800679 if (chan->max_tx_power < iface->conf->min_tx_power)
680 continue;
681
Hai Shalom74f70d42019-02-11 14:42:39 -0800682 if (!chan_bw_allowed(chan, bw, 1, 1)) {
683 wpa_printf(MSG_DEBUG,
684 "ACS: Channel %d: BW %u is not supported",
685 chan->chan, bw);
686 continue;
687 }
688
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700689 /* HT40 on 5 GHz has a limited set of primary channels as per
690 * 11n Annex J */
Hai Shalomfdcde762020-04-02 11:19:20 -0700691 if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
Hai Shaloma20dcd72022-02-04 13:43:00 -0800692 ((iface->conf->ieee80211n &&
693 iface->conf->secondary_channel) ||
694 is_6ghz_freq(chan->freq)) &&
695 !acs_usable_bw40_chan(chan)) {
696 wpa_printf(MSG_DEBUG,
697 "ACS: Channel %d: not allowed as primary channel for 40 MHz bandwidth",
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700698 chan->chan);
699 continue;
700 }
701
Hai Shalomfdcde762020-04-02 11:19:20 -0700702 if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
Hai Shalom81f62d82019-07-22 12:10:00 -0700703 (iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
704 if (hostapd_get_oper_chwidth(iface->conf) ==
705 CHANWIDTH_80MHZ &&
Hai Shaloma20dcd72022-02-04 13:43:00 -0800706 !acs_usable_bw80_chan(chan)) {
Hai Shalom74f70d42019-02-11 14:42:39 -0800707 wpa_printf(MSG_DEBUG,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800708 "ACS: Channel %d: not allowed as primary channel for 80 MHz bandwidth",
Hai Shalom74f70d42019-02-11 14:42:39 -0800709 chan->chan);
710 continue;
711 }
712
Hai Shalom81f62d82019-07-22 12:10:00 -0700713 if (hostapd_get_oper_chwidth(iface->conf) ==
714 CHANWIDTH_160MHZ &&
Hai Shaloma20dcd72022-02-04 13:43:00 -0800715 !acs_usable_bw160_chan(chan)) {
Hai Shalom74f70d42019-02-11 14:42:39 -0800716 wpa_printf(MSG_DEBUG,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800717 "ACS: Channel %d: not allowed as primary channel for 160 MHz bandwidth",
Hai Shalom74f70d42019-02-11 14:42:39 -0800718 chan->chan);
719 continue;
720 }
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800721 }
722
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700723 factor = 0;
724 if (acs_usable_chan(chan))
725 factor = chan->interference_factor;
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800726 total_weight = 1;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700727
728 for (j = 1; j < n_chans; j++) {
729 adj_chan = acs_find_chan(iface, chan->freq + (j * 20));
730 if (!adj_chan)
731 break;
732
Hai Shalom74f70d42019-02-11 14:42:39 -0800733 if (!chan_bw_allowed(adj_chan, bw, 1, 0)) {
734 wpa_printf(MSG_DEBUG,
735 "ACS: PRI Channel %d: secondary channel %d BW %u is not supported",
736 chan->chan, adj_chan->chan, bw);
737 break;
738 }
739
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800740 if (acs_usable_chan(adj_chan)) {
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700741 factor += adj_chan->interference_factor;
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800742 total_weight += 1;
743 }
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700744 }
745
746 if (j != n_chans) {
747 wpa_printf(MSG_DEBUG, "ACS: Channel %d: not enough bandwidth",
748 chan->chan);
749 continue;
750 }
751
752 /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
753 * channel interference factor. */
Hai Shalomfdcde762020-04-02 11:19:20 -0700754 if (is_24ghz_mode(mode->mode)) {
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700755 for (j = 0; j < n_chans; j++) {
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700756 adj_chan = acs_find_chan(iface, chan->freq +
757 (j * 20) - 5);
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800758 if (adj_chan && acs_usable_chan(adj_chan)) {
759 factor += ACS_ADJ_WEIGHT *
760 adj_chan->interference_factor;
761 total_weight += ACS_ADJ_WEIGHT;
762 }
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700763
764 adj_chan = acs_find_chan(iface, chan->freq +
765 (j * 20) - 10);
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800766 if (adj_chan && acs_usable_chan(adj_chan)) {
767 factor += ACS_NEXT_ADJ_WEIGHT *
768 adj_chan->interference_factor;
769 total_weight += ACS_NEXT_ADJ_WEIGHT;
770 }
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700771
772 adj_chan = acs_find_chan(iface, chan->freq +
773 (j * 20) + 5);
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800774 if (adj_chan && acs_usable_chan(adj_chan)) {
775 factor += ACS_ADJ_WEIGHT *
776 adj_chan->interference_factor;
777 total_weight += ACS_ADJ_WEIGHT;
778 }
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700779
780 adj_chan = acs_find_chan(iface, chan->freq +
781 (j * 20) + 10);
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800782 if (adj_chan && acs_usable_chan(adj_chan)) {
783 factor += ACS_NEXT_ADJ_WEIGHT *
784 adj_chan->interference_factor;
785 total_weight += ACS_NEXT_ADJ_WEIGHT;
786 }
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700787 }
788 }
789
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800790 factor /= total_weight;
791
792 bias = NULL;
793 if (iface->conf->acs_chan_bias) {
794 for (k = 0; k < iface->conf->num_acs_chan_bias; k++) {
795 bias = &iface->conf->acs_chan_bias[k];
796 if (bias->channel == chan->chan)
797 break;
798 bias = NULL;
799 }
Hai Shalomfdcde762020-04-02 11:19:20 -0700800 } else if (is_24ghz_mode(mode->mode) &&
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800801 is_common_24ghz_chan(chan->chan)) {
802 tmp_bias.channel = chan->chan;
803 tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11;
804 bias = &tmp_bias;
805 }
806
807 if (bias) {
808 factor *= bias->bias;
809 wpa_printf(MSG_DEBUG,
810 "ACS: * channel %d: total interference = %Lg (%f bias)",
811 chan->chan, factor, bias->bias);
812 } else {
813 wpa_printf(MSG_DEBUG,
814 "ACS: * channel %d: total interference = %Lg",
815 chan->chan, factor);
816 }
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700817
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700818 if (acs_usable_chan(chan) &&
Hai Shalomfdcde762020-04-02 11:19:20 -0700819 (!*ideal_chan || factor < *ideal_factor)) {
820 *ideal_factor = factor;
821 *ideal_chan = chan;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700822 }
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700823
824 /* This channel would at least be usable */
Hai Shalomfdcde762020-04-02 11:19:20 -0700825 if (!(*rand_chan))
826 *rand_chan = chan;
827 }
828}
829
830
831/*
832 * At this point it's assumed chan->interference_factor has been computed.
833 * This function should be reusable regardless of interference computation
834 * option (survey, BSS, spectral, ...). chan->interference factor must be
835 * summable (i.e., must be always greater than zero).
836 */
837static struct hostapd_channel_data *
838acs_find_ideal_chan(struct hostapd_iface *iface)
839{
840 struct hostapd_channel_data *ideal_chan = NULL,
841 *rand_chan = NULL;
842 long double ideal_factor = 0;
843 int i;
844 int n_chans = 1;
845 u32 bw;
846 struct hostapd_hw_modes *mode;
847
Hai Shaloma20dcd72022-02-04 13:43:00 -0800848 if (is_6ghz_op_class(iface->conf->op_class)) {
849 bw = op_class_to_bandwidth(iface->conf->op_class);
850 n_chans = bw / 20;
851 goto bw_selected;
852 }
853
Hai Shalomfdcde762020-04-02 11:19:20 -0700854 /* TODO: HT40- support */
855
856 if (iface->conf->ieee80211n &&
857 iface->conf->secondary_channel == -1) {
858 wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
859 return NULL;
860 }
861
862 if (iface->conf->ieee80211n &&
863 iface->conf->secondary_channel)
864 n_chans = 2;
865
866 if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
867 switch (hostapd_get_oper_chwidth(iface->conf)) {
868 case CHANWIDTH_80MHZ:
869 n_chans = 4;
870 break;
871 case CHANWIDTH_160MHZ:
872 n_chans = 8;
873 break;
874 }
875 }
876
877 bw = num_chan_to_bw(n_chans);
878
Hai Shaloma20dcd72022-02-04 13:43:00 -0800879bw_selected:
Hai Shalomfdcde762020-04-02 11:19:20 -0700880 /* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
881
882 wpa_printf(MSG_DEBUG,
883 "ACS: Survey analysis for selected bandwidth %d MHz", bw);
884
885 for (i = 0; i < iface->num_hw_features; i++) {
886 mode = &iface->hw_features[i];
887 if (!hostapd_hw_skip_mode(iface, mode))
888 acs_find_ideal_chan_mode(iface, mode, n_chans, bw,
889 &rand_chan, &ideal_chan,
890 &ideal_factor);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700891 }
892
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700893 if (ideal_chan) {
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700894 wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg",
895 ideal_chan->chan, ideal_chan->freq, ideal_factor);
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700896 return ideal_chan;
897 }
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700898
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700899 return rand_chan;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700900}
901
902
Hai Shalom81f62d82019-07-22 12:10:00 -0700903static void acs_adjust_center_freq(struct hostapd_iface *iface)
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700904{
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700905 int offset;
906
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700907 wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
908
Hai Shalom81f62d82019-07-22 12:10:00 -0700909 switch (hostapd_get_oper_chwidth(iface->conf)) {
910 case CHANWIDTH_USE_HT:
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700911 offset = 2 * iface->conf->secondary_channel;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700912 break;
Hai Shalom81f62d82019-07-22 12:10:00 -0700913 case CHANWIDTH_80MHZ:
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700914 offset = 6;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700915 break;
Hai Shalom81f62d82019-07-22 12:10:00 -0700916 case CHANWIDTH_160MHZ:
Hai Shalom74f70d42019-02-11 14:42:39 -0800917 offset = 14;
918 break;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700919 default:
920 /* TODO: How can this be calculated? Adjust
921 * acs_find_ideal_chan() */
Hai Shalom74f70d42019-02-11 14:42:39 -0800922 wpa_printf(MSG_INFO,
923 "ACS: Only VHT20/40/80/160 is supported now");
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700924 return;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700925 }
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700926
Hai Shalom81f62d82019-07-22 12:10:00 -0700927 hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
928 iface->conf->channel + offset);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700929}
930
931
932static int acs_study_survey_based(struct hostapd_iface *iface)
933{
934 wpa_printf(MSG_DEBUG, "ACS: Trying survey-based ACS");
935
936 if (!iface->chans_surveyed) {
937 wpa_printf(MSG_ERROR, "ACS: Unable to collect survey data");
938 return -1;
939 }
940
941 if (!acs_surveys_are_sufficient(iface)) {
942 wpa_printf(MSG_ERROR, "ACS: Surveys have insufficient data");
943 return -1;
944 }
945
Hai Shalomfdcde762020-04-02 11:19:20 -0700946 acs_survey_all_chans_interference_factor(iface);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700947 return 0;
948}
949
950
951static int acs_study_options(struct hostapd_iface *iface)
952{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700953 if (acs_study_survey_based(iface) == 0)
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700954 return 0;
955
956 /* TODO: If no surveys are available/sufficient this is a good
957 * place to fallback to BSS-based ACS */
958
959 return -1;
960}
961
962
963static void acs_study(struct hostapd_iface *iface)
964{
965 struct hostapd_channel_data *ideal_chan;
966 int err;
967
968 err = acs_study_options(iface);
969 if (err < 0) {
970 wpa_printf(MSG_ERROR, "ACS: All study options have failed");
971 goto fail;
972 }
973
974 ideal_chan = acs_find_ideal_chan(iface);
975 if (!ideal_chan) {
976 wpa_printf(MSG_ERROR, "ACS: Failed to compute ideal channel");
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700977 err = -1;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700978 goto fail;
979 }
980
981 iface->conf->channel = ideal_chan->chan;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800982 iface->freq = ideal_chan->freq;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700983
Hai Shalom81f62d82019-07-22 12:10:00 -0700984 if (iface->conf->ieee80211ac || iface->conf->ieee80211ax)
985 acs_adjust_center_freq(iface);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700986
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700987 err = 0;
988fail:
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700989 /*
990 * hostapd_setup_interface_complete() will return -1 on failure,
991 * 0 on success and 0 is HOSTAPD_CHAN_VALID :)
992 */
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700993 if (hostapd_acs_completed(iface, err) == HOSTAPD_CHAN_VALID) {
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700994 acs_cleanup(iface);
995 return;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700996 }
997
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -0700998 /* This can possibly happen if channel parameters (secondary
999 * channel, center frequencies) are misconfigured */
1000 wpa_printf(MSG_ERROR, "ACS: Possibly channel configuration is invalid, please report this along with your config file.");
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001001 acs_fail(iface);
1002}
1003
1004
1005static void acs_scan_complete(struct hostapd_iface *iface)
1006{
1007 int err;
1008
1009 iface->scan_cb = NULL;
1010
1011 wpa_printf(MSG_DEBUG, "ACS: Using survey based algorithm (acs_num_scans=%d)",
1012 iface->conf->acs_num_scans);
1013
1014 err = hostapd_drv_get_survey(iface->bss[0], 0);
1015 if (err) {
1016 wpa_printf(MSG_ERROR, "ACS: Failed to get survey data");
Dmitry Shmidt15907092014-03-25 10:42:57 -07001017 goto fail;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001018 }
1019
1020 if (++iface->acs_num_completed_scans < iface->conf->acs_num_scans) {
1021 err = acs_request_scan(iface);
1022 if (err) {
1023 wpa_printf(MSG_ERROR, "ACS: Failed to request scan");
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001024 goto fail;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001025 }
1026
1027 return;
1028 }
1029
1030 acs_study(iface);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001031 return;
1032fail:
1033 hostapd_acs_completed(iface, 1);
1034 acs_fail(iface);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001035}
1036
1037
Hai Shalomfdcde762020-04-02 11:19:20 -07001038static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
1039 struct hostapd_hw_modes *mode,
1040 int *freq)
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001041{
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001042 struct hostapd_channel_data *chan;
Hai Shalomfdcde762020-04-02 11:19:20 -07001043 int i;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001044
Hai Shalomfdcde762020-04-02 11:19:20 -07001045 for (i = 0; i < mode->num_channels; i++) {
1046 chan = &mode->channels[i];
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001047 if (chan->flag & HOSTAPD_CHAN_DISABLED)
1048 continue;
1049
Dmitry Shmidt8bd70b72015-05-26 16:02:19 -07001050 if (!is_in_chanlist(iface, chan))
1051 continue;
1052
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001053 if (!is_in_freqlist(iface, chan))
1054 continue;
1055
Hai Shaloma20dcd72022-02-04 13:43:00 -08001056 if (chan->max_tx_power < iface->conf->min_tx_power)
1057 continue;
1058
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001059 *freq++ = chan->freq;
1060 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001061
1062 return freq;
1063}
1064
1065
1066static int acs_request_scan(struct hostapd_iface *iface)
1067{
1068 struct wpa_driver_scan_params params;
1069 int i, *freq;
1070 int num_channels;
1071 struct hostapd_hw_modes *mode;
1072
1073 os_memset(&params, 0, sizeof(params));
1074
1075 num_channels = 0;
1076 for (i = 0; i < iface->num_hw_features; i++) {
1077 mode = &iface->hw_features[i];
1078 if (!hostapd_hw_skip_mode(iface, mode))
1079 num_channels += mode->num_channels;
1080 }
1081
1082 params.freqs = os_calloc(num_channels + 1, sizeof(params.freqs[0]));
1083 if (params.freqs == NULL)
1084 return -1;
1085
1086 freq = params.freqs;
1087
1088 for (i = 0; i < iface->num_hw_features; i++) {
1089 mode = &iface->hw_features[i];
1090 if (!hostapd_hw_skip_mode(iface, mode))
1091 freq = acs_request_scan_add_freqs(iface, mode, freq);
1092 }
1093
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001094 *freq = 0;
1095
Neo Joue2881702019-10-17 11:32:28 +08001096 if (params.freqs == freq) {
1097 wpa_printf(MSG_ERROR, "ACS: No available channels found");
1098 os_free(params.freqs);
1099 return -1;
1100 }
1101
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001102 iface->scan_cb = acs_scan_complete;
1103
1104 wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
1105 iface->acs_num_completed_scans + 1,
1106 iface->conf->acs_num_scans);
1107
1108 if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
1109 wpa_printf(MSG_ERROR, "ACS: Failed to request initial scan");
1110 acs_cleanup(iface);
Dmitry Shmidt15907092014-03-25 10:42:57 -07001111 os_free(params.freqs);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001112 return -1;
1113 }
1114
1115 os_free(params.freqs);
1116 return 0;
1117}
1118
1119
1120enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
1121{
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001122 wpa_printf(MSG_INFO, "ACS: Automatic channel selection started, this may take a bit");
1123
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001124 if (iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) {
1125 wpa_printf(MSG_INFO, "ACS: Offloading to driver");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001126 if (hostapd_drv_do_acs(iface->bss[0]))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001127 return HOSTAPD_CHAN_INVALID;
1128 return HOSTAPD_CHAN_ACS;
1129 }
1130
Hai Shalomfdcde762020-04-02 11:19:20 -07001131 if (!iface->current_mode &&
1132 iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001133 return HOSTAPD_CHAN_INVALID;
1134
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001135 acs_cleanup(iface);
1136
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001137 if (acs_request_scan(iface) < 0)
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001138 return HOSTAPD_CHAN_INVALID;
1139
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001140 hostapd_set_state(iface, HAPD_IFACE_ACS);
1141 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_STARTED);
1142
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001143 return HOSTAPD_CHAN_ACS;
1144}