Line data Source code
1 : /*
2 : * DFS - Dynamic Frequency Selection
3 : * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
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 :
12 : #include "utils/common.h"
13 : #include "common/ieee802_11_defs.h"
14 : #include "common/wpa_ctrl.h"
15 : #include "hostapd.h"
16 : #include "ap_drv_ops.h"
17 : #include "drivers/driver.h"
18 : #include "dfs.h"
19 :
20 :
21 664 : static int dfs_get_used_n_chans(struct hostapd_iface *iface)
22 : {
23 664 : int n_chans = 1;
24 :
25 664 : if (iface->conf->ieee80211n && iface->conf->secondary_channel)
26 22 : n_chans = 2;
27 :
28 664 : if (iface->conf->ieee80211ac) {
29 11 : switch (iface->conf->vht_oper_chwidth) {
30 : case VHT_CHANWIDTH_USE_HT:
31 9 : break;
32 : case VHT_CHANWIDTH_80MHZ:
33 2 : n_chans = 4;
34 2 : break;
35 : case VHT_CHANWIDTH_160MHZ:
36 0 : n_chans = 8;
37 0 : break;
38 : default:
39 0 : break;
40 : }
41 : }
42 :
43 664 : return n_chans;
44 : }
45 :
46 :
47 0 : static int dfs_channel_available(struct hostapd_channel_data *chan,
48 : int skip_radar)
49 : {
50 : /*
51 : * When radar detection happens, CSA is performed. However, there's no
52 : * time for CAC, so radar channels must be skipped when finding a new
53 : * channel for CSA, unless they are available for immediate use.
54 : */
55 0 : if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
56 0 : ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
57 : HOSTAPD_CHAN_DFS_AVAILABLE))
58 0 : return 0;
59 :
60 0 : if (chan->flag & HOSTAPD_CHAN_DISABLED)
61 0 : return 0;
62 0 : if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
63 0 : ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
64 : HOSTAPD_CHAN_DFS_UNAVAILABLE))
65 0 : return 0;
66 0 : return 1;
67 : }
68 :
69 :
70 0 : static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
71 : {
72 : /*
73 : * The tables contain first valid channel number based on channel width.
74 : * We will also choose this first channel as the control one.
75 : */
76 0 : int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
77 : 184, 192 };
78 : /*
79 : * VHT80, valid channels based on center frequency:
80 : * 42, 58, 106, 122, 138, 155
81 : */
82 0 : int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
83 : /*
84 : * VHT160 valid channels based on center frequency:
85 : * 50, 114
86 : */
87 0 : int allowed_160[] = { 36, 100 };
88 0 : int *allowed = allowed_40;
89 0 : unsigned int i, allowed_no = 0;
90 :
91 0 : switch (n_chans) {
92 : case 2:
93 0 : allowed = allowed_40;
94 0 : allowed_no = ARRAY_SIZE(allowed_40);
95 0 : break;
96 : case 4:
97 0 : allowed = allowed_80;
98 0 : allowed_no = ARRAY_SIZE(allowed_80);
99 0 : break;
100 : case 8:
101 0 : allowed = allowed_160;
102 0 : allowed_no = ARRAY_SIZE(allowed_160);
103 0 : break;
104 : default:
105 0 : wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
106 0 : break;
107 : }
108 :
109 0 : for (i = 0; i < allowed_no; i++) {
110 0 : if (chan->chan == allowed[i])
111 0 : return 1;
112 : }
113 :
114 0 : return 0;
115 : }
116 :
117 :
118 0 : static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
119 : int first_chan_idx, int num_chans,
120 : int skip_radar)
121 : {
122 : struct hostapd_channel_data *first_chan, *chan;
123 : int i;
124 :
125 0 : if (first_chan_idx + num_chans >= mode->num_channels)
126 0 : return 0;
127 :
128 0 : first_chan = &mode->channels[first_chan_idx];
129 :
130 0 : for (i = 0; i < num_chans; i++) {
131 0 : chan = &mode->channels[first_chan_idx + i];
132 :
133 0 : if (first_chan->freq + i * 20 != chan->freq)
134 0 : return 0;
135 :
136 0 : if (!dfs_channel_available(chan, skip_radar))
137 0 : return 0;
138 : }
139 :
140 0 : return 1;
141 : }
142 :
143 :
144 0 : static int is_in_chanlist(struct hostapd_iface *iface,
145 : struct hostapd_channel_data *chan)
146 : {
147 : int *entry;
148 :
149 0 : if (!iface->conf->chanlist)
150 0 : return 1;
151 :
152 0 : for (entry = iface->conf->chanlist; *entry != -1; entry++) {
153 0 : if (*entry == chan->chan)
154 0 : return 1;
155 : }
156 0 : return 0;
157 : }
158 :
159 :
160 : /*
161 : * The function assumes HT40+ operation.
162 : * Make sure to adjust the following variables after calling this:
163 : * - hapd->secondary_channel
164 : * - hapd->vht_oper_centr_freq_seg0_idx
165 : * - hapd->vht_oper_centr_freq_seg1_idx
166 : */
167 0 : static int dfs_find_channel(struct hostapd_iface *iface,
168 : struct hostapd_channel_data **ret_chan,
169 : int idx, int skip_radar)
170 : {
171 : struct hostapd_hw_modes *mode;
172 : struct hostapd_channel_data *chan;
173 0 : int i, channel_idx = 0, n_chans;
174 :
175 0 : mode = iface->current_mode;
176 0 : n_chans = dfs_get_used_n_chans(iface);
177 :
178 0 : wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
179 0 : for (i = 0; i < mode->num_channels; i++) {
180 0 : chan = &mode->channels[i];
181 :
182 : /* Skip HT40/VHT incompatible channels */
183 0 : if (iface->conf->ieee80211n &&
184 0 : iface->conf->secondary_channel &&
185 0 : !dfs_is_chan_allowed(chan, n_chans))
186 0 : continue;
187 :
188 : /* Skip incompatible chandefs */
189 0 : if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
190 0 : continue;
191 :
192 0 : if (!is_in_chanlist(iface, chan))
193 0 : continue;
194 :
195 0 : if (ret_chan && idx == channel_idx) {
196 0 : wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
197 0 : *ret_chan = chan;
198 0 : return idx;
199 : }
200 0 : wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
201 0 : channel_idx++;
202 : }
203 0 : return channel_idx;
204 : }
205 :
206 :
207 0 : static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
208 : struct hostapd_channel_data *chan,
209 : int secondary_channel,
210 : u8 *vht_oper_centr_freq_seg0_idx,
211 : u8 *vht_oper_centr_freq_seg1_idx)
212 : {
213 0 : if (!iface->conf->ieee80211ac)
214 0 : return;
215 :
216 0 : if (!chan)
217 0 : return;
218 :
219 0 : *vht_oper_centr_freq_seg1_idx = 0;
220 :
221 0 : switch (iface->conf->vht_oper_chwidth) {
222 : case VHT_CHANWIDTH_USE_HT:
223 0 : if (secondary_channel == 1)
224 0 : *vht_oper_centr_freq_seg0_idx = chan->chan + 2;
225 0 : else if (secondary_channel == -1)
226 0 : *vht_oper_centr_freq_seg0_idx = chan->chan - 2;
227 : else
228 0 : *vht_oper_centr_freq_seg0_idx = chan->chan;
229 0 : break;
230 : case VHT_CHANWIDTH_80MHZ:
231 0 : *vht_oper_centr_freq_seg0_idx = chan->chan + 6;
232 0 : break;
233 : case VHT_CHANWIDTH_160MHZ:
234 0 : *vht_oper_centr_freq_seg0_idx = chan->chan + 14;
235 0 : break;
236 : default:
237 0 : wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
238 0 : *vht_oper_centr_freq_seg0_idx = 0;
239 0 : break;
240 : }
241 :
242 0 : wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
243 0 : *vht_oper_centr_freq_seg0_idx,
244 0 : *vht_oper_centr_freq_seg1_idx);
245 : }
246 :
247 :
248 : /* Return start channel idx we will use for mode->channels[idx] */
249 664 : static int dfs_get_start_chan_idx(struct hostapd_iface *iface)
250 : {
251 : struct hostapd_hw_modes *mode;
252 : struct hostapd_channel_data *chan;
253 664 : int channel_no = iface->conf->channel;
254 664 : int res = -1, i;
255 :
256 : /* HT40- */
257 664 : if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
258 8 : channel_no -= 4;
259 :
260 : /* VHT */
261 664 : if (iface->conf->ieee80211ac) {
262 11 : switch (iface->conf->vht_oper_chwidth) {
263 : case VHT_CHANWIDTH_USE_HT:
264 9 : break;
265 : case VHT_CHANWIDTH_80MHZ:
266 2 : channel_no =
267 2 : iface->conf->vht_oper_centr_freq_seg0_idx - 6;
268 2 : break;
269 : case VHT_CHANWIDTH_160MHZ:
270 0 : channel_no =
271 0 : iface->conf->vht_oper_centr_freq_seg0_idx - 14;
272 0 : break;
273 : default:
274 0 : wpa_printf(MSG_INFO,
275 : "DFS only VHT20/40/80/160 is supported now");
276 0 : channel_no = -1;
277 0 : break;
278 : }
279 : }
280 :
281 : /* Get idx */
282 664 : mode = iface->current_mode;
283 1452 : for (i = 0; i < mode->num_channels; i++) {
284 1452 : chan = &mode->channels[i];
285 1452 : if (chan->chan == channel_no) {
286 664 : res = i;
287 664 : break;
288 : }
289 : }
290 :
291 664 : if (res == -1) {
292 0 : wpa_printf(MSG_DEBUG,
293 : "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d",
294 0 : mode->num_channels, channel_no, iface->conf->channel,
295 0 : iface->conf->ieee80211n,
296 0 : iface->conf->secondary_channel,
297 0 : iface->conf->vht_oper_chwidth);
298 :
299 0 : for (i = 0; i < mode->num_channels; i++) {
300 0 : wpa_printf(MSG_DEBUG, "Available channel: %d",
301 0 : mode->channels[i].chan);
302 : }
303 : }
304 :
305 664 : return res;
306 : }
307 :
308 :
309 : /* At least one channel have radar flag */
310 664 : static int dfs_check_chans_radar(struct hostapd_iface *iface,
311 : int start_chan_idx, int n_chans)
312 : {
313 : struct hostapd_channel_data *channel;
314 : struct hostapd_hw_modes *mode;
315 664 : int i, res = 0;
316 :
317 664 : mode = iface->current_mode;
318 :
319 1354 : for (i = 0; i < n_chans; i++) {
320 690 : channel = &mode->channels[start_chan_idx + i];
321 690 : if (channel->flag & HOSTAPD_CHAN_RADAR)
322 1 : res++;
323 : }
324 :
325 664 : return res;
326 : }
327 :
328 :
329 : /* All channels available */
330 1 : static int dfs_check_chans_available(struct hostapd_iface *iface,
331 : int start_chan_idx, int n_chans)
332 : {
333 : struct hostapd_channel_data *channel;
334 : struct hostapd_hw_modes *mode;
335 : int i;
336 :
337 1 : mode = iface->current_mode;
338 :
339 1 : for (i = 0; i < n_chans; i++) {
340 1 : channel = &mode->channels[start_chan_idx + i];
341 :
342 1 : if (channel->flag & HOSTAPD_CHAN_DISABLED)
343 0 : break;
344 :
345 1 : if (!(channel->flag & HOSTAPD_CHAN_RADAR))
346 0 : continue;
347 :
348 1 : if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
349 : HOSTAPD_CHAN_DFS_AVAILABLE)
350 1 : break;
351 : }
352 :
353 1 : return i == n_chans;
354 : }
355 :
356 :
357 : /* At least one channel unavailable */
358 1 : static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
359 : int start_chan_idx,
360 : int n_chans)
361 : {
362 : struct hostapd_channel_data *channel;
363 : struct hostapd_hw_modes *mode;
364 1 : int i, res = 0;
365 :
366 1 : mode = iface->current_mode;
367 :
368 2 : for (i = 0; i < n_chans; i++) {
369 1 : channel = &mode->channels[start_chan_idx + i];
370 1 : if (channel->flag & HOSTAPD_CHAN_DISABLED)
371 0 : res++;
372 1 : if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
373 : HOSTAPD_CHAN_DFS_UNAVAILABLE)
374 0 : res++;
375 : }
376 :
377 1 : return res;
378 : }
379 :
380 :
381 : static struct hostapd_channel_data *
382 0 : dfs_get_valid_channel(struct hostapd_iface *iface,
383 : int *secondary_channel,
384 : u8 *vht_oper_centr_freq_seg0_idx,
385 : u8 *vht_oper_centr_freq_seg1_idx,
386 : int skip_radar)
387 : {
388 : struct hostapd_hw_modes *mode;
389 0 : struct hostapd_channel_data *chan = NULL;
390 : int num_available_chandefs;
391 : int chan_idx;
392 : u32 _rand;
393 :
394 0 : wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
395 0 : *secondary_channel = 0;
396 0 : *vht_oper_centr_freq_seg0_idx = 0;
397 0 : *vht_oper_centr_freq_seg1_idx = 0;
398 :
399 0 : if (iface->current_mode == NULL)
400 0 : return NULL;
401 :
402 0 : mode = iface->current_mode;
403 0 : if (mode->mode != HOSTAPD_MODE_IEEE80211A)
404 0 : return NULL;
405 :
406 : /* Get the count first */
407 0 : num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
408 0 : if (num_available_chandefs == 0)
409 0 : return NULL;
410 :
411 0 : os_get_random((u8 *) &_rand, sizeof(_rand));
412 0 : chan_idx = _rand % num_available_chandefs;
413 0 : dfs_find_channel(iface, &chan, chan_idx, skip_radar);
414 :
415 : /* dfs_find_channel() calculations assume HT40+ */
416 0 : if (iface->conf->secondary_channel)
417 0 : *secondary_channel = 1;
418 : else
419 0 : *secondary_channel = 0;
420 :
421 0 : dfs_adjust_vht_center_freq(iface, chan,
422 : *secondary_channel,
423 : vht_oper_centr_freq_seg0_idx,
424 : vht_oper_centr_freq_seg1_idx);
425 :
426 0 : return chan;
427 : }
428 :
429 :
430 0 : static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
431 : {
432 : struct hostapd_hw_modes *mode;
433 0 : struct hostapd_channel_data *chan = NULL;
434 : int i;
435 :
436 0 : mode = iface->current_mode;
437 0 : if (mode == NULL)
438 0 : return 0;
439 :
440 0 : wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
441 0 : for (i = 0; i < iface->current_mode->num_channels; i++) {
442 0 : chan = &iface->current_mode->channels[i];
443 0 : if (chan->freq == freq) {
444 0 : if (chan->flag & HOSTAPD_CHAN_RADAR) {
445 0 : chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
446 0 : chan->flag |= state;
447 0 : return 1; /* Channel found */
448 : }
449 : }
450 : }
451 0 : wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
452 0 : return 0;
453 : }
454 :
455 :
456 0 : static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
457 : int chan_offset, int chan_width, int cf1,
458 : int cf2, u32 state)
459 : {
460 0 : int n_chans = 1, i;
461 : struct hostapd_hw_modes *mode;
462 0 : int frequency = freq;
463 0 : int ret = 0;
464 :
465 0 : mode = iface->current_mode;
466 0 : if (mode == NULL)
467 0 : return 0;
468 :
469 0 : if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
470 0 : wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
471 0 : return 0;
472 : }
473 :
474 : /* Seems cf1 and chan_width is enough here */
475 0 : switch (chan_width) {
476 : case CHAN_WIDTH_20_NOHT:
477 : case CHAN_WIDTH_20:
478 0 : n_chans = 1;
479 0 : if (frequency == 0)
480 0 : frequency = cf1;
481 0 : break;
482 : case CHAN_WIDTH_40:
483 0 : n_chans = 2;
484 0 : frequency = cf1 - 10;
485 0 : break;
486 : case CHAN_WIDTH_80:
487 0 : n_chans = 4;
488 0 : frequency = cf1 - 30;
489 0 : break;
490 : case CHAN_WIDTH_160:
491 0 : n_chans = 8;
492 0 : frequency = cf1 - 70;
493 0 : break;
494 : default:
495 0 : wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
496 : chan_width);
497 0 : break;
498 : }
499 :
500 0 : wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
501 : n_chans);
502 0 : for (i = 0; i < n_chans; i++) {
503 0 : ret += set_dfs_state_freq(iface, frequency, state);
504 0 : frequency = frequency + 20;
505 : }
506 :
507 0 : return ret;
508 : }
509 :
510 :
511 0 : static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
512 : int chan_width, int cf1, int cf2)
513 : {
514 : int start_chan_idx;
515 : struct hostapd_hw_modes *mode;
516 : struct hostapd_channel_data *chan;
517 0 : int n_chans, i, j, frequency = freq, radar_n_chans = 1;
518 : u8 radar_chan;
519 0 : int res = 0;
520 :
521 : /* Our configuration */
522 0 : mode = iface->current_mode;
523 0 : start_chan_idx = dfs_get_start_chan_idx(iface);
524 0 : n_chans = dfs_get_used_n_chans(iface);
525 :
526 : /* Check we are on DFS channel(s) */
527 0 : if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
528 0 : return 0;
529 :
530 : /* Reported via radar event */
531 0 : switch (chan_width) {
532 : case CHAN_WIDTH_20_NOHT:
533 : case CHAN_WIDTH_20:
534 0 : radar_n_chans = 1;
535 0 : if (frequency == 0)
536 0 : frequency = cf1;
537 0 : break;
538 : case CHAN_WIDTH_40:
539 0 : radar_n_chans = 2;
540 0 : frequency = cf1 - 10;
541 0 : break;
542 : case CHAN_WIDTH_80:
543 0 : radar_n_chans = 4;
544 0 : frequency = cf1 - 30;
545 0 : break;
546 : case CHAN_WIDTH_160:
547 0 : radar_n_chans = 8;
548 0 : frequency = cf1 - 70;
549 0 : break;
550 : default:
551 0 : wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
552 : chan_width);
553 0 : break;
554 : }
555 :
556 0 : ieee80211_freq_to_chan(frequency, &radar_chan);
557 :
558 0 : for (i = 0; i < n_chans; i++) {
559 0 : chan = &mode->channels[start_chan_idx + i];
560 0 : if (!(chan->flag & HOSTAPD_CHAN_RADAR))
561 0 : continue;
562 0 : for (j = 0; j < radar_n_chans; j++) {
563 0 : wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
564 0 : chan->chan, radar_chan + j * 4);
565 0 : if (chan->chan == radar_chan + j * 4)
566 0 : res++;
567 : }
568 : }
569 :
570 0 : wpa_printf(MSG_DEBUG, "overlapped: %d", res);
571 :
572 0 : return res;
573 : }
574 :
575 :
576 664 : static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
577 : int start_chan_idx, int n_chans)
578 : {
579 : struct hostapd_channel_data *channel;
580 : struct hostapd_hw_modes *mode;
581 : int i;
582 664 : unsigned int cac_time_ms = 0;
583 :
584 664 : mode = iface->current_mode;
585 :
586 1354 : for (i = 0; i < n_chans; i++) {
587 690 : channel = &mode->channels[start_chan_idx + i];
588 690 : if (!(channel->flag & HOSTAPD_CHAN_RADAR))
589 689 : continue;
590 1 : if (channel->dfs_cac_ms > cac_time_ms)
591 1 : cac_time_ms = channel->dfs_cac_ms;
592 : }
593 :
594 664 : return cac_time_ms;
595 : }
596 :
597 :
598 : /*
599 : * Main DFS handler
600 : * 1 - continue channel/ap setup
601 : * 0 - channel/ap setup will be continued after CAC
602 : * -1 - hit critical error
603 : */
604 664 : int hostapd_handle_dfs(struct hostapd_iface *iface)
605 : {
606 : struct hostapd_channel_data *channel;
607 : int res, n_chans, start_chan_idx;
608 664 : int skip_radar = 0;
609 :
610 664 : iface->cac_started = 0;
611 :
612 : do {
613 : /* Get start (first) channel for current configuration */
614 664 : start_chan_idx = dfs_get_start_chan_idx(iface);
615 664 : if (start_chan_idx == -1)
616 0 : return -1;
617 :
618 : /* Get number of used channels, depend on width */
619 664 : n_chans = dfs_get_used_n_chans(iface);
620 :
621 : /* Setup CAC time */
622 664 : iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
623 : n_chans);
624 :
625 : /* Check if any of configured channels require DFS */
626 664 : res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
627 664 : wpa_printf(MSG_DEBUG,
628 : "DFS %d channels required radar detection",
629 : res);
630 664 : if (!res)
631 663 : return 1;
632 :
633 : /* Check if all channels are DFS available */
634 1 : res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
635 1 : wpa_printf(MSG_DEBUG,
636 : "DFS all channels available, (SKIP CAC): %s",
637 : res ? "yes" : "no");
638 1 : if (res)
639 0 : return 1;
640 :
641 : /* Check if any of configured channels is unavailable */
642 1 : res = dfs_check_chans_unavailable(iface, start_chan_idx,
643 : n_chans);
644 1 : wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
645 : res, res ? "yes": "no");
646 1 : if (res) {
647 0 : int sec = 0;
648 0 : u8 cf1 = 0, cf2 = 0;
649 :
650 0 : channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
651 : skip_radar);
652 0 : if (!channel) {
653 0 : wpa_printf(MSG_ERROR, "could not get valid channel");
654 0 : return -1;
655 : }
656 :
657 0 : iface->freq = channel->freq;
658 0 : iface->conf->channel = channel->chan;
659 0 : iface->conf->secondary_channel = sec;
660 0 : iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
661 0 : iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
662 : }
663 1 : } while (res);
664 :
665 : /* Finally start CAC */
666 1 : hostapd_set_state(iface, HAPD_IFACE_DFS);
667 1 : wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
668 6 : wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
669 : "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
670 : iface->freq,
671 2 : iface->conf->channel, iface->conf->secondary_channel,
672 1 : iface->conf->vht_oper_chwidth,
673 1 : iface->conf->vht_oper_centr_freq_seg0_idx,
674 1 : iface->conf->vht_oper_centr_freq_seg1_idx,
675 1 : iface->dfs_cac_ms / 1000);
676 :
677 7 : res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
678 : iface->freq,
679 1 : iface->conf->channel,
680 1 : iface->conf->ieee80211n,
681 1 : iface->conf->ieee80211ac,
682 1 : iface->conf->secondary_channel,
683 1 : iface->conf->vht_oper_chwidth,
684 1 : iface->conf->vht_oper_centr_freq_seg0_idx,
685 1 : iface->conf->vht_oper_centr_freq_seg1_idx);
686 :
687 1 : if (res) {
688 1 : wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
689 1 : return -1;
690 : }
691 :
692 0 : return 0;
693 : }
694 :
695 :
696 0 : int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
697 : int ht_enabled, int chan_offset, int chan_width,
698 : int cf1, int cf2)
699 : {
700 0 : wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
701 : "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
702 : success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
703 :
704 0 : if (success) {
705 : /* Complete iface/ap configuration */
706 0 : set_dfs_state(iface, freq, ht_enabled, chan_offset,
707 : chan_width, cf1, cf2,
708 : HOSTAPD_CHAN_DFS_AVAILABLE);
709 0 : iface->cac_started = 0;
710 0 : hostapd_setup_interface_complete(iface, 0);
711 : }
712 :
713 0 : return 0;
714 : }
715 :
716 :
717 0 : static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
718 : {
719 : struct hostapd_channel_data *channel;
720 : int secondary_channel;
721 0 : u8 vht_oper_centr_freq_seg0_idx = 0;
722 0 : u8 vht_oper_centr_freq_seg1_idx = 0;
723 0 : int skip_radar = 0;
724 0 : int err = 1;
725 :
726 : /* Radar detected during active CAC */
727 0 : iface->cac_started = 0;
728 0 : channel = dfs_get_valid_channel(iface, &secondary_channel,
729 : &vht_oper_centr_freq_seg0_idx,
730 : &vht_oper_centr_freq_seg1_idx,
731 : skip_radar);
732 :
733 0 : if (!channel) {
734 0 : wpa_printf(MSG_ERROR, "No valid channel available");
735 0 : hostapd_setup_interface_complete(iface, err);
736 0 : return err;
737 : }
738 :
739 0 : wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
740 0 : channel->chan);
741 0 : wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
742 : "freq=%d chan=%d sec_chan=%d", channel->freq,
743 0 : channel->chan, secondary_channel);
744 :
745 0 : iface->freq = channel->freq;
746 0 : iface->conf->channel = channel->chan;
747 0 : iface->conf->secondary_channel = secondary_channel;
748 0 : iface->conf->vht_oper_centr_freq_seg0_idx =
749 : vht_oper_centr_freq_seg0_idx;
750 0 : iface->conf->vht_oper_centr_freq_seg1_idx =
751 : vht_oper_centr_freq_seg1_idx;
752 0 : err = 0;
753 :
754 0 : hostapd_setup_interface_complete(iface, err);
755 0 : return err;
756 : }
757 :
758 :
759 0 : static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
760 : {
761 : struct hostapd_channel_data *channel;
762 : int secondary_channel;
763 : u8 vht_oper_centr_freq_seg0_idx;
764 : u8 vht_oper_centr_freq_seg1_idx;
765 0 : int skip_radar = 1;
766 : struct csa_settings csa_settings;
767 0 : struct hostapd_data *hapd = iface->bss[0];
768 0 : int err = 1;
769 :
770 0 : wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
771 0 : __func__, iface->cac_started ? "yes" : "no",
772 0 : iface->csa_in_progress ? "yes" : "no");
773 :
774 : /* Check if CSA in progress */
775 0 : if (iface->csa_in_progress)
776 0 : return 0;
777 :
778 : /* Check if active CAC */
779 0 : if (iface->cac_started)
780 0 : return hostapd_dfs_start_channel_switch_cac(iface);
781 :
782 : /* Perform channel switch/CSA */
783 0 : channel = dfs_get_valid_channel(iface, &secondary_channel,
784 : &vht_oper_centr_freq_seg0_idx,
785 : &vht_oper_centr_freq_seg1_idx,
786 : skip_radar);
787 :
788 0 : if (!channel) {
789 : /*
790 : * If there is no channel to switch immediately to, check if
791 : * there is another channel where we can switch even if it
792 : * requires to perform a CAC first.
793 : */
794 0 : skip_radar = 0;
795 0 : channel = dfs_get_valid_channel(iface, &secondary_channel,
796 : &vht_oper_centr_freq_seg0_idx,
797 : &vht_oper_centr_freq_seg1_idx,
798 : skip_radar);
799 0 : if (!channel) {
800 : /* FIXME: Wait for channel(s) to become available */
801 0 : hostapd_disable_iface(iface);
802 0 : return err;
803 : }
804 :
805 0 : iface->freq = channel->freq;
806 0 : iface->conf->channel = channel->chan;
807 0 : iface->conf->secondary_channel = secondary_channel;
808 0 : iface->conf->vht_oper_centr_freq_seg0_idx =
809 : vht_oper_centr_freq_seg0_idx;
810 0 : iface->conf->vht_oper_centr_freq_seg1_idx =
811 : vht_oper_centr_freq_seg1_idx;
812 :
813 0 : hostapd_disable_iface(iface);
814 0 : hostapd_enable_iface(iface);
815 0 : return 0;
816 : }
817 :
818 0 : wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
819 0 : channel->chan);
820 0 : wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
821 : "freq=%d chan=%d sec_chan=%d", channel->freq,
822 0 : channel->chan, secondary_channel);
823 :
824 : /* Setup CSA request */
825 0 : os_memset(&csa_settings, 0, sizeof(csa_settings));
826 0 : csa_settings.cs_count = 5;
827 0 : csa_settings.block_tx = 1;
828 0 : err = hostapd_set_freq_params(&csa_settings.freq_params,
829 0 : iface->conf->hw_mode,
830 : channel->freq,
831 0 : channel->chan,
832 0 : iface->conf->ieee80211n,
833 0 : iface->conf->ieee80211ac,
834 : secondary_channel,
835 0 : iface->conf->vht_oper_chwidth,
836 : vht_oper_centr_freq_seg0_idx,
837 : vht_oper_centr_freq_seg1_idx,
838 0 : iface->current_mode->vht_capab);
839 :
840 0 : if (err) {
841 0 : wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
842 0 : hostapd_disable_iface(iface);
843 0 : return err;
844 : }
845 :
846 0 : err = hostapd_switch_channel(hapd, &csa_settings);
847 0 : if (err) {
848 0 : wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
849 : err);
850 0 : iface->freq = channel->freq;
851 0 : iface->conf->channel = channel->chan;
852 0 : iface->conf->secondary_channel = secondary_channel;
853 0 : iface->conf->vht_oper_centr_freq_seg0_idx =
854 : vht_oper_centr_freq_seg0_idx;
855 0 : iface->conf->vht_oper_centr_freq_seg1_idx =
856 : vht_oper_centr_freq_seg1_idx;
857 :
858 0 : hostapd_disable_iface(iface);
859 0 : hostapd_enable_iface(iface);
860 0 : return 0;
861 : }
862 :
863 : /* Channel configuration will be updated once CSA completes and
864 : * ch_switch_notify event is received */
865 :
866 0 : wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
867 0 : return 0;
868 : }
869 :
870 :
871 2 : int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
872 : int ht_enabled, int chan_offset, int chan_width,
873 : int cf1, int cf2)
874 : {
875 : int res;
876 :
877 2 : if (!iface->conf->ieee80211h)
878 2 : return 0;
879 :
880 0 : wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
881 : "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
882 : freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
883 :
884 : /* mark radar frequency as invalid */
885 0 : res = set_dfs_state(iface, freq, ht_enabled, chan_offset,
886 : chan_width, cf1, cf2,
887 : HOSTAPD_CHAN_DFS_UNAVAILABLE);
888 :
889 : /* Skip if reported radar event not overlapped our channels */
890 0 : res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
891 0 : if (!res)
892 0 : return 0;
893 :
894 : /* radar detected while operating, switch the channel. */
895 0 : res = hostapd_dfs_start_channel_switch(iface);
896 :
897 0 : return res;
898 : }
899 :
900 :
901 0 : int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
902 : int ht_enabled, int chan_offset, int chan_width,
903 : int cf1, int cf2)
904 : {
905 0 : wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
906 : "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
907 : freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
908 : /* TODO add correct implementation here */
909 0 : set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
910 : cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
911 0 : return 0;
912 : }
913 :
914 :
915 4132 : int hostapd_is_dfs_required(struct hostapd_iface *iface)
916 : {
917 : int n_chans, start_chan_idx;
918 :
919 4132 : if (!iface->conf->ieee80211h || !iface->current_mode ||
920 0 : iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
921 4132 : return 0;
922 :
923 : /* Get start (first) channel for current configuration */
924 0 : start_chan_idx = dfs_get_start_chan_idx(iface);
925 0 : if (start_chan_idx == -1)
926 0 : return -1;
927 :
928 : /* Get number of used channels, depend on width */
929 0 : n_chans = dfs_get_used_n_chans(iface);
930 :
931 : /* Check if any of configured channels require DFS */
932 0 : return dfs_check_chans_radar(iface, start_chan_idx, n_chans);
933 : }
|