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