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