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