1 /* 2 * DFS - Dynamic Frequency Selection 3 * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> 4 * Copyright (c) 2013-2017, Qualcomm Atheros, Inc. 5 * 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 static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1) 23 { 24 int n_chans = 1; 25 26 *seg1 = 0; 27 28 if (iface->conf->ieee80211n && iface->conf->secondary_channel) 29 n_chans = 2; 30 31 if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) { 32 switch (hostapd_get_oper_chwidth(iface->conf)) { 33 case CHANWIDTH_USE_HT: 34 break; 35 case CHANWIDTH_80MHZ: 36 n_chans = 4; 37 break; 38 case CHANWIDTH_160MHZ: 39 n_chans = 8; 40 break; 41 case CHANWIDTH_80P80MHZ: 42 n_chans = 4; 43 *seg1 = 4; 44 break; 45 default: 46 break; 47 } 48 } 49 50 return n_chans; 51 } 52 53 54 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 if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) && 63 ((chan->flag & HOSTAPD_CHAN_DFS_MASK) != 64 HOSTAPD_CHAN_DFS_AVAILABLE)) 65 return 0; 66 67 if (chan->flag & HOSTAPD_CHAN_DISABLED) 68 return 0; 69 if ((chan->flag & HOSTAPD_CHAN_RADAR) && 70 ((chan->flag & HOSTAPD_CHAN_DFS_MASK) == 71 HOSTAPD_CHAN_DFS_UNAVAILABLE)) 72 return 0; 73 return 1; 74 } 75 76 77 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 int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 84 165, 173, 184, 192 }; 85 /* 86 * VHT80, valid channels based on center frequency: 87 * 42, 58, 106, 122, 138, 155, 171 88 */ 89 int allowed_80[] = { 36, 52, 100, 116, 132, 149, 165 }; 90 /* 91 * VHT160 valid channels based on center frequency: 92 * 50, 114, 163 93 */ 94 int allowed_160[] = { 36, 100, 149 }; 95 int *allowed = allowed_40; 96 unsigned int i, allowed_no = 0; 97 98 switch (n_chans) { 99 case 2: 100 allowed = allowed_40; 101 allowed_no = ARRAY_SIZE(allowed_40); 102 break; 103 case 4: 104 allowed = allowed_80; 105 allowed_no = ARRAY_SIZE(allowed_80); 106 break; 107 case 8: 108 allowed = allowed_160; 109 allowed_no = ARRAY_SIZE(allowed_160); 110 break; 111 default: 112 wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans); 113 break; 114 } 115 116 for (i = 0; i < allowed_no; i++) { 117 if (chan->chan == allowed[i]) 118 return 1; 119 } 120 121 return 0; 122 } 123 124 125 static struct hostapd_channel_data * 126 dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx) 127 { 128 int i; 129 130 for (i = first_chan_idx; i < mode->num_channels; i++) { 131 if (mode->channels[i].freq == freq) 132 return &mode->channels[i]; 133 } 134 135 return NULL; 136 } 137 138 139 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 u32 bw = num_chan_to_bw(num_chans); 146 147 if (first_chan_idx + num_chans > mode->num_channels) { 148 wpa_printf(MSG_DEBUG, 149 "DFS: some channels in range not defined"); 150 return 0; 151 } 152 153 first_chan = &mode->channels[first_chan_idx]; 154 155 /* hostapd DFS implementation assumes the first channel as primary. 156 * If it's not allowed to use the first channel as primary, decline the 157 * whole channel range. */ 158 if (!chan_pri_allowed(first_chan)) { 159 wpa_printf(MSG_DEBUG, "DFS: primary chanenl not allowed"); 160 return 0; 161 } 162 163 for (i = 0; i < num_chans; i++) { 164 chan = dfs_get_chan_data(mode, first_chan->freq + i * 20, 165 first_chan_idx); 166 if (!chan) { 167 wpa_printf(MSG_DEBUG, "DFS: no channel data for %d", 168 first_chan->freq + i * 20); 169 return 0; 170 } 171 172 /* HT 40 MHz secondary channel availability checked only for 173 * primary channel */ 174 if (!chan_bw_allowed(chan, bw, 1, !i)) { 175 wpa_printf(MSG_DEBUG, "DFS: bw now allowed for %d", 176 first_chan->freq + i * 20); 177 return 0; 178 } 179 180 if (!dfs_channel_available(chan, skip_radar)) { 181 wpa_printf(MSG_DEBUG, "DFS: channel not available %d", 182 first_chan->freq + i * 20); 183 return 0; 184 } 185 } 186 187 return 1; 188 } 189 190 191 static int is_in_chanlist(struct hostapd_iface *iface, 192 struct hostapd_channel_data *chan) 193 { 194 if (!iface->conf->acs_ch_list.num) 195 return 1; 196 197 return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan); 198 } 199 200 201 /* 202 * The function assumes HT40+ operation. 203 * Make sure to adjust the following variables after calling this: 204 * - hapd->secondary_channel 205 * - hapd->vht/he_oper_centr_freq_seg0_idx 206 * - hapd->vht/he_oper_centr_freq_seg1_idx 207 */ 208 static int dfs_find_channel(struct hostapd_iface *iface, 209 struct hostapd_channel_data **ret_chan, 210 int idx, int skip_radar) 211 { 212 struct hostapd_hw_modes *mode; 213 struct hostapd_channel_data *chan; 214 int i, channel_idx = 0, n_chans, n_chans1; 215 216 mode = iface->current_mode; 217 n_chans = dfs_get_used_n_chans(iface, &n_chans1); 218 219 wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans); 220 for (i = 0; i < mode->num_channels; i++) { 221 chan = &mode->channels[i]; 222 223 /* Skip HT40/VHT incompatible channels */ 224 if (iface->conf->ieee80211n && 225 iface->conf->secondary_channel && 226 (!dfs_is_chan_allowed(chan, n_chans) || 227 !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))) { 228 wpa_printf(MSG_DEBUG, 229 "DFS: channel %d (%d) is incompatible", 230 chan->freq, chan->chan); 231 continue; 232 } 233 234 /* Skip incompatible chandefs */ 235 if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) { 236 wpa_printf(MSG_DEBUG, 237 "DFS: range not available for %d (%d)", 238 chan->freq, chan->chan); 239 continue; 240 } 241 242 if (!is_in_chanlist(iface, chan)) { 243 wpa_printf(MSG_DEBUG, 244 "DFS: channel %d (%d) not in chanlist", 245 chan->freq, chan->chan); 246 continue; 247 } 248 249 if (chan->max_tx_power < iface->conf->min_tx_power) 250 continue; 251 252 if (ret_chan && idx == channel_idx) { 253 wpa_printf(MSG_DEBUG, "Selected channel %d (%d)", 254 chan->freq, chan->chan); 255 *ret_chan = chan; 256 return idx; 257 } 258 wpa_printf(MSG_DEBUG, "Adding channel %d (%d)", 259 chan->freq, chan->chan); 260 channel_idx++; 261 } 262 return channel_idx; 263 } 264 265 266 static void dfs_adjust_center_freq(struct hostapd_iface *iface, 267 struct hostapd_channel_data *chan, 268 int secondary_channel, 269 int sec_chan_idx_80p80, 270 u8 *oper_centr_freq_seg0_idx, 271 u8 *oper_centr_freq_seg1_idx) 272 { 273 if (!iface->conf->ieee80211ac && !iface->conf->ieee80211ax) 274 return; 275 276 if (!chan) 277 return; 278 279 *oper_centr_freq_seg1_idx = 0; 280 281 switch (hostapd_get_oper_chwidth(iface->conf)) { 282 case CHANWIDTH_USE_HT: 283 if (secondary_channel == 1) 284 *oper_centr_freq_seg0_idx = chan->chan + 2; 285 else if (secondary_channel == -1) 286 *oper_centr_freq_seg0_idx = chan->chan - 2; 287 else 288 *oper_centr_freq_seg0_idx = chan->chan; 289 break; 290 case CHANWIDTH_80MHZ: 291 *oper_centr_freq_seg0_idx = chan->chan + 6; 292 break; 293 case CHANWIDTH_160MHZ: 294 *oper_centr_freq_seg0_idx = chan->chan + 14; 295 break; 296 case CHANWIDTH_80P80MHZ: 297 *oper_centr_freq_seg0_idx = chan->chan + 6; 298 *oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6; 299 break; 300 301 default: 302 wpa_printf(MSG_INFO, 303 "DFS: Unsupported channel width configuration"); 304 *oper_centr_freq_seg0_idx = 0; 305 break; 306 } 307 308 wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d", 309 *oper_centr_freq_seg0_idx, 310 *oper_centr_freq_seg1_idx); 311 } 312 313 314 /* Return start channel idx we will use for mode->channels[idx] */ 315 static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start) 316 { 317 struct hostapd_hw_modes *mode; 318 struct hostapd_channel_data *chan; 319 int channel_no = iface->conf->channel; 320 int res = -1, i; 321 int chan_seg1 = -1; 322 323 *seg1_start = -1; 324 325 /* HT40- */ 326 if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1) 327 channel_no -= 4; 328 329 /* VHT/HE */ 330 if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) { 331 switch (hostapd_get_oper_chwidth(iface->conf)) { 332 case CHANWIDTH_USE_HT: 333 break; 334 case CHANWIDTH_80MHZ: 335 channel_no = hostapd_get_oper_centr_freq_seg0_idx( 336 iface->conf) - 6; 337 break; 338 case CHANWIDTH_160MHZ: 339 channel_no = hostapd_get_oper_centr_freq_seg0_idx( 340 iface->conf) - 14; 341 break; 342 case CHANWIDTH_80P80MHZ: 343 channel_no = hostapd_get_oper_centr_freq_seg0_idx( 344 iface->conf) - 6; 345 chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx( 346 iface->conf) - 6; 347 break; 348 default: 349 wpa_printf(MSG_INFO, 350 "DFS only VHT20/40/80/160/80+80 is supported now"); 351 channel_no = -1; 352 break; 353 } 354 } 355 356 /* Get idx */ 357 mode = iface->current_mode; 358 for (i = 0; i < mode->num_channels; i++) { 359 chan = &mode->channels[i]; 360 if (chan->chan == channel_no) { 361 res = i; 362 break; 363 } 364 } 365 366 if (res != -1 && chan_seg1 > -1) { 367 int found = 0; 368 369 /* Get idx for seg1 */ 370 mode = iface->current_mode; 371 for (i = 0; i < mode->num_channels; i++) { 372 chan = &mode->channels[i]; 373 if (chan->chan == chan_seg1) { 374 *seg1_start = i; 375 found = 1; 376 break; 377 } 378 } 379 if (!found) 380 res = -1; 381 } 382 383 if (res == -1) { 384 wpa_printf(MSG_DEBUG, 385 "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d", 386 mode->num_channels, channel_no, iface->conf->channel, 387 iface->conf->ieee80211n, 388 iface->conf->secondary_channel, 389 hostapd_get_oper_chwidth(iface->conf)); 390 391 for (i = 0; i < mode->num_channels; i++) { 392 wpa_printf(MSG_DEBUG, "Available channel: %d", 393 mode->channels[i].chan); 394 } 395 } 396 397 return res; 398 } 399 400 401 /* At least one channel have radar flag */ 402 static int dfs_check_chans_radar(struct hostapd_iface *iface, 403 int start_chan_idx, int n_chans) 404 { 405 struct hostapd_channel_data *channel; 406 struct hostapd_hw_modes *mode; 407 int i, res = 0; 408 409 mode = iface->current_mode; 410 411 for (i = 0; i < n_chans; i++) { 412 channel = &mode->channels[start_chan_idx + i]; 413 if (channel->flag & HOSTAPD_CHAN_RADAR) 414 res++; 415 } 416 417 return res; 418 } 419 420 421 /* All channels available */ 422 static int dfs_check_chans_available(struct hostapd_iface *iface, 423 int start_chan_idx, int n_chans) 424 { 425 struct hostapd_channel_data *channel; 426 struct hostapd_hw_modes *mode; 427 int i; 428 429 mode = iface->current_mode; 430 431 for (i = 0; i < n_chans; i++) { 432 channel = &mode->channels[start_chan_idx + i]; 433 434 if (channel->flag & HOSTAPD_CHAN_DISABLED) 435 break; 436 437 if (!(channel->flag & HOSTAPD_CHAN_RADAR)) 438 continue; 439 440 if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) != 441 HOSTAPD_CHAN_DFS_AVAILABLE) 442 break; 443 } 444 445 return i == n_chans; 446 } 447 448 449 /* At least one channel unavailable */ 450 static int dfs_check_chans_unavailable(struct hostapd_iface *iface, 451 int start_chan_idx, 452 int n_chans) 453 { 454 struct hostapd_channel_data *channel; 455 struct hostapd_hw_modes *mode; 456 int i, res = 0; 457 458 mode = iface->current_mode; 459 460 for (i = 0; i < n_chans; i++) { 461 channel = &mode->channels[start_chan_idx + i]; 462 if (channel->flag & HOSTAPD_CHAN_DISABLED) 463 res++; 464 if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) == 465 HOSTAPD_CHAN_DFS_UNAVAILABLE) 466 res++; 467 } 468 469 return res; 470 } 471 472 473 static struct hostapd_channel_data * 474 dfs_get_valid_channel(struct hostapd_iface *iface, 475 int *secondary_channel, 476 u8 *oper_centr_freq_seg0_idx, 477 u8 *oper_centr_freq_seg1_idx, 478 int skip_radar) 479 { 480 struct hostapd_hw_modes *mode; 481 struct hostapd_channel_data *chan = NULL; 482 struct hostapd_channel_data *chan2 = NULL; 483 int num_available_chandefs; 484 int chan_idx, chan_idx2; 485 int sec_chan_idx_80p80 = -1; 486 int i; 487 u32 _rand; 488 489 wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); 490 *secondary_channel = 0; 491 *oper_centr_freq_seg0_idx = 0; 492 *oper_centr_freq_seg1_idx = 0; 493 494 if (iface->current_mode == NULL) 495 return NULL; 496 497 mode = iface->current_mode; 498 if (mode->mode != HOSTAPD_MODE_IEEE80211A) 499 return NULL; 500 501 /* Get the count first */ 502 num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar); 503 wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d", 504 num_available_chandefs); 505 if (num_available_chandefs == 0) 506 return NULL; 507 508 if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0) 509 return NULL; 510 chan_idx = _rand % num_available_chandefs; 511 dfs_find_channel(iface, &chan, chan_idx, skip_radar); 512 if (!chan) { 513 wpa_printf(MSG_DEBUG, "DFS: no random channel found"); 514 return NULL; 515 } 516 wpa_printf(MSG_DEBUG, "DFS: got random channel %d (%d)", 517 chan->freq, chan->chan); 518 519 /* dfs_find_channel() calculations assume HT40+ */ 520 if (iface->conf->secondary_channel) 521 *secondary_channel = 1; 522 else 523 *secondary_channel = 0; 524 525 /* Get secondary channel for HT80P80 */ 526 if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) { 527 if (num_available_chandefs <= 1) { 528 wpa_printf(MSG_ERROR, 529 "only 1 valid chan, can't support 80+80"); 530 return NULL; 531 } 532 533 /* 534 * Loop all channels except channel1 to find a valid channel2 535 * that is not adjacent to channel1. 536 */ 537 for (i = 0; i < num_available_chandefs - 1; i++) { 538 /* start from chan_idx + 1, end when chan_idx - 1 */ 539 chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs; 540 dfs_find_channel(iface, &chan2, chan_idx2, skip_radar); 541 if (chan2 && abs(chan2->chan - chan->chan) > 12) { 542 /* two channels are not adjacent */ 543 sec_chan_idx_80p80 = chan2->chan; 544 wpa_printf(MSG_DEBUG, 545 "DFS: got second chan: %d (%d)", 546 chan2->freq, chan2->chan); 547 break; 548 } 549 } 550 551 /* Check if we got a valid secondary channel which is not 552 * adjacent to the first channel. 553 */ 554 if (sec_chan_idx_80p80 == -1) { 555 wpa_printf(MSG_INFO, 556 "DFS: failed to get chan2 for 80+80"); 557 return NULL; 558 } 559 } 560 561 dfs_adjust_center_freq(iface, chan, 562 *secondary_channel, 563 sec_chan_idx_80p80, 564 oper_centr_freq_seg0_idx, 565 oper_centr_freq_seg1_idx); 566 567 return chan; 568 } 569 570 571 static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state) 572 { 573 struct hostapd_hw_modes *mode; 574 struct hostapd_channel_data *chan = NULL; 575 int i; 576 577 mode = iface->current_mode; 578 if (mode == NULL) 579 return 0; 580 581 wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq); 582 for (i = 0; i < iface->current_mode->num_channels; i++) { 583 chan = &iface->current_mode->channels[i]; 584 if (chan->freq == freq) { 585 if (chan->flag & HOSTAPD_CHAN_RADAR) { 586 chan->flag &= ~HOSTAPD_CHAN_DFS_MASK; 587 chan->flag |= state; 588 return 1; /* Channel found */ 589 } 590 } 591 } 592 wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq); 593 return 0; 594 } 595 596 597 static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled, 598 int chan_offset, int chan_width, int cf1, 599 int cf2, u32 state) 600 { 601 int n_chans = 1, i; 602 struct hostapd_hw_modes *mode; 603 int frequency = freq; 604 int frequency2 = 0; 605 int ret = 0; 606 607 mode = iface->current_mode; 608 if (mode == NULL) 609 return 0; 610 611 if (mode->mode != HOSTAPD_MODE_IEEE80211A) { 612 wpa_printf(MSG_WARNING, "current_mode != IEEE80211A"); 613 return 0; 614 } 615 616 /* Seems cf1 and chan_width is enough here */ 617 switch (chan_width) { 618 case CHAN_WIDTH_20_NOHT: 619 case CHAN_WIDTH_20: 620 n_chans = 1; 621 if (frequency == 0) 622 frequency = cf1; 623 break; 624 case CHAN_WIDTH_40: 625 n_chans = 2; 626 frequency = cf1 - 10; 627 break; 628 case CHAN_WIDTH_80: 629 n_chans = 4; 630 frequency = cf1 - 30; 631 break; 632 case CHAN_WIDTH_80P80: 633 n_chans = 4; 634 frequency = cf1 - 30; 635 frequency2 = cf2 - 30; 636 break; 637 case CHAN_WIDTH_160: 638 n_chans = 8; 639 frequency = cf1 - 70; 640 break; 641 default: 642 wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 643 chan_width); 644 break; 645 } 646 647 wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency, 648 n_chans); 649 for (i = 0; i < n_chans; i++) { 650 ret += set_dfs_state_freq(iface, frequency, state); 651 frequency = frequency + 20; 652 653 if (chan_width == CHAN_WIDTH_80P80) { 654 ret += set_dfs_state_freq(iface, frequency2, state); 655 frequency2 = frequency2 + 20; 656 } 657 } 658 659 return ret; 660 } 661 662 663 static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq, 664 int chan_width, int cf1, int cf2) 665 { 666 int start_chan_idx, start_chan_idx1; 667 struct hostapd_hw_modes *mode; 668 struct hostapd_channel_data *chan; 669 int n_chans, n_chans1, i, j, frequency = freq, radar_n_chans = 1; 670 u8 radar_chan; 671 int res = 0; 672 673 /* Our configuration */ 674 mode = iface->current_mode; 675 start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1); 676 n_chans = dfs_get_used_n_chans(iface, &n_chans1); 677 678 /* Check we are on DFS channel(s) */ 679 if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans)) 680 return 0; 681 682 /* Reported via radar event */ 683 switch (chan_width) { 684 case CHAN_WIDTH_20_NOHT: 685 case CHAN_WIDTH_20: 686 radar_n_chans = 1; 687 if (frequency == 0) 688 frequency = cf1; 689 break; 690 case CHAN_WIDTH_40: 691 radar_n_chans = 2; 692 frequency = cf1 - 10; 693 break; 694 case CHAN_WIDTH_80: 695 radar_n_chans = 4; 696 frequency = cf1 - 30; 697 break; 698 case CHAN_WIDTH_160: 699 radar_n_chans = 8; 700 frequency = cf1 - 70; 701 break; 702 default: 703 wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 704 chan_width); 705 break; 706 } 707 708 ieee80211_freq_to_chan(frequency, &radar_chan); 709 710 for (i = 0; i < n_chans; i++) { 711 chan = &mode->channels[start_chan_idx + i]; 712 if (!(chan->flag & HOSTAPD_CHAN_RADAR)) 713 continue; 714 for (j = 0; j < radar_n_chans; j++) { 715 wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d", 716 chan->chan, radar_chan + j * 4); 717 if (chan->chan == radar_chan + j * 4) 718 res++; 719 } 720 } 721 722 wpa_printf(MSG_DEBUG, "overlapped: %d", res); 723 724 return res; 725 } 726 727 728 static unsigned int dfs_get_cac_time(struct hostapd_iface *iface, 729 int start_chan_idx, int n_chans) 730 { 731 struct hostapd_channel_data *channel; 732 struct hostapd_hw_modes *mode; 733 int i; 734 unsigned int cac_time_ms = 0; 735 736 mode = iface->current_mode; 737 738 for (i = 0; i < n_chans; i++) { 739 channel = &mode->channels[start_chan_idx + i]; 740 if (!(channel->flag & HOSTAPD_CHAN_RADAR)) 741 continue; 742 if (channel->dfs_cac_ms > cac_time_ms) 743 cac_time_ms = channel->dfs_cac_ms; 744 } 745 746 return cac_time_ms; 747 } 748 749 750 /* 751 * Main DFS handler 752 * 1 - continue channel/ap setup 753 * 0 - channel/ap setup will be continued after CAC 754 * -1 - hit critical error 755 */ 756 int hostapd_handle_dfs(struct hostapd_iface *iface) 757 { 758 struct hostapd_channel_data *channel; 759 int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1; 760 int skip_radar = 0; 761 762 if (is_6ghz_freq(iface->freq)) 763 return 1; 764 765 if (!iface->current_mode) { 766 /* 767 * This can happen with drivers that do not provide mode 768 * information and as such, cannot really use hostapd for DFS. 769 */ 770 wpa_printf(MSG_DEBUG, 771 "DFS: No current_mode information - assume no need to perform DFS operations by hostapd"); 772 return 1; 773 } 774 775 iface->cac_started = 0; 776 777 do { 778 /* Get start (first) channel for current configuration */ 779 start_chan_idx = dfs_get_start_chan_idx(iface, 780 &start_chan_idx1); 781 if (start_chan_idx == -1) 782 return -1; 783 784 /* Get number of used channels, depend on width */ 785 n_chans = dfs_get_used_n_chans(iface, &n_chans1); 786 787 /* Setup CAC time */ 788 iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx, 789 n_chans); 790 791 /* Check if any of configured channels require DFS */ 792 res = dfs_check_chans_radar(iface, start_chan_idx, n_chans); 793 wpa_printf(MSG_DEBUG, 794 "DFS %d channels required radar detection", 795 res); 796 if (!res) 797 return 1; 798 799 /* Check if all channels are DFS available */ 800 res = dfs_check_chans_available(iface, start_chan_idx, n_chans); 801 wpa_printf(MSG_DEBUG, 802 "DFS all channels available, (SKIP CAC): %s", 803 res ? "yes" : "no"); 804 if (res) 805 return 1; 806 807 /* Check if any of configured channels is unavailable */ 808 res = dfs_check_chans_unavailable(iface, start_chan_idx, 809 n_chans); 810 wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", 811 res, res ? "yes": "no"); 812 if (res) { 813 int sec = 0; 814 u8 cf1 = 0, cf2 = 0; 815 816 channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, 817 skip_radar); 818 if (!channel) { 819 wpa_printf(MSG_ERROR, "could not get valid channel"); 820 hostapd_set_state(iface, HAPD_IFACE_DFS); 821 return 0; 822 } 823 824 iface->freq = channel->freq; 825 iface->conf->channel = channel->chan; 826 iface->conf->secondary_channel = sec; 827 hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1); 828 hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2); 829 } 830 } while (res); 831 832 /* Finally start CAC */ 833 hostapd_set_state(iface, HAPD_IFACE_DFS); 834 wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq); 835 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START 836 "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds", 837 iface->freq, 838 iface->conf->channel, iface->conf->secondary_channel, 839 hostapd_get_oper_chwidth(iface->conf), 840 hostapd_get_oper_centr_freq_seg0_idx(iface->conf), 841 hostapd_get_oper_centr_freq_seg1_idx(iface->conf), 842 iface->dfs_cac_ms / 1000); 843 844 res = hostapd_start_dfs_cac( 845 iface, iface->conf->hw_mode, iface->freq, iface->conf->channel, 846 iface->conf->ieee80211n, iface->conf->ieee80211ac, 847 iface->conf->ieee80211ax, 848 iface->conf->secondary_channel, 849 hostapd_get_oper_chwidth(iface->conf), 850 hostapd_get_oper_centr_freq_seg0_idx(iface->conf), 851 hostapd_get_oper_centr_freq_seg1_idx(iface->conf)); 852 853 if (res) { 854 wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res); 855 return -1; 856 } 857 858 return 0; 859 } 860 861 862 int hostapd_is_dfs_chan_available(struct hostapd_iface *iface) 863 { 864 int n_chans, n_chans1, start_chan_idx, start_chan_idx1; 865 866 /* Get the start (first) channel for current configuration */ 867 start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1); 868 if (start_chan_idx < 0) 869 return 0; 870 871 /* Get the number of used channels, depending on width */ 872 n_chans = dfs_get_used_n_chans(iface, &n_chans1); 873 874 /* Check if all channels are DFS available */ 875 return dfs_check_chans_available(iface, start_chan_idx, n_chans); 876 } 877 878 879 int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, 880 int ht_enabled, int chan_offset, int chan_width, 881 int cf1, int cf2) 882 { 883 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED 884 "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 885 success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 886 887 if (success) { 888 /* Complete iface/ap configuration */ 889 if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) { 890 /* Complete AP configuration for the first bring up. */ 891 if (iface->state != HAPD_IFACE_ENABLED) 892 hostapd_setup_interface_complete(iface, 0); 893 else 894 iface->cac_started = 0; 895 } else { 896 set_dfs_state(iface, freq, ht_enabled, chan_offset, 897 chan_width, cf1, cf2, 898 HOSTAPD_CHAN_DFS_AVAILABLE); 899 /* 900 * Just mark the channel available when CAC completion 901 * event is received in enabled state. CAC result could 902 * have been propagated from another radio having the 903 * same regulatory configuration. When CAC completion is 904 * received during non-HAPD_IFACE_ENABLED state, make 905 * sure the configured channel is available because this 906 * CAC completion event could have been propagated from 907 * another radio. 908 */ 909 if (iface->state != HAPD_IFACE_ENABLED && 910 hostapd_is_dfs_chan_available(iface)) { 911 hostapd_setup_interface_complete(iface, 0); 912 iface->cac_started = 0; 913 } 914 } 915 } 916 917 return 0; 918 } 919 920 921 int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq, 922 int ht_enabled, int chan_offset, int chan_width, 923 int cf1, int cf2) 924 { 925 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_PRE_CAC_EXPIRED 926 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 927 freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 928 929 /* Proceed only if DFS is not offloaded to the driver */ 930 if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) 931 return 0; 932 933 set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, 934 cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); 935 936 return 0; 937 } 938 939 940 static struct hostapd_channel_data * 941 dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel, 942 u8 *oper_centr_freq_seg0_idx, 943 u8 *oper_centr_freq_seg1_idx, int *skip_radar) 944 { 945 struct hostapd_channel_data *channel; 946 947 for (;;) { 948 channel = dfs_get_valid_channel(iface, secondary_channel, 949 oper_centr_freq_seg0_idx, 950 oper_centr_freq_seg1_idx, 951 *skip_radar); 952 if (channel) { 953 wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d", 954 channel->chan); 955 return channel; 956 } 957 958 if (*skip_radar) { 959 *skip_radar = 0; 960 } else { 961 int oper_chwidth; 962 963 oper_chwidth = hostapd_get_oper_chwidth(iface->conf); 964 if (oper_chwidth == CHANWIDTH_USE_HT) 965 break; 966 *skip_radar = 1; 967 hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1); 968 } 969 } 970 971 wpa_printf(MSG_INFO, 972 "%s: no DFS channels left, waiting for NOP to finish", 973 __func__); 974 return NULL; 975 } 976 977 978 static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) 979 { 980 struct hostapd_channel_data *channel; 981 int secondary_channel; 982 u8 oper_centr_freq_seg0_idx = 0; 983 u8 oper_centr_freq_seg1_idx = 0; 984 int skip_radar = 0; 985 int err = 1; 986 987 /* Radar detected during active CAC */ 988 iface->cac_started = 0; 989 channel = dfs_get_valid_channel(iface, &secondary_channel, 990 &oper_centr_freq_seg0_idx, 991 &oper_centr_freq_seg1_idx, 992 skip_radar); 993 994 if (!channel) { 995 channel = dfs_downgrade_bandwidth(iface, &secondary_channel, 996 &oper_centr_freq_seg0_idx, 997 &oper_centr_freq_seg1_idx, 998 &skip_radar); 999 if (!channel) { 1000 wpa_printf(MSG_ERROR, "No valid channel available"); 1001 return err; 1002 } 1003 } 1004 1005 wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 1006 channel->chan); 1007 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 1008 "freq=%d chan=%d sec_chan=%d", channel->freq, 1009 channel->chan, secondary_channel); 1010 1011 iface->freq = channel->freq; 1012 iface->conf->channel = channel->chan; 1013 iface->conf->secondary_channel = secondary_channel; 1014 hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 1015 oper_centr_freq_seg0_idx); 1016 hostapd_set_oper_centr_freq_seg1_idx(iface->conf, 1017 oper_centr_freq_seg1_idx); 1018 err = 0; 1019 1020 hostapd_setup_interface_complete(iface, err); 1021 return err; 1022 } 1023 1024 1025 static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) 1026 { 1027 struct hostapd_channel_data *channel; 1028 int secondary_channel; 1029 u8 oper_centr_freq_seg0_idx; 1030 u8 oper_centr_freq_seg1_idx; 1031 u8 new_vht_oper_chwidth; 1032 int skip_radar = 1; 1033 struct csa_settings csa_settings; 1034 unsigned int i; 1035 int err = 1; 1036 struct hostapd_hw_modes *cmode = iface->current_mode; 1037 u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf); 1038 int ieee80211_mode = IEEE80211_MODE_AP; 1039 1040 wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", 1041 __func__, iface->cac_started ? "yes" : "no", 1042 hostapd_csa_in_progress(iface) ? "yes" : "no"); 1043 1044 /* Check if CSA in progress */ 1045 if (hostapd_csa_in_progress(iface)) 1046 return 0; 1047 1048 /* Check if active CAC */ 1049 if (iface->cac_started) 1050 return hostapd_dfs_start_channel_switch_cac(iface); 1051 1052 /* 1053 * Allow selection of DFS channel in ETSI to comply with 1054 * uniform spreading. 1055 */ 1056 if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI) 1057 skip_radar = 0; 1058 1059 /* Perform channel switch/CSA */ 1060 channel = dfs_get_valid_channel(iface, &secondary_channel, 1061 &oper_centr_freq_seg0_idx, 1062 &oper_centr_freq_seg1_idx, 1063 skip_radar); 1064 1065 if (!channel) { 1066 /* 1067 * If there is no channel to switch immediately to, check if 1068 * there is another channel where we can switch even if it 1069 * requires to perform a CAC first. 1070 */ 1071 skip_radar = 0; 1072 channel = dfs_downgrade_bandwidth(iface, &secondary_channel, 1073 &oper_centr_freq_seg0_idx, 1074 &oper_centr_freq_seg1_idx, 1075 &skip_radar); 1076 if (!channel) { 1077 /* 1078 * Toggle interface state to enter DFS state 1079 * until NOP is finished. 1080 */ 1081 hostapd_disable_iface(iface); 1082 hostapd_enable_iface(iface); 1083 return 0; 1084 } 1085 1086 if (!skip_radar) { 1087 iface->freq = channel->freq; 1088 iface->conf->channel = channel->chan; 1089 iface->conf->secondary_channel = secondary_channel; 1090 hostapd_set_oper_centr_freq_seg0_idx( 1091 iface->conf, oper_centr_freq_seg0_idx); 1092 hostapd_set_oper_centr_freq_seg1_idx( 1093 iface->conf, oper_centr_freq_seg1_idx); 1094 1095 hostapd_disable_iface(iface); 1096 hostapd_enable_iface(iface); 1097 return 0; 1098 } 1099 } 1100 1101 wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 1102 channel->chan); 1103 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 1104 "freq=%d chan=%d sec_chan=%d", channel->freq, 1105 channel->chan, secondary_channel); 1106 1107 new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf); 1108 hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth); 1109 1110 /* Setup CSA request */ 1111 os_memset(&csa_settings, 0, sizeof(csa_settings)); 1112 csa_settings.cs_count = 5; 1113 csa_settings.block_tx = 1; 1114 #ifdef CONFIG_MESH 1115 if (iface->mconf) 1116 ieee80211_mode = IEEE80211_MODE_MESH; 1117 #endif /* CONFIG_MESH */ 1118 err = hostapd_set_freq_params(&csa_settings.freq_params, 1119 iface->conf->hw_mode, 1120 channel->freq, 1121 channel->chan, 1122 iface->conf->enable_edmg, 1123 iface->conf->edmg_channel, 1124 iface->conf->ieee80211n, 1125 iface->conf->ieee80211ac, 1126 iface->conf->ieee80211ax, 1127 secondary_channel, 1128 new_vht_oper_chwidth, 1129 oper_centr_freq_seg0_idx, 1130 oper_centr_freq_seg1_idx, 1131 cmode->vht_capab, 1132 &cmode->he_capab[ieee80211_mode]); 1133 1134 if (err) { 1135 wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); 1136 hostapd_disable_iface(iface); 1137 return err; 1138 } 1139 1140 for (i = 0; i < iface->num_bss; i++) { 1141 err = hostapd_switch_channel(iface->bss[i], &csa_settings); 1142 if (err) 1143 break; 1144 } 1145 1146 if (err) { 1147 wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", 1148 err); 1149 iface->freq = channel->freq; 1150 iface->conf->channel = channel->chan; 1151 iface->conf->secondary_channel = secondary_channel; 1152 hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth); 1153 hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 1154 oper_centr_freq_seg0_idx); 1155 hostapd_set_oper_centr_freq_seg1_idx(iface->conf, 1156 oper_centr_freq_seg1_idx); 1157 1158 hostapd_disable_iface(iface); 1159 hostapd_enable_iface(iface); 1160 return 0; 1161 } 1162 1163 /* Channel configuration will be updated once CSA completes and 1164 * ch_switch_notify event is received */ 1165 1166 wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); 1167 return 0; 1168 } 1169 1170 1171 int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, 1172 int ht_enabled, int chan_offset, int chan_width, 1173 int cf1, int cf2) 1174 { 1175 int res; 1176 1177 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED 1178 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 1179 freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 1180 1181 /* Proceed only if DFS is not offloaded to the driver */ 1182 if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) 1183 return 0; 1184 1185 if (!iface->conf->ieee80211h) 1186 return 0; 1187 1188 /* mark radar frequency as invalid */ 1189 res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, 1190 cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE); 1191 if (!res) 1192 return 0; 1193 1194 /* Skip if reported radar event not overlapped our channels */ 1195 res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); 1196 if (!res) 1197 return 0; 1198 1199 /* radar detected while operating, switch the channel. */ 1200 res = hostapd_dfs_start_channel_switch(iface); 1201 1202 return res; 1203 } 1204 1205 1206 int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, 1207 int ht_enabled, int chan_offset, int chan_width, 1208 int cf1, int cf2) 1209 { 1210 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED 1211 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 1212 freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 1213 1214 /* Proceed only if DFS is not offloaded to the driver */ 1215 if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) 1216 return 0; 1217 1218 /* TODO add correct implementation here */ 1219 set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, 1220 cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); 1221 1222 /* Handle cases where all channels were initially unavailable */ 1223 if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) 1224 hostapd_handle_dfs(iface); 1225 1226 return 0; 1227 } 1228 1229 1230 int hostapd_is_dfs_required(struct hostapd_iface *iface) 1231 { 1232 int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res; 1233 1234 if ((!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && 1235 !iface->conf->ieee80211h) || 1236 !iface->current_mode || 1237 iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) 1238 return 0; 1239 1240 /* Get start (first) channel for current configuration */ 1241 start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1); 1242 if (start_chan_idx == -1) 1243 return -1; 1244 1245 /* Get number of used channels, depend on width */ 1246 n_chans = dfs_get_used_n_chans(iface, &n_chans1); 1247 1248 /* Check if any of configured channels require DFS */ 1249 res = dfs_check_chans_radar(iface, start_chan_idx, n_chans); 1250 if (res) 1251 return res; 1252 if (start_chan_idx1 >= 0 && n_chans1 > 0) 1253 res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1); 1254 return res; 1255 } 1256 1257 1258 int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq, 1259 int ht_enabled, int chan_offset, int chan_width, 1260 int cf1, int cf2) 1261 { 1262 /* This is called when the driver indicates that an offloaded DFS has 1263 * started CAC. */ 1264 hostapd_set_state(iface, HAPD_IFACE_DFS); 1265 /* TODO: How to check CAC time for ETSI weather channels? */ 1266 iface->dfs_cac_ms = 60000; 1267 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START 1268 "freq=%d chan=%d chan_offset=%d width=%d seg0=%d " 1269 "seg1=%d cac_time=%ds", 1270 freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 1271 iface->dfs_cac_ms / 1000); 1272 iface->cac_started = 1; 1273 os_get_reltime(&iface->dfs_cac_start); 1274 return 0; 1275 } 1276 1277 1278 /* 1279 * Main DFS handler for offloaded case. 1280 * 2 - continue channel/AP setup for non-DFS channel 1281 * 1 - continue channel/AP setup for DFS channel 1282 * 0 - channel/AP setup will be continued after CAC 1283 * -1 - hit critical error 1284 */ 1285 int hostapd_handle_dfs_offload(struct hostapd_iface *iface) 1286 { 1287 int dfs_res; 1288 1289 wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d", 1290 __func__, iface->cac_started); 1291 1292 /* 1293 * If DFS has already been started, then we are being called from a 1294 * callback to continue AP/channel setup. Reset the CAC start flag and 1295 * return. 1296 */ 1297 if (iface->cac_started) { 1298 wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d", 1299 __func__, iface->cac_started); 1300 iface->cac_started = 0; 1301 return 1; 1302 } 1303 1304 dfs_res = hostapd_is_dfs_required(iface); 1305 if (dfs_res > 0) { 1306 wpa_printf(MSG_DEBUG, 1307 "%s: freq %d MHz requires DFS for %d chans", 1308 __func__, iface->freq, dfs_res); 1309 return 0; 1310 } 1311 1312 wpa_printf(MSG_DEBUG, 1313 "%s: freq %d MHz does not require DFS. Continue channel/AP setup", 1314 __func__, iface->freq); 1315 return 2; 1316 } 1317 1318 1319 int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width, 1320 int center_freq) 1321 { 1322 struct hostapd_channel_data *chan; 1323 struct hostapd_hw_modes *mode = iface->current_mode; 1324 int half_width; 1325 int res = 0; 1326 int i; 1327 1328 if (!iface->conf->ieee80211h || !mode || 1329 mode->mode != HOSTAPD_MODE_IEEE80211A) 1330 return 0; 1331 1332 switch (width) { 1333 case CHAN_WIDTH_20_NOHT: 1334 case CHAN_WIDTH_20: 1335 half_width = 10; 1336 break; 1337 case CHAN_WIDTH_40: 1338 half_width = 20; 1339 break; 1340 case CHAN_WIDTH_80: 1341 case CHAN_WIDTH_80P80: 1342 half_width = 40; 1343 break; 1344 case CHAN_WIDTH_160: 1345 half_width = 80; 1346 break; 1347 default: 1348 wpa_printf(MSG_WARNING, "DFS chanwidth %d not supported", 1349 width); 1350 return 0; 1351 } 1352 1353 for (i = 0; i < mode->num_channels; i++) { 1354 chan = &mode->channels[i]; 1355 1356 if (!(chan->flag & HOSTAPD_CHAN_RADAR)) 1357 continue; 1358 1359 if ((chan->flag & HOSTAPD_CHAN_DFS_MASK) == 1360 HOSTAPD_CHAN_DFS_AVAILABLE) 1361 continue; 1362 1363 if (center_freq - chan->freq < half_width && 1364 chan->freq - center_freq < half_width) 1365 res++; 1366 } 1367 1368 wpa_printf(MSG_DEBUG, "DFS CAC required: (%d, %d): in range: %s", 1369 center_freq - half_width, center_freq + half_width, 1370 res ? "yes" : "no"); 1371 1372 return res; 1373 } 1374