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