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