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 2107 : static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
23 : {
24 2107 : int n_chans = 1;
25 :
26 2107 : *seg1 = 0;
27 :
28 2107 : if (iface->conf->ieee80211n && iface->conf->secondary_channel)
29 93 : n_chans = 2;
30 :
31 2107 : if (iface->conf->ieee80211ac) {
32 48 : switch (iface->conf->vht_oper_chwidth) {
33 : case VHT_CHANWIDTH_USE_HT:
34 14 : break;
35 : case VHT_CHANWIDTH_80MHZ:
36 18 : n_chans = 4;
37 18 : break;
38 : case VHT_CHANWIDTH_160MHZ:
39 14 : n_chans = 8;
40 14 : break;
41 : case VHT_CHANWIDTH_80P80MHZ:
42 2 : n_chans = 4;
43 2 : *seg1 = 4;
44 2 : break;
45 : default:
46 0 : break;
47 : }
48 : }
49 :
50 2107 : return n_chans;
51 : }
52 :
53 :
54 193 : 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 215 : 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 171 : if (chan->flag & HOSTAPD_CHAN_DISABLED)
68 30 : return 0;
69 231 : if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
70 90 : ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
71 : HOSTAPD_CHAN_DFS_UNAVAILABLE))
72 7 : return 0;
73 134 : 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 194 : dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
127 : {
128 : int i;
129 :
130 241 : for (i = first_chan_idx; i < mode->num_channels; i++) {
131 240 : if (mode->channels[i].freq == freq)
132 193 : return &mode->channels[i];
133 : }
134 :
135 1 : return NULL;
136 : }
137 :
138 :
139 167 : 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 167 : if (first_chan_idx + num_chans > mode->num_channels)
147 0 : return 0;
148 :
149 167 : first_chan = &mode->channels[first_chan_idx];
150 :
151 301 : for (i = 0; i < num_chans; i++) {
152 194 : chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
153 : first_chan_idx);
154 194 : if (!chan)
155 1 : return 0;
156 :
157 193 : if (!dfs_channel_available(chan, skip_radar))
158 59 : return 0;
159 : }
160 :
161 107 : return 1;
162 : }
163 :
164 :
165 107 : static int is_in_chanlist(struct hostapd_iface *iface,
166 : struct hostapd_channel_data *chan)
167 : {
168 107 : if (!iface->conf->acs_ch_list.num)
169 36 : return 1;
170 :
171 71 : 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 219 : for (i = 0; i < mode->num_channels; i++) {
195 211 : chan = &mode->channels[i];
196 :
197 : /* Skip HT40/VHT incompatible channels */
198 397 : if (iface->conf->ieee80211n &&
199 261 : iface->conf->secondary_channel &&
200 75 : !dfs_is_chan_allowed(chan, n_chans))
201 44 : continue;
202 :
203 : /* Skip incompatible chandefs */
204 167 : if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
205 60 : continue;
206 :
207 107 : if (!is_in_chanlist(iface, chan))
208 60 : continue;
209 :
210 47 : 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 39 : wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
216 39 : 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 2091 : 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 2091 : int channel_no = iface->conf->channel;
269 2091 : int res = -1, i;
270 2091 : int chan_seg1 = -1;
271 :
272 2091 : *seg1_start = -1;
273 :
274 : /* HT40- */
275 2091 : if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
276 23 : channel_no -= 4;
277 :
278 : /* VHT */
279 2091 : if (iface->conf->ieee80211ac) {
280 44 : switch (iface->conf->vht_oper_chwidth) {
281 : case VHT_CHANWIDTH_USE_HT:
282 12 : break;
283 : case VHT_CHANWIDTH_80MHZ:
284 16 : channel_no =
285 16 : iface->conf->vht_oper_centr_freq_seg0_idx - 6;
286 16 : break;
287 : case VHT_CHANWIDTH_160MHZ:
288 14 : channel_no =
289 14 : iface->conf->vht_oper_centr_freq_seg0_idx - 14;
290 14 : break;
291 : case VHT_CHANWIDTH_80P80MHZ:
292 2 : channel_no =
293 2 : iface->conf->vht_oper_centr_freq_seg0_idx - 6;
294 2 : chan_seg1 =
295 2 : iface->conf->vht_oper_centr_freq_seg1_idx - 6;
296 2 : 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 2091 : mode = iface->current_mode;
307 3676 : for (i = 0; i < mode->num_channels; i++) {
308 3676 : chan = &mode->channels[i];
309 3676 : if (chan->chan == channel_no) {
310 2091 : res = i;
311 2091 : break;
312 : }
313 : }
314 :
315 2091 : if (res != -1 && chan_seg1 > -1) {
316 2 : int found = 0;
317 :
318 : /* Get idx for seg1 */
319 2 : mode = iface->current_mode;
320 40 : for (i = 0; i < mode->num_channels; i++) {
321 40 : chan = &mode->channels[i];
322 40 : if (chan->chan == chan_seg1) {
323 2 : *seg1_start = i;
324 2 : found = 1;
325 2 : break;
326 : }
327 : }
328 2 : if (!found)
329 0 : res = -1;
330 : }
331 :
332 2091 : 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 2091 : return res;
347 : }
348 :
349 :
350 : /* At least one channel have radar flag */
351 2091 : 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 2091 : int i, res = 0;
357 :
358 2091 : mode = iface->current_mode;
359 :
360 4389 : for (i = 0; i < n_chans; i++) {
361 2298 : channel = &mode->channels[start_chan_idx + i];
362 2298 : if (channel->flag & HOSTAPD_CHAN_RADAR)
363 154 : res++;
364 : }
365 :
366 2091 : return res;
367 : }
368 :
369 :
370 : /* All channels available */
371 19 : 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 19 : mode = iface->current_mode;
379 :
380 44 : for (i = 0; i < n_chans; i++) {
381 38 : channel = &mode->channels[start_chan_idx + i];
382 :
383 38 : if (channel->flag & HOSTAPD_CHAN_DISABLED)
384 0 : break;
385 :
386 38 : if (!(channel->flag & HOSTAPD_CHAN_RADAR))
387 8 : continue;
388 :
389 30 : if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
390 : HOSTAPD_CHAN_DFS_AVAILABLE)
391 13 : break;
392 : }
393 :
394 19 : return i == n_chans;
395 : }
396 :
397 :
398 : /* At least one channel unavailable */
399 13 : 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 13 : int i, res = 0;
406 :
407 13 : mode = iface->current_mode;
408 :
409 48 : for (i = 0; i < n_chans; i++) {
410 35 : channel = &mode->channels[start_chan_idx + i];
411 35 : if (channel->flag & HOSTAPD_CHAN_DISABLED)
412 0 : res++;
413 35 : if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
414 : HOSTAPD_CHAN_DFS_UNAVAILABLE)
415 0 : res++;
416 : }
417 :
418 13 : 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 : _rand = os_random();
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 34 : static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
473 : {
474 : struct hostapd_hw_modes *mode;
475 34 : struct hostapd_channel_data *chan = NULL;
476 : int i;
477 :
478 34 : mode = iface->current_mode;
479 34 : if (mode == NULL)
480 0 : return 0;
481 :
482 34 : wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
483 329 : for (i = 0; i < iface->current_mode->num_channels; i++) {
484 325 : chan = &iface->current_mode->channels[i];
485 325 : if (chan->freq == freq) {
486 34 : if (chan->flag & HOSTAPD_CHAN_RADAR) {
487 30 : chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
488 30 : chan->flag |= state;
489 30 : 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 14 : 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 14 : int n_chans = 1, i;
503 : struct hostapd_hw_modes *mode;
504 14 : int frequency = freq;
505 14 : int ret = 0;
506 :
507 14 : mode = iface->current_mode;
508 14 : if (mode == NULL)
509 0 : return 0;
510 :
511 14 : 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 14 : 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 3 : n_chans = 2;
526 3 : frequency = cf1 - 10;
527 3 : 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 14 : wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
543 : n_chans);
544 48 : for (i = 0; i < n_chans; i++) {
545 34 : ret += set_dfs_state_freq(iface, frequency, state);
546 34 : frequency = frequency + 20;
547 : }
548 :
549 14 : 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 2013 : 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 2013 : unsigned int cac_time_ms = 0;
625 :
626 2013 : mode = iface->current_mode;
627 :
628 4128 : for (i = 0; i < n_chans; i++) {
629 2115 : channel = &mode->channels[start_chan_idx + i];
630 2115 : if (!(channel->flag & HOSTAPD_CHAN_RADAR))
631 2067 : continue;
632 48 : if (channel->dfs_cac_ms > cac_time_ms)
633 19 : cac_time_ms = channel->dfs_cac_ms;
634 : }
635 :
636 2013 : 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 2013 : 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 2013 : int skip_radar = 0;
651 :
652 2013 : 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 2013 : iface->cac_started = 0;
663 :
664 : do {
665 : /* Get start (first) channel for current configuration */
666 2013 : start_chan_idx = dfs_get_start_chan_idx(iface,
667 : &start_chan_idx1);
668 2013 : if (start_chan_idx == -1)
669 0 : return -1;
670 :
671 : /* Get number of used channels, depend on width */
672 2013 : n_chans = dfs_get_used_n_chans(iface, &n_chans1);
673 :
674 : /* Setup CAC time */
675 2013 : 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 2013 : res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
680 2013 : wpa_printf(MSG_DEBUG,
681 : "DFS %d channels required radar detection",
682 : res);
683 2013 : if (!res)
684 1994 : return 1;
685 :
686 : /* Check if all channels are DFS available */
687 19 : res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
688 19 : wpa_printf(MSG_DEBUG,
689 : "DFS all channels available, (SKIP CAC): %s",
690 : res ? "yes" : "no");
691 19 : if (res)
692 6 : return 1;
693 :
694 : /* Check if any of configured channels is unavailable */
695 13 : res = dfs_check_chans_unavailable(iface, start_chan_idx,
696 : n_chans);
697 13 : wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
698 : res, res ? "yes": "no");
699 13 : 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 : return -1;
708 : }
709 :
710 0 : iface->freq = channel->freq;
711 0 : iface->conf->channel = channel->chan;
712 0 : iface->conf->secondary_channel = sec;
713 0 : iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
714 0 : iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
715 : }
716 13 : } while (res);
717 :
718 : /* Finally start CAC */
719 13 : hostapd_set_state(iface, HAPD_IFACE_DFS);
720 13 : wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
721 78 : wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
722 : "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
723 : iface->freq,
724 26 : iface->conf->channel, iface->conf->secondary_channel,
725 13 : iface->conf->vht_oper_chwidth,
726 13 : iface->conf->vht_oper_centr_freq_seg0_idx,
727 13 : iface->conf->vht_oper_centr_freq_seg1_idx,
728 13 : iface->dfs_cac_ms / 1000);
729 :
730 91 : res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
731 : iface->freq,
732 13 : iface->conf->channel,
733 13 : iface->conf->ieee80211n,
734 13 : iface->conf->ieee80211ac,
735 13 : iface->conf->secondary_channel,
736 13 : iface->conf->vht_oper_chwidth,
737 13 : iface->conf->vht_oper_centr_freq_seg0_idx,
738 13 : iface->conf->vht_oper_centr_freq_seg1_idx);
739 :
740 13 : if (res) {
741 1 : wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
742 1 : return -1;
743 : }
744 :
745 12 : return 0;
746 : }
747 :
748 :
749 12 : int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
750 : int ht_enabled, int chan_offset, int chan_width,
751 : int cf1, int cf2)
752 : {
753 12 : wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
754 : "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
755 : success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
756 :
757 12 : if (success) {
758 : /* Complete iface/ap configuration */
759 6 : if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
760 : /* Complete AP configuration for the first bring up. */
761 0 : if (iface->state != HAPD_IFACE_ENABLED)
762 0 : hostapd_setup_interface_complete(iface, 0);
763 : else
764 0 : iface->cac_started = 0;
765 : } else {
766 6 : set_dfs_state(iface, freq, ht_enabled, chan_offset,
767 : chan_width, cf1, cf2,
768 : HOSTAPD_CHAN_DFS_AVAILABLE);
769 6 : iface->cac_started = 0;
770 6 : hostapd_setup_interface_complete(iface, 0);
771 : }
772 : }
773 :
774 12 : return 0;
775 : }
776 :
777 :
778 6 : static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
779 : {
780 : struct hostapd_channel_data *channel;
781 : int secondary_channel;
782 6 : u8 vht_oper_centr_freq_seg0_idx = 0;
783 6 : u8 vht_oper_centr_freq_seg1_idx = 0;
784 6 : int skip_radar = 0;
785 6 : int err = 1;
786 :
787 : /* Radar detected during active CAC */
788 6 : iface->cac_started = 0;
789 6 : channel = dfs_get_valid_channel(iface, &secondary_channel,
790 : &vht_oper_centr_freq_seg0_idx,
791 : &vht_oper_centr_freq_seg1_idx,
792 : skip_radar);
793 :
794 6 : if (!channel) {
795 0 : wpa_printf(MSG_ERROR, "No valid channel available");
796 0 : hostapd_setup_interface_complete(iface, err);
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 16 : static int hostapd_csa_in_progress(struct hostapd_iface *iface)
821 : {
822 : unsigned int i;
823 32 : for (i = 0; i < iface->num_bss; i++)
824 16 : if (iface->bss[i]->csa_in_progress)
825 0 : return 1;
826 16 : return 0;
827 : }
828 :
829 :
830 8 : static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
831 : {
832 : struct hostapd_channel_data *channel;
833 : int secondary_channel;
834 : u8 vht_oper_centr_freq_seg0_idx;
835 : u8 vht_oper_centr_freq_seg1_idx;
836 8 : int skip_radar = 1;
837 : struct csa_settings csa_settings;
838 : unsigned int i;
839 8 : int err = 1;
840 :
841 16 : wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
842 8 : __func__, iface->cac_started ? "yes" : "no",
843 8 : hostapd_csa_in_progress(iface) ? "yes" : "no");
844 :
845 : /* Check if CSA in progress */
846 8 : if (hostapd_csa_in_progress(iface))
847 0 : return 0;
848 :
849 : /* Check if active CAC */
850 8 : if (iface->cac_started)
851 6 : return hostapd_dfs_start_channel_switch_cac(iface);
852 :
853 : /* Perform channel switch/CSA */
854 2 : channel = dfs_get_valid_channel(iface, &secondary_channel,
855 : &vht_oper_centr_freq_seg0_idx,
856 : &vht_oper_centr_freq_seg1_idx,
857 : skip_radar);
858 :
859 2 : if (!channel) {
860 : /*
861 : * If there is no channel to switch immediately to, check if
862 : * there is another channel where we can switch even if it
863 : * requires to perform a CAC first.
864 : */
865 0 : skip_radar = 0;
866 0 : channel = dfs_get_valid_channel(iface, &secondary_channel,
867 : &vht_oper_centr_freq_seg0_idx,
868 : &vht_oper_centr_freq_seg1_idx,
869 : skip_radar);
870 0 : if (!channel) {
871 : /* FIXME: Wait for channel(s) to become available */
872 0 : hostapd_disable_iface(iface);
873 0 : return err;
874 : }
875 :
876 0 : iface->freq = channel->freq;
877 0 : iface->conf->channel = channel->chan;
878 0 : iface->conf->secondary_channel = secondary_channel;
879 0 : iface->conf->vht_oper_centr_freq_seg0_idx =
880 : vht_oper_centr_freq_seg0_idx;
881 0 : iface->conf->vht_oper_centr_freq_seg1_idx =
882 : vht_oper_centr_freq_seg1_idx;
883 :
884 0 : hostapd_disable_iface(iface);
885 0 : hostapd_enable_iface(iface);
886 0 : return 0;
887 : }
888 :
889 2 : wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
890 2 : channel->chan);
891 4 : wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
892 : "freq=%d chan=%d sec_chan=%d", channel->freq,
893 2 : channel->chan, secondary_channel);
894 :
895 : /* Setup CSA request */
896 2 : os_memset(&csa_settings, 0, sizeof(csa_settings));
897 2 : csa_settings.cs_count = 5;
898 2 : csa_settings.block_tx = 1;
899 12 : err = hostapd_set_freq_params(&csa_settings.freq_params,
900 2 : iface->conf->hw_mode,
901 : channel->freq,
902 2 : channel->chan,
903 2 : iface->conf->ieee80211n,
904 2 : iface->conf->ieee80211ac,
905 : secondary_channel,
906 2 : iface->conf->vht_oper_chwidth,
907 : vht_oper_centr_freq_seg0_idx,
908 : vht_oper_centr_freq_seg1_idx,
909 2 : iface->current_mode->vht_capab);
910 :
911 2 : if (err) {
912 0 : wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
913 0 : hostapd_disable_iface(iface);
914 0 : return err;
915 : }
916 :
917 4 : for (i = 0; i < iface->num_bss; i++) {
918 2 : err = hostapd_switch_channel(iface->bss[i], &csa_settings);
919 2 : if (err)
920 0 : break;
921 : }
922 :
923 2 : if (err) {
924 0 : wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
925 : err);
926 0 : iface->freq = channel->freq;
927 0 : iface->conf->channel = channel->chan;
928 0 : iface->conf->secondary_channel = secondary_channel;
929 0 : iface->conf->vht_oper_centr_freq_seg0_idx =
930 : vht_oper_centr_freq_seg0_idx;
931 0 : iface->conf->vht_oper_centr_freq_seg1_idx =
932 : vht_oper_centr_freq_seg1_idx;
933 :
934 0 : hostapd_disable_iface(iface);
935 0 : hostapd_enable_iface(iface);
936 0 : return 0;
937 : }
938 :
939 : /* Channel configuration will be updated once CSA completes and
940 : * ch_switch_notify event is received */
941 :
942 2 : wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
943 2 : return 0;
944 : }
945 :
946 :
947 10 : int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
948 : int ht_enabled, int chan_offset, int chan_width,
949 : int cf1, int cf2)
950 : {
951 : int res;
952 :
953 10 : wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
954 : "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
955 : freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
956 :
957 : /* Proceed only if DFS is not offloaded to the driver */
958 10 : if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
959 0 : return 0;
960 :
961 10 : if (!iface->conf->ieee80211h)
962 2 : return 0;
963 :
964 : /* mark radar frequency as invalid */
965 8 : set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
966 : cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
967 :
968 : /* Skip if reported radar event not overlapped our channels */
969 8 : res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
970 8 : if (!res)
971 0 : return 0;
972 :
973 : /* radar detected while operating, switch the channel. */
974 8 : res = hostapd_dfs_start_channel_switch(iface);
975 :
976 8 : return res;
977 : }
978 :
979 :
980 0 : int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
981 : int ht_enabled, int chan_offset, int chan_width,
982 : int cf1, int cf2)
983 : {
984 0 : wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
985 : "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
986 : freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
987 :
988 : /* Proceed only if DFS is not offloaded to the driver */
989 0 : if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
990 0 : return 0;
991 :
992 : /* TODO add correct implementation here */
993 0 : set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
994 : cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
995 0 : return 0;
996 : }
997 :
998 :
999 11930 : int hostapd_is_dfs_required(struct hostapd_iface *iface)
1000 : {
1001 : int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res;
1002 :
1003 12000 : if (!iface->conf->ieee80211h || !iface->current_mode ||
1004 70 : iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
1005 11860 : return 0;
1006 :
1007 : /* Get start (first) channel for current configuration */
1008 70 : start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
1009 70 : if (start_chan_idx == -1)
1010 0 : return -1;
1011 :
1012 : /* Get number of used channels, depend on width */
1013 70 : n_chans = dfs_get_used_n_chans(iface, &n_chans1);
1014 :
1015 : /* Check if any of configured channels require DFS */
1016 70 : res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
1017 70 : if (res)
1018 37 : return res;
1019 33 : if (start_chan_idx1 >= 0 && n_chans1 > 0)
1020 0 : res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
1021 33 : return res;
1022 : }
1023 :
1024 :
1025 0 : int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
1026 : int ht_enabled, int chan_offset, int chan_width,
1027 : int cf1, int cf2)
1028 : {
1029 0 : wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
1030 : "freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
1031 : "seg1=%d cac_time=%ds",
1032 0 : freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60);
1033 0 : iface->cac_started = 1;
1034 0 : return 0;
1035 : }
1036 :
1037 :
1038 : /*
1039 : * Main DFS handler for offloaded case.
1040 : * 2 - continue channel/AP setup for non-DFS channel
1041 : * 1 - continue channel/AP setup for DFS channel
1042 : * 0 - channel/AP setup will be continued after CAC
1043 : * -1 - hit critical error
1044 : */
1045 0 : int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
1046 : {
1047 0 : wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
1048 0 : __func__, iface->cac_started);
1049 :
1050 : /*
1051 : * If DFS has already been started, then we are being called from a
1052 : * callback to continue AP/channel setup. Reset the CAC start flag and
1053 : * return.
1054 : */
1055 0 : if (iface->cac_started) {
1056 0 : wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
1057 0 : __func__, iface->cac_started);
1058 0 : iface->cac_started = 0;
1059 0 : return 1;
1060 : }
1061 :
1062 0 : if (ieee80211_is_dfs(iface->freq)) {
1063 0 : wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
1064 : __func__, iface->freq);
1065 0 : return 0;
1066 : }
1067 :
1068 0 : wpa_printf(MSG_DEBUG,
1069 : "%s: freq %d MHz does not require DFS. Continue channel/AP setup",
1070 : __func__, iface->freq);
1071 0 : return 2;
1072 : }
|