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