1 /*
2 * DFS - Dynamic Frequency Selection
3 * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2013-2017, Qualcomm Atheros, Inc.
5 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
6 *
7 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
9 */
10
11 #include "utils/includes.h"
12
13 #include "utils/common.h"
14 #include "common/ieee802_11_defs.h"
15 #include "common/hw_features_common.h"
16 #include "common/wpa_ctrl.h"
17 #include "hostapd.h"
18 #include "beacon.h"
19 #include "ap_drv_ops.h"
20 #include "drivers/driver.h"
21 #include "dfs.h"
22
23
24 enum dfs_channel_type {
25 DFS_ANY_CHANNEL,
26 DFS_AVAILABLE, /* non-radar or radar-available */
27 DFS_NO_CAC_YET, /* radar-not-yet-available */
28 };
29
30 static struct hostapd_channel_data *
31 dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
32 u8 *oper_centr_freq_seg0_idx,
33 u8 *oper_centr_freq_seg1_idx,
34 enum dfs_channel_type *channel_type);
35
36
dfs_use_radar_background(struct hostapd_iface * iface)37 static bool dfs_use_radar_background(struct hostapd_iface *iface)
38 {
39 return (iface->drv_flags2 & WPA_DRIVER_FLAGS2_RADAR_BACKGROUND) &&
40 iface->conf->enable_background_radar;
41 }
42
43
dfs_get_used_n_chans(struct hostapd_iface * iface,int * seg1)44 static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
45 {
46 int n_chans = 1;
47
48 *seg1 = 0;
49
50 if (iface->conf->ieee80211n && iface->conf->secondary_channel)
51 n_chans = 2;
52
53 if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
54 switch (hostapd_get_oper_chwidth(iface->conf)) {
55 case CONF_OPER_CHWIDTH_USE_HT:
56 break;
57 case CONF_OPER_CHWIDTH_80MHZ:
58 n_chans = 4;
59 break;
60 case CONF_OPER_CHWIDTH_160MHZ:
61 n_chans = 8;
62 break;
63 case CONF_OPER_CHWIDTH_80P80MHZ:
64 n_chans = 4;
65 *seg1 = 4;
66 break;
67 default:
68 break;
69 }
70 }
71
72 return n_chans;
73 }
74
75
76 /* dfs_channel_available: select new channel according to type parameter */
dfs_channel_available(struct hostapd_channel_data * chan,enum dfs_channel_type type)77 static int dfs_channel_available(struct hostapd_channel_data *chan,
78 enum dfs_channel_type type)
79 {
80 if (type == DFS_NO_CAC_YET) {
81 /* Select only radar channel where CAC has not been
82 * performed yet
83 */
84 if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
85 (chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
86 HOSTAPD_CHAN_DFS_USABLE)
87 return 1;
88 return 0;
89 }
90
91 /*
92 * When radar detection happens, CSA is performed. However, there's no
93 * time for CAC, so radar channels must be skipped when finding a new
94 * channel for CSA, unless they are available for immediate use.
95 */
96 if (type == DFS_AVAILABLE && (chan->flag & HOSTAPD_CHAN_RADAR) &&
97 ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
98 HOSTAPD_CHAN_DFS_AVAILABLE))
99 return 0;
100
101 if (chan->flag & HOSTAPD_CHAN_DISABLED)
102 return 0;
103 if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
104 ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
105 HOSTAPD_CHAN_DFS_UNAVAILABLE))
106 return 0;
107 return 1;
108 }
109
110
dfs_is_chan_allowed(struct hostapd_channel_data * chan,int n_chans)111 static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
112 {
113 /*
114 * The tables contain first valid channel number based on channel width.
115 * We will also choose this first channel as the control one.
116 */
117 int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
118 165, 173, 184, 192 };
119 /*
120 * VHT80, valid channels based on center frequency:
121 * 42, 58, 106, 122, 138, 155, 171
122 */
123 int allowed_80[] = { 36, 52, 100, 116, 132, 149, 165 };
124 /*
125 * VHT160 valid channels based on center frequency:
126 * 50, 114, 163
127 */
128 int allowed_160[] = { 36, 100, 149 };
129 int *allowed = allowed_40;
130 unsigned int i, allowed_no = 0;
131
132 switch (n_chans) {
133 case 2:
134 allowed = allowed_40;
135 allowed_no = ARRAY_SIZE(allowed_40);
136 break;
137 case 4:
138 allowed = allowed_80;
139 allowed_no = ARRAY_SIZE(allowed_80);
140 break;
141 case 8:
142 allowed = allowed_160;
143 allowed_no = ARRAY_SIZE(allowed_160);
144 break;
145 default:
146 wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
147 break;
148 }
149
150 for (i = 0; i < allowed_no; i++) {
151 if (chan->chan == allowed[i])
152 return 1;
153 }
154
155 return 0;
156 }
157
158
159 static struct hostapd_channel_data *
dfs_get_chan_data(struct hostapd_hw_modes * mode,int freq,int first_chan_idx)160 dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
161 {
162 int i;
163
164 for (i = first_chan_idx; i < mode->num_channels; i++) {
165 if (mode->channels[i].freq == freq)
166 return &mode->channels[i];
167 }
168
169 return NULL;
170 }
171
172
dfs_chan_range_available(struct hostapd_hw_modes * mode,int first_chan_idx,int num_chans,enum dfs_channel_type type)173 static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
174 int first_chan_idx, int num_chans,
175 enum dfs_channel_type type)
176 {
177 struct hostapd_channel_data *first_chan, *chan;
178 int i;
179 u32 bw = num_chan_to_bw(num_chans);
180
181 if (first_chan_idx + num_chans > mode->num_channels) {
182 wpa_printf(MSG_DEBUG,
183 "DFS: some channels in range not defined");
184 return 0;
185 }
186
187 first_chan = &mode->channels[first_chan_idx];
188
189 /* hostapd DFS implementation assumes the first channel as primary.
190 * If it's not allowed to use the first channel as primary, decline the
191 * whole channel range. */
192 if (!chan_pri_allowed(first_chan)) {
193 wpa_printf(MSG_DEBUG, "DFS: primary channel not allowed");
194 return 0;
195 }
196
197 for (i = 0; i < num_chans; i++) {
198 chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
199 first_chan_idx);
200 if (!chan) {
201 wpa_printf(MSG_DEBUG, "DFS: no channel data for %d",
202 first_chan->freq + i * 20);
203 return 0;
204 }
205
206 /* HT 40 MHz secondary channel availability checked only for
207 * primary channel */
208 if (!chan_bw_allowed(chan, bw, 1, !i)) {
209 wpa_printf(MSG_DEBUG, "DFS: bw now allowed for %d",
210 first_chan->freq + i * 20);
211 return 0;
212 }
213
214 if (!dfs_channel_available(chan, type)) {
215 wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
216 first_chan->freq + i * 20);
217 return 0;
218 }
219 }
220
221 return 1;
222 }
223
224
is_in_chanlist(struct hostapd_iface * iface,struct hostapd_channel_data * chan)225 static int is_in_chanlist(struct hostapd_iface *iface,
226 struct hostapd_channel_data *chan)
227 {
228 if (!iface->conf->acs_ch_list.num)
229 return 1;
230
231 return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
232 }
233
234
235 /*
236 * The function assumes HT40+ operation.
237 * Make sure to adjust the following variables after calling this:
238 * - hapd->secondary_channel
239 * - hapd->vht/he_oper_centr_freq_seg0_idx
240 * - hapd->vht/he_oper_centr_freq_seg1_idx
241 */
dfs_find_channel(struct hostapd_iface * iface,struct hostapd_channel_data ** ret_chan,int idx,enum dfs_channel_type type)242 static int dfs_find_channel(struct hostapd_iface *iface,
243 struct hostapd_channel_data **ret_chan,
244 int idx, enum dfs_channel_type type)
245 {
246 struct hostapd_hw_modes *mode;
247 struct hostapd_channel_data *chan;
248 int i, channel_idx = 0, n_chans, n_chans1;
249
250 mode = iface->current_mode;
251 n_chans = dfs_get_used_n_chans(iface, &n_chans1);
252
253 wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
254 for (i = 0; i < mode->num_channels; i++) {
255 chan = &mode->channels[i];
256
257 if (!chan_in_current_hw_info(iface->current_hw_info, chan)) {
258 wpa_printf(MSG_DEBUG,
259 "DFS: channel %d (%d) is not under current hardware index",
260 chan->freq, chan->chan);
261 continue;
262 }
263
264 /* Skip HT40/VHT incompatible channels */
265 if (iface->conf->ieee80211n &&
266 iface->conf->secondary_channel &&
267 (!dfs_is_chan_allowed(chan, n_chans) ||
268 !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))) {
269 wpa_printf(MSG_DEBUG,
270 "DFS: channel %d (%d) is incompatible",
271 chan->freq, chan->chan);
272 continue;
273 }
274
275 /* Skip incompatible chandefs */
276 if (!dfs_chan_range_available(mode, i, n_chans, type)) {
277 wpa_printf(MSG_DEBUG,
278 "DFS: range not available for %d (%d)",
279 chan->freq, chan->chan);
280 continue;
281 }
282
283 if (!is_in_chanlist(iface, chan)) {
284 wpa_printf(MSG_DEBUG,
285 "DFS: channel %d (%d) not in chanlist",
286 chan->freq, chan->chan);
287 continue;
288 }
289
290 if (chan->max_tx_power < iface->conf->min_tx_power)
291 continue;
292
293 if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
294 iface->conf->country[2] == 0x4f)
295 continue;
296
297 if (ret_chan && idx == channel_idx) {
298 wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
299 chan->freq, chan->chan);
300 *ret_chan = chan;
301 return idx;
302 }
303 wpa_printf(MSG_DEBUG, "Adding channel %d (%d)",
304 chan->freq, chan->chan);
305 channel_idx++;
306 }
307 return channel_idx;
308 }
309
310
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)311 static void dfs_adjust_center_freq(struct hostapd_iface *iface,
312 struct hostapd_channel_data *chan,
313 int secondary_channel,
314 int sec_chan_idx_80p80,
315 u8 *oper_centr_freq_seg0_idx,
316 u8 *oper_centr_freq_seg1_idx)
317 {
318 if (!iface->conf->ieee80211ac && !iface->conf->ieee80211ax)
319 return;
320
321 if (!chan)
322 return;
323
324 *oper_centr_freq_seg1_idx = 0;
325
326 switch (hostapd_get_oper_chwidth(iface->conf)) {
327 case CONF_OPER_CHWIDTH_USE_HT:
328 if (secondary_channel == 1)
329 *oper_centr_freq_seg0_idx = chan->chan + 2;
330 else if (secondary_channel == -1)
331 *oper_centr_freq_seg0_idx = chan->chan - 2;
332 else
333 *oper_centr_freq_seg0_idx = chan->chan;
334 break;
335 case CONF_OPER_CHWIDTH_80MHZ:
336 *oper_centr_freq_seg0_idx = chan->chan + 6;
337 break;
338 case CONF_OPER_CHWIDTH_160MHZ:
339 *oper_centr_freq_seg0_idx = chan->chan + 14;
340 break;
341 case CONF_OPER_CHWIDTH_80P80MHZ:
342 *oper_centr_freq_seg0_idx = chan->chan + 6;
343 *oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
344 break;
345
346 default:
347 wpa_printf(MSG_INFO,
348 "DFS: Unsupported channel width configuration");
349 *oper_centr_freq_seg0_idx = 0;
350 break;
351 }
352
353 wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
354 *oper_centr_freq_seg0_idx,
355 *oper_centr_freq_seg1_idx);
356 }
357
358
359 /* Return start channel idx we will use for mode->channels[idx] */
dfs_get_start_chan_idx(struct hostapd_iface * iface,int * seg1_start)360 static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
361 {
362 struct hostapd_hw_modes *mode;
363 struct hostapd_channel_data *chan;
364 int channel_no = iface->conf->channel;
365 int res = -1, i;
366 int chan_seg1 = -1;
367
368 *seg1_start = -1;
369
370 /* HT40- */
371 if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
372 channel_no -= 4;
373
374 /* VHT/HE/EHT */
375 if (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
376 iface->conf->ieee80211be) {
377 switch (hostapd_get_oper_chwidth(iface->conf)) {
378 case CONF_OPER_CHWIDTH_USE_HT:
379 break;
380 case CONF_OPER_CHWIDTH_80MHZ:
381 channel_no = hostapd_get_oper_centr_freq_seg0_idx(
382 iface->conf) - 6;
383 break;
384 case CONF_OPER_CHWIDTH_160MHZ:
385 channel_no = hostapd_get_oper_centr_freq_seg0_idx(
386 iface->conf) - 14;
387 break;
388 case CONF_OPER_CHWIDTH_80P80MHZ:
389 channel_no = hostapd_get_oper_centr_freq_seg0_idx(
390 iface->conf) - 6;
391 chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx(
392 iface->conf) - 6;
393 break;
394 case CONF_OPER_CHWIDTH_320MHZ:
395 channel_no = hostapd_get_oper_centr_freq_seg0_idx(
396 iface->conf) - 30;
397 break;
398 default:
399 wpa_printf(MSG_INFO,
400 "DFS only EHT20/40/80/160/80+80/320 is supported now");
401 channel_no = -1;
402 break;
403 }
404 }
405
406 /* Get idx */
407 mode = iface->current_mode;
408 for (i = 0; i < mode->num_channels; i++) {
409 chan = &mode->channels[i];
410 if (chan->chan == channel_no) {
411 res = i;
412 break;
413 }
414 }
415
416 if (res != -1 && chan_seg1 > -1) {
417 int found = 0;
418
419 /* Get idx for seg1 */
420 mode = iface->current_mode;
421 for (i = 0; i < mode->num_channels; i++) {
422 chan = &mode->channels[i];
423 if (chan->chan == chan_seg1) {
424 *seg1_start = i;
425 found = 1;
426 break;
427 }
428 }
429 if (!found)
430 res = -1;
431 }
432
433 if (res == -1) {
434 wpa_printf(MSG_DEBUG,
435 "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d",
436 mode->num_channels, channel_no, iface->conf->channel,
437 iface->conf->ieee80211n,
438 iface->conf->secondary_channel,
439 hostapd_get_oper_chwidth(iface->conf));
440
441 for (i = 0; i < mode->num_channels; i++) {
442 wpa_printf(MSG_DEBUG, "Available channel: %d",
443 mode->channels[i].chan);
444 }
445 }
446
447 return res;
448 }
449
450
451 /* At least one channel have radar flag */
dfs_check_chans_radar(struct hostapd_iface * iface,int start_chan_idx,int n_chans)452 static int dfs_check_chans_radar(struct hostapd_iface *iface,
453 int start_chan_idx, int n_chans)
454 {
455 struct hostapd_channel_data *channel;
456 struct hostapd_hw_modes *mode;
457 int i, res = 0;
458
459 mode = iface->current_mode;
460
461 for (i = 0; i < n_chans; i++) {
462 if (start_chan_idx + i >= mode->num_channels)
463 break;
464 channel = &mode->channels[start_chan_idx + i];
465 if (channel->flag & HOSTAPD_CHAN_RADAR)
466 res++;
467 }
468
469 return res;
470 }
471
472
473 /* All channels available */
dfs_check_chans_available(struct hostapd_iface * iface,int start_chan_idx,int n_chans)474 static int dfs_check_chans_available(struct hostapd_iface *iface,
475 int start_chan_idx, int n_chans)
476 {
477 struct hostapd_channel_data *channel;
478 struct hostapd_hw_modes *mode;
479 int i;
480
481 mode = iface->current_mode;
482
483 for (i = 0; i < n_chans; i++) {
484 channel = &mode->channels[start_chan_idx + i];
485
486 if (channel->flag & HOSTAPD_CHAN_DISABLED)
487 break;
488
489 if (!(channel->flag & HOSTAPD_CHAN_RADAR))
490 continue;
491
492 if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
493 HOSTAPD_CHAN_DFS_AVAILABLE)
494 break;
495 }
496
497 return i == n_chans;
498 }
499
500
501 /* At least one channel unavailable */
dfs_check_chans_unavailable(struct hostapd_iface * iface,int start_chan_idx,int n_chans)502 static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
503 int start_chan_idx,
504 int n_chans)
505 {
506 struct hostapd_channel_data *channel;
507 struct hostapd_hw_modes *mode;
508 int i, res = 0;
509
510 mode = iface->current_mode;
511
512 for (i = 0; i < n_chans; i++) {
513 channel = &mode->channels[start_chan_idx + i];
514 if (channel->flag & HOSTAPD_CHAN_DISABLED)
515 res++;
516 if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
517 HOSTAPD_CHAN_DFS_UNAVAILABLE)
518 res++;
519 }
520
521 return res;
522 }
523
524
525 static struct hostapd_channel_data *
dfs_get_valid_channel(struct hostapd_iface * iface,int * secondary_channel,u8 * oper_centr_freq_seg0_idx,u8 * oper_centr_freq_seg1_idx,enum dfs_channel_type type)526 dfs_get_valid_channel(struct hostapd_iface *iface,
527 int *secondary_channel,
528 u8 *oper_centr_freq_seg0_idx,
529 u8 *oper_centr_freq_seg1_idx,
530 enum dfs_channel_type type)
531 {
532 struct hostapd_hw_modes *mode;
533 struct hostapd_channel_data *chan = NULL;
534 struct hostapd_channel_data *chan2 = NULL;
535 int num_available_chandefs;
536 int chan_idx, chan_idx2;
537 int sec_chan_idx_80p80 = -1;
538 int i;
539 u32 _rand;
540
541 wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
542 *secondary_channel = 0;
543 *oper_centr_freq_seg0_idx = 0;
544 *oper_centr_freq_seg1_idx = 0;
545
546 if (iface->current_mode == NULL)
547 return NULL;
548
549 mode = iface->current_mode;
550 if (mode->mode != HOSTAPD_MODE_IEEE80211A)
551 return NULL;
552
553 /* Get the count first */
554 num_available_chandefs = dfs_find_channel(iface, NULL, 0, type);
555 wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
556 num_available_chandefs);
557 if (num_available_chandefs == 0)
558 return NULL;
559
560 if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
561 return NULL;
562 chan_idx = _rand % num_available_chandefs;
563 wpa_printf(MSG_DEBUG, "DFS: Picked random entry from the list: %d/%d",
564 chan_idx, num_available_chandefs);
565 dfs_find_channel(iface, &chan, chan_idx, type);
566 if (!chan) {
567 wpa_printf(MSG_DEBUG, "DFS: no random channel found");
568 return NULL;
569 }
570 wpa_printf(MSG_DEBUG, "DFS: got random channel %d (%d)",
571 chan->freq, chan->chan);
572
573 /* dfs_find_channel() calculations assume HT40+ */
574 if (iface->conf->secondary_channel)
575 *secondary_channel = 1;
576 else
577 *secondary_channel = 0;
578
579 /* Get secondary channel for HT80P80 */
580 if (hostapd_get_oper_chwidth(iface->conf) ==
581 CONF_OPER_CHWIDTH_80P80MHZ) {
582 if (num_available_chandefs <= 1) {
583 wpa_printf(MSG_ERROR,
584 "only 1 valid chan, can't support 80+80");
585 return NULL;
586 }
587
588 /*
589 * Loop all channels except channel1 to find a valid channel2
590 * that is not adjacent to channel1.
591 */
592 for (i = 0; i < num_available_chandefs - 1; i++) {
593 /* start from chan_idx + 1, end when chan_idx - 1 */
594 chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
595 dfs_find_channel(iface, &chan2, chan_idx2, type);
596 if (chan2 && abs(chan2->chan - chan->chan) > 12) {
597 /* two channels are not adjacent */
598 sec_chan_idx_80p80 = chan2->chan;
599 wpa_printf(MSG_DEBUG,
600 "DFS: got second chan: %d (%d)",
601 chan2->freq, chan2->chan);
602 break;
603 }
604 }
605
606 /* Check if we got a valid secondary channel which is not
607 * adjacent to the first channel.
608 */
609 if (sec_chan_idx_80p80 == -1) {
610 wpa_printf(MSG_INFO,
611 "DFS: failed to get chan2 for 80+80");
612 return NULL;
613 }
614 }
615
616 dfs_adjust_center_freq(iface, chan,
617 *secondary_channel,
618 sec_chan_idx_80p80,
619 oper_centr_freq_seg0_idx,
620 oper_centr_freq_seg1_idx);
621
622 return chan;
623 }
624
625
dfs_set_valid_channel(struct hostapd_iface * iface,int skip_radar)626 static int dfs_set_valid_channel(struct hostapd_iface *iface, int skip_radar)
627 {
628 struct hostapd_channel_data *channel;
629 u8 cf1 = 0, cf2 = 0;
630 int sec = 0;
631
632 channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
633 skip_radar ? DFS_AVAILABLE :
634 DFS_ANY_CHANNEL);
635 if (!channel) {
636 wpa_printf(MSG_ERROR, "could not get valid channel");
637 return -1;
638 }
639
640 iface->freq = channel->freq;
641 iface->conf->channel = channel->chan;
642 iface->conf->secondary_channel = sec;
643 hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
644 hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
645
646 return 0;
647 }
648
649
set_dfs_state_freq(struct hostapd_iface * iface,int freq,u32 state)650 static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
651 {
652 struct hostapd_hw_modes *mode;
653 struct hostapd_channel_data *chan = NULL;
654 int i;
655
656 mode = iface->current_mode;
657 if (mode == NULL)
658 return 0;
659
660 wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
661 for (i = 0; i < iface->current_mode->num_channels; i++) {
662 chan = &iface->current_mode->channels[i];
663 if (chan->freq == freq) {
664 if (chan->flag & HOSTAPD_CHAN_RADAR) {
665 chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
666 chan->flag |= state;
667 return 1; /* Channel found */
668 }
669 }
670 }
671 wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
672 return 0;
673 }
674
675
set_dfs_state(struct hostapd_iface * iface,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2,u32 state)676 static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
677 int chan_offset, int chan_width, int cf1,
678 int cf2, u32 state)
679 {
680 int n_chans = 1, i;
681 struct hostapd_hw_modes *mode;
682 int frequency = freq;
683 int frequency2 = 0;
684 int ret = 0;
685
686 mode = iface->current_mode;
687 if (mode == NULL)
688 return 0;
689
690 if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
691 wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
692 return 0;
693 }
694
695 /* Seems cf1 and chan_width is enough here */
696 switch (chan_width) {
697 case CHAN_WIDTH_20_NOHT:
698 case CHAN_WIDTH_20:
699 n_chans = 1;
700 if (frequency == 0)
701 frequency = cf1;
702 break;
703 case CHAN_WIDTH_40:
704 n_chans = 2;
705 frequency = cf1 - 10;
706 break;
707 case CHAN_WIDTH_80:
708 n_chans = 4;
709 frequency = cf1 - 30;
710 break;
711 case CHAN_WIDTH_80P80:
712 n_chans = 4;
713 frequency = cf1 - 30;
714 frequency2 = cf2 - 30;
715 break;
716 case CHAN_WIDTH_160:
717 n_chans = 8;
718 frequency = cf1 - 70;
719 break;
720 default:
721 wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
722 chan_width);
723 break;
724 }
725
726 wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
727 n_chans);
728 for (i = 0; i < n_chans; i++) {
729 ret += set_dfs_state_freq(iface, frequency, state);
730 frequency = frequency + 20;
731
732 if (chan_width == CHAN_WIDTH_80P80) {
733 ret += set_dfs_state_freq(iface, frequency2, state);
734 frequency2 = frequency2 + 20;
735 }
736 }
737
738 return ret;
739 }
740
741
dfs_are_channels_overlapped(struct hostapd_iface * iface,int freq,int chan_width,int cf1,int cf2)742 static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
743 int chan_width, int cf1, int cf2)
744 {
745 int start_chan_idx, start_chan_idx1;
746 struct hostapd_hw_modes *mode;
747 struct hostapd_channel_data *chan;
748 int n_chans, n_chans1, i, j, frequency = freq, radar_n_chans = 1;
749 u8 radar_chan;
750 int res = 0;
751
752 /* Our configuration */
753 mode = iface->current_mode;
754 start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
755 n_chans = dfs_get_used_n_chans(iface, &n_chans1);
756
757 /* Check we are on DFS channel(s) */
758 if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
759 return 0;
760
761 /* Reported via radar event */
762 switch (chan_width) {
763 case CHAN_WIDTH_20_NOHT:
764 case CHAN_WIDTH_20:
765 radar_n_chans = 1;
766 if (frequency == 0)
767 frequency = cf1;
768 break;
769 case CHAN_WIDTH_40:
770 radar_n_chans = 2;
771 frequency = cf1 - 10;
772 break;
773 case CHAN_WIDTH_80:
774 radar_n_chans = 4;
775 frequency = cf1 - 30;
776 break;
777 case CHAN_WIDTH_160:
778 radar_n_chans = 8;
779 frequency = cf1 - 70;
780 break;
781 default:
782 wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
783 chan_width);
784 break;
785 }
786
787 ieee80211_freq_to_chan(frequency, &radar_chan);
788
789 for (i = 0; i < n_chans; i++) {
790 chan = &mode->channels[start_chan_idx + i];
791 if (!(chan->flag & HOSTAPD_CHAN_RADAR))
792 continue;
793 for (j = 0; j < radar_n_chans; j++) {
794 wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
795 chan->chan, radar_chan + j * 4);
796 if (chan->chan == radar_chan + j * 4)
797 res++;
798 }
799 }
800
801 wpa_printf(MSG_DEBUG, "overlapped: %d", res);
802
803 return res;
804 }
805
806
dfs_get_cac_time(struct hostapd_iface * iface,int start_chan_idx,int n_chans)807 static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
808 int start_chan_idx, int n_chans)
809 {
810 struct hostapd_channel_data *channel;
811 struct hostapd_hw_modes *mode;
812 int i;
813 unsigned int cac_time_ms = 0;
814
815 mode = iface->current_mode;
816
817 for (i = 0; i < n_chans; i++) {
818 if (start_chan_idx + i >= mode->num_channels)
819 break;
820 channel = &mode->channels[start_chan_idx + i];
821 if (!(channel->flag & HOSTAPD_CHAN_RADAR))
822 continue;
823 if (channel->dfs_cac_ms > cac_time_ms)
824 cac_time_ms = channel->dfs_cac_ms;
825 }
826
827 return cac_time_ms;
828 }
829
830
831 /*
832 * Main DFS handler
833 * 1 - continue channel/ap setup
834 * 0 - channel/ap setup will be continued after CAC
835 * -1 - hit critical error
836 */
hostapd_handle_dfs(struct hostapd_iface * iface)837 int hostapd_handle_dfs(struct hostapd_iface *iface)
838 {
839 int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
840 int skip_radar = 0;
841
842 if (is_6ghz_freq(iface->freq))
843 return 1;
844
845 if (!iface->current_mode) {
846 /*
847 * This can happen with drivers that do not provide mode
848 * information and as such, cannot really use hostapd for DFS.
849 */
850 wpa_printf(MSG_DEBUG,
851 "DFS: No current_mode information - assume no need to perform DFS operations by hostapd");
852 return 1;
853 }
854
855 iface->cac_started = 0;
856
857 do {
858 /* Get start (first) channel for current configuration */
859 start_chan_idx = dfs_get_start_chan_idx(iface,
860 &start_chan_idx1);
861 if (start_chan_idx == -1)
862 return -1;
863
864 /* Get number of used channels, depend on width */
865 n_chans = dfs_get_used_n_chans(iface, &n_chans1);
866
867 /* Setup CAC time */
868 iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
869 n_chans);
870
871 /* Check if any of configured channels require DFS */
872 res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
873 wpa_printf(MSG_DEBUG,
874 "DFS %d channels required radar detection",
875 res);
876 if (!res)
877 return 1;
878
879 /* Check if all channels are DFS available */
880 res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
881 wpa_printf(MSG_DEBUG,
882 "DFS all channels available, (SKIP CAC): %s",
883 res ? "yes" : "no");
884 if (res)
885 return 1;
886
887 /* Check if any of configured channels is unavailable */
888 res = dfs_check_chans_unavailable(iface, start_chan_idx,
889 n_chans);
890 wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
891 res, res ? "yes": "no");
892 if (res) {
893 if (dfs_set_valid_channel(iface, skip_radar) < 0) {
894 hostapd_set_state(iface, HAPD_IFACE_DFS);
895 return 0;
896 }
897 }
898 } while (res);
899
900 /* Finally start CAC */
901 hostapd_set_state(iface, HAPD_IFACE_DFS);
902 wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz%s", iface->freq,
903 dfs_use_radar_background(iface) ? " (background)" : "");
904 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
905 "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
906 iface->freq,
907 iface->conf->channel, iface->conf->secondary_channel,
908 hostapd_get_oper_chwidth(iface->conf),
909 hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
910 hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
911 iface->dfs_cac_ms / 1000);
912
913 res = hostapd_start_dfs_cac(
914 iface, iface->conf->hw_mode, iface->freq, iface->conf->channel,
915 iface->conf->ieee80211n, iface->conf->ieee80211ac,
916 iface->conf->ieee80211ax, iface->conf->ieee80211be,
917 iface->conf->secondary_channel,
918 hostapd_get_oper_chwidth(iface->conf),
919 hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
920 hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
921 dfs_use_radar_background(iface));
922
923 if (res) {
924 wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
925 return -1;
926 }
927
928 if (dfs_use_radar_background(iface)) {
929 /* Cache background radar parameters. */
930 iface->radar_background.channel = iface->conf->channel;
931 iface->radar_background.secondary_channel =
932 iface->conf->secondary_channel;
933 iface->radar_background.freq = iface->freq;
934 iface->radar_background.centr_freq_seg0_idx =
935 hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
936 iface->radar_background.centr_freq_seg1_idx =
937 hostapd_get_oper_centr_freq_seg1_idx(iface->conf);
938
939 /*
940 * Let's select a random channel according to the
941 * regulations and perform CAC on dedicated radar chain.
942 */
943 res = dfs_set_valid_channel(iface, 1);
944 if (res < 0)
945 return res;
946
947 iface->radar_background.temp_ch = 1;
948 return 1;
949 }
950
951 return 0;
952 }
953
954
hostapd_is_dfs_chan_available(struct hostapd_iface * iface)955 int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
956 {
957 int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
958
959 /* Get the start (first) channel for current configuration */
960 start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
961 if (start_chan_idx < 0)
962 return 0;
963
964 /* Get the number of used channels, depending on width */
965 n_chans = dfs_get_used_n_chans(iface, &n_chans1);
966
967 /* Check if all channels are DFS available */
968 return dfs_check_chans_available(iface, start_chan_idx, n_chans);
969 }
970
971
hostapd_dfs_request_channel_switch(struct hostapd_iface * iface,int channel,int freq,int secondary_channel,u8 current_vht_oper_chwidth,u8 oper_centr_freq_seg0_idx,u8 oper_centr_freq_seg1_idx)972 static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
973 int channel, int freq,
974 int secondary_channel,
975 u8 current_vht_oper_chwidth,
976 u8 oper_centr_freq_seg0_idx,
977 u8 oper_centr_freq_seg1_idx)
978 {
979 struct hostapd_hw_modes *cmode = iface->current_mode;
980 int ieee80211_mode = IEEE80211_MODE_AP, err;
981 struct csa_settings csa_settings;
982 u8 new_vht_oper_chwidth;
983 unsigned int i;
984 unsigned int num_err = 0;
985 u8 op_class, chan;
986
987 wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel);
988 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
989 "freq=%d chan=%d sec_chan=%d", freq, channel,
990 secondary_channel);
991
992 new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
993 hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
994 if (ieee80211_freq_to_channel_ext(freq, secondary_channel,
995 new_vht_oper_chwidth, &op_class,
996 &chan) != NUM_HOSTAPD_MODES) {
997 wpa_printf(MSG_DEBUG, "Update op_class %d->%d",
998 iface->conf->op_class, op_class);
999 iface->conf->op_class = op_class;
1000 }
1001
1002 /* Setup CSA request */
1003 os_memset(&csa_settings, 0, sizeof(csa_settings));
1004 csa_settings.cs_count = 5;
1005 csa_settings.block_tx = 1;
1006 csa_settings.link_id = -1;
1007 #ifdef CONFIG_IEEE80211BE
1008 if (iface->bss[0]->conf->mld_ap)
1009 csa_settings.link_id = iface->bss[0]->mld_link_id;
1010 #endif /* CONFIG_IEEE80211BE */
1011 #ifdef CONFIG_MESH
1012 if (iface->mconf)
1013 ieee80211_mode = IEEE80211_MODE_MESH;
1014 #endif /* CONFIG_MESH */
1015 err = hostapd_set_freq_params(&csa_settings.freq_params,
1016 iface->conf->hw_mode,
1017 freq, channel,
1018 iface->conf->enable_edmg,
1019 iface->conf->edmg_channel,
1020 iface->conf->ieee80211n,
1021 iface->conf->ieee80211ac,
1022 iface->conf->ieee80211ax,
1023 iface->conf->ieee80211be,
1024 secondary_channel,
1025 new_vht_oper_chwidth,
1026 oper_centr_freq_seg0_idx,
1027 oper_centr_freq_seg1_idx,
1028 cmode->vht_capab,
1029 &cmode->he_capab[ieee80211_mode],
1030 &cmode->eht_capab[ieee80211_mode],
1031 hostapd_get_punct_bitmap(iface->bss[0]));
1032
1033 if (err) {
1034 wpa_printf(MSG_ERROR,
1035 "DFS failed to calculate CSA freq params");
1036 hostapd_disable_iface(iface);
1037 return err;
1038 }
1039
1040 for (i = 0; i < iface->num_bss; i++) {
1041 err = hostapd_switch_channel(iface->bss[i], &csa_settings);
1042 if (err)
1043 num_err++;
1044 }
1045
1046 if (num_err == iface->num_bss) {
1047 wpa_printf(MSG_WARNING,
1048 "DFS failed to schedule CSA (%d) - trying fallback",
1049 err);
1050 iface->freq = freq;
1051 iface->conf->channel = channel;
1052 iface->conf->secondary_channel = secondary_channel;
1053 hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
1054 hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
1055 oper_centr_freq_seg0_idx);
1056 hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
1057 oper_centr_freq_seg1_idx);
1058 if (ieee80211_freq_to_channel_ext(freq, secondary_channel,
1059 new_vht_oper_chwidth,
1060 &op_class, &chan) !=
1061 NUM_HOSTAPD_MODES) {
1062 wpa_printf(MSG_DEBUG, "Update op_class %d->%d",
1063 iface->conf->op_class, op_class);
1064 iface->conf->op_class = op_class;
1065 }
1066
1067 hostapd_disable_iface(iface);
1068 hostapd_enable_iface(iface);
1069
1070 return 0;
1071 }
1072
1073 /* Channel configuration will be updated once CSA completes and
1074 * ch_switch_notify event is received */
1075 wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
1076
1077 return 0;
1078 }
1079
1080
hostapd_dfs_update_background_chain(struct hostapd_iface * iface)1081 static void hostapd_dfs_update_background_chain(struct hostapd_iface *iface)
1082 {
1083 int sec = 0;
1084 enum dfs_channel_type channel_type = DFS_NO_CAC_YET;
1085 struct hostapd_channel_data *channel;
1086 u8 oper_centr_freq_seg0_idx = 0;
1087 u8 oper_centr_freq_seg1_idx = 0;
1088
1089 /*
1090 * Allow selection of DFS channel in ETSI to comply with
1091 * uniform spreading.
1092 */
1093 if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
1094 channel_type = DFS_ANY_CHANNEL;
1095
1096 channel = dfs_get_valid_channel(iface, &sec, &oper_centr_freq_seg0_idx,
1097 &oper_centr_freq_seg1_idx,
1098 channel_type);
1099 if (!channel ||
1100 channel->chan == iface->conf->channel ||
1101 channel->chan == iface->radar_background.channel)
1102 channel = dfs_downgrade_bandwidth(iface, &sec,
1103 &oper_centr_freq_seg0_idx,
1104 &oper_centr_freq_seg1_idx,
1105 &channel_type);
1106 if (!channel ||
1107 hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
1108 channel->freq, channel->chan,
1109 iface->conf->ieee80211n,
1110 iface->conf->ieee80211ac,
1111 iface->conf->ieee80211ax,
1112 iface->conf->ieee80211be,
1113 sec, hostapd_get_oper_chwidth(iface->conf),
1114 oper_centr_freq_seg0_idx,
1115 oper_centr_freq_seg1_idx, true)) {
1116 wpa_printf(MSG_ERROR, "DFS failed to start CAC offchannel");
1117 iface->radar_background.channel = -1;
1118 return;
1119 }
1120
1121 iface->radar_background.channel = channel->chan;
1122 iface->radar_background.freq = channel->freq;
1123 iface->radar_background.secondary_channel = sec;
1124 iface->radar_background.centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
1125 iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
1126
1127 wpa_printf(MSG_DEBUG,
1128 "%s: setting background chain to chan %d (%d MHz)",
1129 __func__, channel->chan, channel->freq);
1130 }
1131
1132
1133 static bool
hostapd_is_freq_in_current_hw_info(struct hostapd_iface * iface,int freq)1134 hostapd_is_freq_in_current_hw_info(struct hostapd_iface *iface, int freq)
1135 {
1136 struct hostapd_channel_data *chan;
1137
1138 if (!iface->current_mode)
1139 return false;
1140
1141 chan = hw_mode_get_channel(iface->current_mode, freq, NULL);
1142
1143 /* If channel data is not found for the given frequency, consider it is
1144 * out of the current hardware info. */
1145 if (!chan)
1146 return false;
1147
1148 return chan_in_current_hw_info(iface->current_hw_info, chan);
1149 }
1150
1151
1152 static bool
hostapd_dfs_is_background_event(struct hostapd_iface * iface,int freq)1153 hostapd_dfs_is_background_event(struct hostapd_iface *iface, int freq)
1154 {
1155 return dfs_use_radar_background(iface) &&
1156 iface->radar_background.channel != -1 &&
1157 iface->radar_background.freq == freq;
1158 }
1159
1160
1161 static int
hostapd_dfs_start_channel_switch_background(struct hostapd_iface * iface)1162 hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface)
1163 {
1164 u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
1165
1166 iface->conf->channel = iface->radar_background.channel;
1167 iface->freq = iface->radar_background.freq;
1168 iface->conf->secondary_channel =
1169 iface->radar_background.secondary_channel;
1170 hostapd_set_oper_centr_freq_seg0_idx(
1171 iface->conf, iface->radar_background.centr_freq_seg0_idx);
1172 hostapd_set_oper_centr_freq_seg1_idx(
1173 iface->conf, iface->radar_background.centr_freq_seg1_idx);
1174
1175 hostapd_dfs_update_background_chain(iface);
1176
1177 return hostapd_dfs_request_channel_switch(
1178 iface, iface->conf->channel, iface->freq,
1179 iface->conf->secondary_channel, current_vht_oper_chwidth,
1180 hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
1181 hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
1182 }
1183
1184
hostapd_dfs_complete_cac(struct hostapd_iface * iface,int success,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1185 int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
1186 int ht_enabled, int chan_offset, int chan_width,
1187 int cf1, int cf2)
1188 {
1189 if (!hostapd_is_freq_in_current_hw_info(iface, freq)) {
1190 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
1191 DFS_EVENT_CAC_COMPLETED
1192 "Ignoring since freq=%d info is out of own range",
1193 freq);
1194 return 0;
1195 }
1196
1197 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
1198 "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d radar_detected=%d",
1199 success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2,
1200 iface->radar_detected);
1201
1202 if (success) {
1203 /* Complete iface/ap configuration */
1204 if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
1205 /* Complete AP configuration for the first bring up. If
1206 * a radar was detected in this channel, interface setup
1207 * will be handled in
1208 * 1. hostapd_event_ch_switch() if switching to a
1209 * non-DFS channel
1210 * 2. on next CAC complete event if switching to another
1211 * DFS channel.
1212 */
1213 if (iface->state != HAPD_IFACE_ENABLED &&
1214 !iface->radar_detected)
1215 hostapd_setup_interface_complete(iface, 0);
1216 else
1217 iface->cac_started = 0;
1218 } else {
1219 set_dfs_state(iface, freq, ht_enabled, chan_offset,
1220 chan_width, cf1, cf2,
1221 HOSTAPD_CHAN_DFS_AVAILABLE);
1222
1223 /*
1224 * Radar event from background chain for the selected
1225 * channel. Perform CSA, move the main chain to the
1226 * selected channel and configure the background chain
1227 * to a new DFS channel.
1228 */
1229 if (hostapd_dfs_is_background_event(iface, freq)) {
1230 iface->radar_background.cac_started = 0;
1231 if (!iface->radar_background.temp_ch)
1232 return 0;
1233
1234 iface->radar_background.temp_ch = 0;
1235 return hostapd_dfs_start_channel_switch_background(iface);
1236 }
1237
1238 /*
1239 * Just mark the channel available when CAC completion
1240 * event is received in enabled state. CAC result could
1241 * have been propagated from another radio having the
1242 * same regulatory configuration. When CAC completion is
1243 * received during non-HAPD_IFACE_ENABLED state, make
1244 * sure the configured channel is available because this
1245 * CAC completion event could have been propagated from
1246 * another radio.
1247 */
1248 if (iface->state != HAPD_IFACE_ENABLED &&
1249 hostapd_is_dfs_chan_available(iface)) {
1250 hostapd_setup_interface_complete(iface, 0);
1251 iface->cac_started = 0;
1252 }
1253 }
1254 } else if (hostapd_dfs_is_background_event(iface, freq)) {
1255 iface->radar_background.cac_started = 0;
1256 hostapd_dfs_update_background_chain(iface);
1257 }
1258
1259 iface->radar_detected = false;
1260 return 0;
1261 }
1262
1263
hostapd_dfs_pre_cac_expired(struct hostapd_iface * iface,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1264 int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
1265 int ht_enabled, int chan_offset, int chan_width,
1266 int cf1, int cf2)
1267 {
1268 if (!hostapd_is_freq_in_current_hw_info(iface, freq)) {
1269 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
1270 DFS_EVENT_PRE_CAC_EXPIRED
1271 "Ignoring since freq=%d info is out of own range",
1272 freq);
1273 return 0;
1274 }
1275
1276 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_PRE_CAC_EXPIRED
1277 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
1278 freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
1279
1280 /* Proceed only if DFS is not offloaded to the driver */
1281 if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1282 return 0;
1283
1284 set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
1285 cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
1286
1287 return 0;
1288 }
1289
1290
1291 static struct hostapd_channel_data *
dfs_downgrade_bandwidth(struct hostapd_iface * iface,int * secondary_channel,u8 * oper_centr_freq_seg0_idx,u8 * oper_centr_freq_seg1_idx,enum dfs_channel_type * channel_type)1292 dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
1293 u8 *oper_centr_freq_seg0_idx,
1294 u8 *oper_centr_freq_seg1_idx,
1295 enum dfs_channel_type *channel_type)
1296 {
1297 struct hostapd_channel_data *channel;
1298
1299 for (;;) {
1300 channel = dfs_get_valid_channel(iface, secondary_channel,
1301 oper_centr_freq_seg0_idx,
1302 oper_centr_freq_seg1_idx,
1303 *channel_type);
1304 if (channel) {
1305 wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
1306 channel->chan);
1307 return channel;
1308 }
1309
1310 if (*channel_type != DFS_ANY_CHANNEL) {
1311 *channel_type = DFS_ANY_CHANNEL;
1312 } else {
1313 int oper_chwidth;
1314
1315 oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
1316 if (oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
1317 break;
1318 *channel_type = DFS_AVAILABLE;
1319 hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
1320 }
1321 }
1322
1323 wpa_printf(MSG_INFO,
1324 "%s: no DFS channels left, waiting for NOP to finish",
1325 __func__);
1326 return NULL;
1327 }
1328
1329
hostapd_dfs_start_channel_switch_cac(struct hostapd_iface * iface)1330 static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
1331 {
1332 struct hostapd_channel_data *channel;
1333 int secondary_channel;
1334 u8 oper_centr_freq_seg0_idx = 0;
1335 u8 oper_centr_freq_seg1_idx = 0;
1336 enum dfs_channel_type channel_type = DFS_ANY_CHANNEL;
1337 int err = 1;
1338 u8 op_class, chan;
1339
1340 /* Radar detected during active CAC */
1341 iface->cac_started = 0;
1342 channel = dfs_get_valid_channel(iface, &secondary_channel,
1343 &oper_centr_freq_seg0_idx,
1344 &oper_centr_freq_seg1_idx,
1345 channel_type);
1346
1347 if (!channel) {
1348 channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
1349 &oper_centr_freq_seg0_idx,
1350 &oper_centr_freq_seg1_idx,
1351 &channel_type);
1352 if (!channel) {
1353 wpa_printf(MSG_ERROR, "No valid channel available");
1354 return err;
1355 }
1356 }
1357
1358 wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
1359 channel->chan);
1360 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
1361 "freq=%d chan=%d sec_chan=%d", channel->freq,
1362 channel->chan, secondary_channel);
1363
1364 iface->freq = channel->freq;
1365 iface->conf->channel = channel->chan;
1366 iface->conf->secondary_channel = secondary_channel;
1367 hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
1368 oper_centr_freq_seg0_idx);
1369 hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
1370 oper_centr_freq_seg1_idx);
1371 if (ieee80211_freq_to_channel_ext(channel->freq, secondary_channel,
1372 hostapd_get_oper_chwidth(iface->conf),
1373 &op_class, &chan) !=
1374 NUM_HOSTAPD_MODES) {
1375 wpa_printf(MSG_DEBUG, "Update op_class %d->%d",
1376 iface->conf->op_class, op_class);
1377 iface->conf->op_class = op_class;
1378 }
1379 err = 0;
1380
1381 hostapd_setup_interface_complete(iface, err);
1382 return err;
1383 }
1384
1385
1386 static int
hostapd_dfs_background_start_channel_switch(struct hostapd_iface * iface,int freq)1387 hostapd_dfs_background_start_channel_switch(struct hostapd_iface *iface,
1388 int freq)
1389 {
1390 if (!dfs_use_radar_background(iface))
1391 return -1; /* Background radar chain not supported. */
1392
1393 wpa_printf(MSG_DEBUG,
1394 "%s called (background CAC active: %s, CSA active: %s)",
1395 __func__, iface->radar_background.cac_started ? "yes" : "no",
1396 hostapd_csa_in_progress(iface) ? "yes" : "no");
1397
1398 /* Check if CSA in progress */
1399 if (hostapd_csa_in_progress(iface))
1400 return 0;
1401
1402 if (hostapd_dfs_is_background_event(iface, freq)) {
1403 /*
1404 * Radar pattern is reported on the background chain.
1405 * Just select a new random channel according to the
1406 * regulations for monitoring.
1407 */
1408 hostapd_dfs_update_background_chain(iface);
1409 return 0;
1410 }
1411
1412 /*
1413 * If background radar detection is supported and the radar channel
1414 * monitored by the background chain is available switch to it without
1415 * waiting for the CAC.
1416 */
1417 if (iface->radar_background.channel == -1)
1418 return -1; /* Background radar chain not available. */
1419
1420 if (iface->radar_background.cac_started) {
1421 /*
1422 * Background channel not available yet. Perform CAC on the
1423 * main chain.
1424 */
1425 iface->radar_background.temp_ch = 1;
1426 return -1;
1427 }
1428
1429 return hostapd_dfs_start_channel_switch_background(iface);
1430 }
1431
1432
hostapd_dfs_start_channel_switch(struct hostapd_iface * iface)1433 static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
1434 {
1435 struct hostapd_channel_data *channel;
1436 int secondary_channel;
1437 u8 oper_centr_freq_seg0_idx;
1438 u8 oper_centr_freq_seg1_idx;
1439 enum dfs_channel_type channel_type = DFS_AVAILABLE;
1440 u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
1441
1442 wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
1443 __func__, iface->cac_started ? "yes" : "no",
1444 hostapd_csa_in_progress(iface) ? "yes" : "no");
1445
1446 /* Check if CSA in progress */
1447 if (hostapd_csa_in_progress(iface))
1448 return 0;
1449
1450 /* Check if active CAC */
1451 if (iface->cac_started)
1452 return hostapd_dfs_start_channel_switch_cac(iface);
1453
1454 /*
1455 * Allow selection of DFS channel in ETSI to comply with
1456 * uniform spreading.
1457 */
1458 if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
1459 channel_type = DFS_ANY_CHANNEL;
1460
1461 /* Perform channel switch/CSA */
1462 channel = dfs_get_valid_channel(iface, &secondary_channel,
1463 &oper_centr_freq_seg0_idx,
1464 &oper_centr_freq_seg1_idx,
1465 channel_type);
1466
1467 if (!channel) {
1468 /*
1469 * If there is no channel to switch immediately to, check if
1470 * there is another channel where we can switch even if it
1471 * requires to perform a CAC first.
1472 */
1473 channel_type = DFS_ANY_CHANNEL;
1474 channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
1475 &oper_centr_freq_seg0_idx,
1476 &oper_centr_freq_seg1_idx,
1477 &channel_type);
1478 if (!channel) {
1479 /*
1480 * Toggle interface state to enter DFS state
1481 * until NOP is finished.
1482 */
1483 hostapd_disable_iface(iface);
1484 hostapd_enable_iface(iface);
1485 return 0;
1486 }
1487
1488 if (channel_type == DFS_ANY_CHANNEL) {
1489 iface->freq = channel->freq;
1490 iface->conf->channel = channel->chan;
1491 iface->conf->secondary_channel = secondary_channel;
1492 hostapd_set_oper_centr_freq_seg0_idx(
1493 iface->conf, oper_centr_freq_seg0_idx);
1494 hostapd_set_oper_centr_freq_seg1_idx(
1495 iface->conf, oper_centr_freq_seg1_idx);
1496
1497 hostapd_disable_iface(iface);
1498 hostapd_enable_iface(iface);
1499 return 0;
1500 }
1501 }
1502
1503 return hostapd_dfs_request_channel_switch(iface, channel->chan,
1504 channel->freq,
1505 secondary_channel,
1506 current_vht_oper_chwidth,
1507 oper_centr_freq_seg0_idx,
1508 oper_centr_freq_seg1_idx);
1509 }
1510
1511
hostapd_dfs_radar_detected(struct hostapd_iface * iface,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1512 int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
1513 int ht_enabled, int chan_offset, int chan_width,
1514 int cf1, int cf2)
1515 {
1516 if (!hostapd_is_freq_in_current_hw_info(iface, freq)) {
1517 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
1518 DFS_EVENT_RADAR_DETECTED
1519 "Ignoring since freq=%d info is out of own range",
1520 freq);
1521 return 0;
1522 }
1523
1524 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
1525 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
1526 freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
1527
1528 iface->radar_detected = true;
1529
1530 /* Proceed only if DFS is not offloaded to the driver */
1531 if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1532 return 0;
1533
1534 if (!iface->conf->ieee80211h)
1535 return 0;
1536
1537 /* mark radar frequency as invalid */
1538 if (!set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
1539 cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE))
1540 return 0;
1541
1542 if (!hostapd_dfs_is_background_event(iface, freq)) {
1543 /* Skip if reported radar event not overlapped our channels */
1544 if (!dfs_are_channels_overlapped(iface, freq, chan_width,
1545 cf1, cf2))
1546 return 0;
1547 }
1548
1549 if (hostapd_dfs_background_start_channel_switch(iface, freq)) {
1550 /* Radar detected while operating, switch the channel. */
1551 return hostapd_dfs_start_channel_switch(iface);
1552 }
1553
1554 return 0;
1555 }
1556
1557
hostapd_dfs_nop_finished(struct hostapd_iface * iface,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1558 int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
1559 int ht_enabled, int chan_offset, int chan_width,
1560 int cf1, int cf2)
1561 {
1562 if (!hostapd_is_freq_in_current_hw_info(iface, freq)) {
1563 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
1564 DFS_EVENT_NOP_FINISHED
1565 "Ignoring since freq=%d info is out of own range",
1566 freq);
1567 return 0;
1568 }
1569
1570 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
1571 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
1572 freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
1573
1574 /* Proceed only if DFS is not offloaded to the driver */
1575 if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1576 return 0;
1577
1578 /* TODO add correct implementation here */
1579 set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
1580 cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
1581
1582 if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) {
1583 /* Handle cases where all channels were initially unavailable */
1584 hostapd_handle_dfs(iface);
1585 } else if (dfs_use_radar_background(iface) &&
1586 iface->radar_background.channel == -1) {
1587 /* Reset radar background chain if disabled */
1588 hostapd_dfs_update_background_chain(iface);
1589 }
1590
1591 return 0;
1592 }
1593
1594
hostapd_is_dfs_required(struct hostapd_iface * iface)1595 int hostapd_is_dfs_required(struct hostapd_iface *iface)
1596 {
1597 int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res;
1598
1599 if ((!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
1600 !iface->conf->ieee80211h) ||
1601 !iface->current_mode ||
1602 iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
1603 return 0;
1604
1605 /* Get start (first) channel for current configuration */
1606 start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
1607 if (start_chan_idx == -1)
1608 return -1;
1609
1610 /* Get number of used channels, depend on width */
1611 n_chans = dfs_get_used_n_chans(iface, &n_chans1);
1612
1613 /* Check if any of configured channels require DFS */
1614 res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
1615 if (res)
1616 return res;
1617 if (start_chan_idx1 >= 0 && n_chans1 > 0)
1618 res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
1619 return res;
1620 }
1621
1622
hostapd_dfs_start_cac(struct hostapd_data * hapd,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1623 int hostapd_dfs_start_cac(struct hostapd_data *hapd, int freq,
1624 int ht_enabled, int chan_offset, int chan_width,
1625 int cf1, int cf2)
1626 {
1627 struct hostapd_iface *iface = hapd->iface;
1628
1629 if (!hostapd_is_freq_in_current_hw_info(iface, freq)) {
1630 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
1631 "Ignoring since freq=%d info is out of own range",
1632 freq);
1633 return 0;
1634 }
1635
1636 if (hostapd_dfs_is_background_event(iface, freq)) {
1637 iface->radar_background.cac_started = 1;
1638 } else {
1639 /* This is called when the driver indicates that an offloaded
1640 * DFS has started CAC. radar_detected might be set for previous
1641 * DFS channel. Clear it for this new CAC process. */
1642 hostapd_set_state(iface, HAPD_IFACE_DFS);
1643 iface->cac_started = 1;
1644
1645 /* Clear radar_detected in case it is for the previous
1646 * frequency. Also remove disabled link's information in RNR
1647 * element from other links. */
1648 iface->radar_detected = false;
1649 if (iface->interfaces && iface->interfaces->count > 1)
1650 ieee802_11_set_beacons(iface);
1651 }
1652 /* TODO: How to check CAC time for ETSI weather channels? */
1653 iface->dfs_cac_ms = 60000;
1654 wpa_msg(hapd->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
1655 "freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
1656 "seg1=%d cac_time=%ds%s",
1657 freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
1658 iface->dfs_cac_ms / 1000,
1659 hostapd_dfs_is_background_event(iface, freq) ?
1660 " (background)" : "");
1661
1662 os_get_reltime(&iface->dfs_cac_start);
1663 return 0;
1664 }
1665
1666
1667 /*
1668 * Main DFS handler for offloaded case.
1669 * 2 - continue channel/AP setup for non-DFS channel
1670 * 1 - continue channel/AP setup for DFS channel
1671 * 0 - channel/AP setup will be continued after CAC
1672 * -1 - hit critical error
1673 */
hostapd_handle_dfs_offload(struct hostapd_iface * iface)1674 int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
1675 {
1676 int dfs_res;
1677
1678 wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
1679 __func__, iface->cac_started);
1680
1681 /*
1682 * If DFS has already been started, then we are being called from a
1683 * callback to continue AP/channel setup. Reset the CAC start flag and
1684 * return.
1685 */
1686 if (iface->cac_started) {
1687 wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
1688 __func__, iface->cac_started);
1689 iface->cac_started = 0;
1690 return 1;
1691 }
1692
1693 dfs_res = hostapd_is_dfs_required(iface);
1694 if (dfs_res > 0) {
1695 wpa_printf(MSG_DEBUG,
1696 "%s: freq %d MHz requires DFS for %d chans",
1697 __func__, iface->freq, dfs_res);
1698 return 0;
1699 }
1700
1701 wpa_printf(MSG_DEBUG,
1702 "%s: freq %d MHz does not require DFS. Continue channel/AP setup",
1703 __func__, iface->freq);
1704 return 2;
1705 }
1706
1707
hostapd_is_dfs_overlap(struct hostapd_iface * iface,enum chan_width width,int center_freq)1708 int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
1709 int center_freq)
1710 {
1711 struct hostapd_channel_data *chan;
1712 struct hostapd_hw_modes *mode = iface->current_mode;
1713 int half_width;
1714 int res = 0;
1715 int i;
1716
1717 if (!iface->conf->ieee80211h || !mode ||
1718 mode->mode != HOSTAPD_MODE_IEEE80211A)
1719 return 0;
1720
1721 switch (width) {
1722 case CHAN_WIDTH_20_NOHT:
1723 case CHAN_WIDTH_20:
1724 half_width = 10;
1725 break;
1726 case CHAN_WIDTH_40:
1727 half_width = 20;
1728 break;
1729 case CHAN_WIDTH_80:
1730 case CHAN_WIDTH_80P80:
1731 half_width = 40;
1732 break;
1733 case CHAN_WIDTH_160:
1734 half_width = 80;
1735 break;
1736 default:
1737 wpa_printf(MSG_WARNING, "DFS chanwidth %d not supported",
1738 width);
1739 return 0;
1740 }
1741
1742 for (i = 0; i < mode->num_channels; i++) {
1743 chan = &mode->channels[i];
1744
1745 if (!(chan->flag & HOSTAPD_CHAN_RADAR))
1746 continue;
1747
1748 if ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
1749 HOSTAPD_CHAN_DFS_AVAILABLE)
1750 continue;
1751
1752 if (center_freq - chan->freq < half_width &&
1753 chan->freq - center_freq < half_width)
1754 res++;
1755 }
1756
1757 wpa_printf(MSG_DEBUG, "DFS CAC required: (%d, %d): in range: %s",
1758 center_freq - half_width, center_freq + half_width,
1759 res ? "yes" : "no");
1760
1761 return res;
1762 }
1763