1 /* 2 * DFS - Dynamic Frequency Selection 3 * Copyright (c) 2002-2013, Jouni Malinen <j (at) 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 21 static 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 47 static 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 70 static 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 118 static 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 144 static 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 */ 167 static 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 207 static 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] */ 249 static 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 */ 310 static 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 */ 330 static 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 */ 358 static 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 381 static struct hostapd_channel_data * 382 dfs_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 430 static 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 456 static 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 511 static 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 static unsigned int dfs_get_cac_time(struct hostapd_iface *iface, 577 int start_chan_idx, int n_chans) 578 { 579 struct hostapd_channel_data *channel; 580 struct hostapd_hw_modes *mode; 581 int i; 582 unsigned int cac_time_ms = 0; 583 584 mode = iface->current_mode; 585 586 for (i = 0; i < n_chans; i++) { 587 channel = &mode->channels[start_chan_idx + i]; 588 if (!(channel->flag & HOSTAPD_CHAN_RADAR)) 589 continue; 590 if (channel->dfs_cac_ms > cac_time_ms) 591 cac_time_ms = channel->dfs_cac_ms; 592 } 593 594 return cac_time_ms; 595 } 596 597 598 /* 599 * Main DFS handler 600 * 1 - continue channel/ap setup 601 * 0 - channel/ap setup will be continued after CAC 602 * -1 - hit critical error 603 */ 604 int hostapd_handle_dfs(struct hostapd_iface *iface) 605 { 606 struct hostapd_channel_data *channel; 607 int res, n_chans, start_chan_idx; 608 int skip_radar = 0; 609 610 iface->cac_started = 0; 611 612 do { 613 /* Get start (first) channel for current configuration */ 614 start_chan_idx = dfs_get_start_chan_idx(iface); 615 if (start_chan_idx == -1) 616 return -1; 617 618 /* Get number of used channels, depend on width */ 619 n_chans = dfs_get_used_n_chans(iface); 620 621 /* Setup CAC time */ 622 iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx, 623 n_chans); 624 625 /* Check if any of configured channels require DFS */ 626 res = dfs_check_chans_radar(iface, start_chan_idx, n_chans); 627 wpa_printf(MSG_DEBUG, 628 "DFS %d channels required radar detection", 629 res); 630 if (!res) 631 return 1; 632 633 /* Check if all channels are DFS available */ 634 res = dfs_check_chans_available(iface, start_chan_idx, n_chans); 635 wpa_printf(MSG_DEBUG, 636 "DFS all channels available, (SKIP CAC): %s", 637 res ? "yes" : "no"); 638 if (res) 639 return 1; 640 641 /* Check if any of configured channels is unavailable */ 642 res = dfs_check_chans_unavailable(iface, start_chan_idx, 643 n_chans); 644 wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", 645 res, res ? "yes": "no"); 646 if (res) { 647 int sec = 0; 648 u8 cf1 = 0, cf2 = 0; 649 650 channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, 651 skip_radar); 652 if (!channel) { 653 wpa_printf(MSG_ERROR, "could not get valid channel"); 654 return -1; 655 } 656 657 iface->freq = channel->freq; 658 iface->conf->channel = channel->chan; 659 iface->conf->secondary_channel = sec; 660 iface->conf->vht_oper_centr_freq_seg0_idx = cf1; 661 iface->conf->vht_oper_centr_freq_seg1_idx = cf2; 662 } 663 } while (res); 664 665 /* Finally start CAC */ 666 hostapd_set_state(iface, HAPD_IFACE_DFS); 667 wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq); 668 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START 669 "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds", 670 iface->freq, 671 iface->conf->channel, iface->conf->secondary_channel, 672 iface->conf->vht_oper_chwidth, 673 iface->conf->vht_oper_centr_freq_seg0_idx, 674 iface->conf->vht_oper_centr_freq_seg1_idx, 675 iface->dfs_cac_ms / 1000); 676 677 res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode, 678 iface->freq, 679 iface->conf->channel, 680 iface->conf->ieee80211n, 681 iface->conf->ieee80211ac, 682 iface->conf->secondary_channel, 683 iface->conf->vht_oper_chwidth, 684 iface->conf->vht_oper_centr_freq_seg0_idx, 685 iface->conf->vht_oper_centr_freq_seg1_idx); 686 687 if (res) { 688 wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res); 689 return -1; 690 } 691 692 return 0; 693 } 694 695 696 int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, 697 int ht_enabled, int chan_offset, int chan_width, 698 int cf1, int cf2) 699 { 700 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED 701 "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 702 success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 703 704 if (success) { 705 /* Complete iface/ap configuration */ 706 set_dfs_state(iface, freq, ht_enabled, chan_offset, 707 chan_width, cf1, cf2, 708 HOSTAPD_CHAN_DFS_AVAILABLE); 709 iface->cac_started = 0; 710 hostapd_setup_interface_complete(iface, 0); 711 } 712 713 return 0; 714 } 715 716 717 static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) 718 { 719 struct hostapd_channel_data *channel; 720 int secondary_channel; 721 u8 vht_oper_centr_freq_seg0_idx = 0; 722 u8 vht_oper_centr_freq_seg1_idx = 0; 723 int skip_radar = 0; 724 int err = 1; 725 726 /* Radar detected during active CAC */ 727 iface->cac_started = 0; 728 channel = dfs_get_valid_channel(iface, &secondary_channel, 729 &vht_oper_centr_freq_seg0_idx, 730 &vht_oper_centr_freq_seg1_idx, 731 skip_radar); 732 733 if (!channel) { 734 wpa_printf(MSG_ERROR, "No valid channel available"); 735 hostapd_setup_interface_complete(iface, err); 736 return err; 737 } 738 739 wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 740 channel->chan); 741 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 742 "freq=%d chan=%d sec_chan=%d", channel->freq, 743 channel->chan, secondary_channel); 744 745 iface->freq = channel->freq; 746 iface->conf->channel = channel->chan; 747 iface->conf->secondary_channel = secondary_channel; 748 iface->conf->vht_oper_centr_freq_seg0_idx = 749 vht_oper_centr_freq_seg0_idx; 750 iface->conf->vht_oper_centr_freq_seg1_idx = 751 vht_oper_centr_freq_seg1_idx; 752 err = 0; 753 754 hostapd_setup_interface_complete(iface, err); 755 return err; 756 } 757 758 759 static int hostapd_csa_in_progress(struct hostapd_iface *iface) 760 { 761 unsigned int i; 762 for (i = 0; i < iface->num_bss; i++) 763 if (iface->bss[i]->csa_in_progress) 764 return 1; 765 return 0; 766 } 767 768 769 static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) 770 { 771 struct hostapd_channel_data *channel; 772 int secondary_channel; 773 u8 vht_oper_centr_freq_seg0_idx; 774 u8 vht_oper_centr_freq_seg1_idx; 775 int skip_radar = 1; 776 struct csa_settings csa_settings; 777 unsigned int i; 778 int err = 1; 779 780 wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", 781 __func__, iface->cac_started ? "yes" : "no", 782 hostapd_csa_in_progress(iface) ? "yes" : "no"); 783 784 /* Check if CSA in progress */ 785 if (hostapd_csa_in_progress(iface)) 786 return 0; 787 788 /* Check if active CAC */ 789 if (iface->cac_started) 790 return hostapd_dfs_start_channel_switch_cac(iface); 791 792 /* Perform channel switch/CSA */ 793 channel = dfs_get_valid_channel(iface, &secondary_channel, 794 &vht_oper_centr_freq_seg0_idx, 795 &vht_oper_centr_freq_seg1_idx, 796 skip_radar); 797 798 if (!channel) { 799 /* 800 * If there is no channel to switch immediately to, check if 801 * there is another channel where we can switch even if it 802 * requires to perform a CAC first. 803 */ 804 skip_radar = 0; 805 channel = dfs_get_valid_channel(iface, &secondary_channel, 806 &vht_oper_centr_freq_seg0_idx, 807 &vht_oper_centr_freq_seg1_idx, 808 skip_radar); 809 if (!channel) { 810 /* FIXME: Wait for channel(s) to become available */ 811 hostapd_disable_iface(iface); 812 return err; 813 } 814 815 iface->freq = channel->freq; 816 iface->conf->channel = channel->chan; 817 iface->conf->secondary_channel = secondary_channel; 818 iface->conf->vht_oper_centr_freq_seg0_idx = 819 vht_oper_centr_freq_seg0_idx; 820 iface->conf->vht_oper_centr_freq_seg1_idx = 821 vht_oper_centr_freq_seg1_idx; 822 823 hostapd_disable_iface(iface); 824 hostapd_enable_iface(iface); 825 return 0; 826 } 827 828 wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 829 channel->chan); 830 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 831 "freq=%d chan=%d sec_chan=%d", channel->freq, 832 channel->chan, secondary_channel); 833 834 /* Setup CSA request */ 835 os_memset(&csa_settings, 0, sizeof(csa_settings)); 836 csa_settings.cs_count = 5; 837 csa_settings.block_tx = 1; 838 err = hostapd_set_freq_params(&csa_settings.freq_params, 839 iface->conf->hw_mode, 840 channel->freq, 841 channel->chan, 842 iface->conf->ieee80211n, 843 iface->conf->ieee80211ac, 844 secondary_channel, 845 iface->conf->vht_oper_chwidth, 846 vht_oper_centr_freq_seg0_idx, 847 vht_oper_centr_freq_seg1_idx, 848 iface->current_mode->vht_capab); 849 850 if (err) { 851 wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); 852 hostapd_disable_iface(iface); 853 return err; 854 } 855 856 for (i = 0; i < iface->num_bss; i++) { 857 err = hostapd_switch_channel(iface->bss[i], &csa_settings); 858 if (err) 859 break; 860 } 861 862 if (err) { 863 wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", 864 err); 865 iface->freq = channel->freq; 866 iface->conf->channel = channel->chan; 867 iface->conf->secondary_channel = secondary_channel; 868 iface->conf->vht_oper_centr_freq_seg0_idx = 869 vht_oper_centr_freq_seg0_idx; 870 iface->conf->vht_oper_centr_freq_seg1_idx = 871 vht_oper_centr_freq_seg1_idx; 872 873 hostapd_disable_iface(iface); 874 hostapd_enable_iface(iface); 875 return 0; 876 } 877 878 /* Channel configuration will be updated once CSA completes and 879 * ch_switch_notify event is received */ 880 881 wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); 882 return 0; 883 } 884 885 886 int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, 887 int ht_enabled, int chan_offset, int chan_width, 888 int cf1, int cf2) 889 { 890 int res; 891 892 if (!iface->conf->ieee80211h) 893 return 0; 894 895 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED 896 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 897 freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 898 899 /* mark radar frequency as invalid */ 900 set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, 901 cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE); 902 903 /* Skip if reported radar event not overlapped our channels */ 904 res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); 905 if (!res) 906 return 0; 907 908 /* radar detected while operating, switch the channel. */ 909 res = hostapd_dfs_start_channel_switch(iface); 910 911 return res; 912 } 913 914 915 int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, 916 int ht_enabled, int chan_offset, int chan_width, 917 int cf1, int cf2) 918 { 919 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED 920 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 921 freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 922 /* TODO add correct implementation here */ 923 set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, 924 cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); 925 return 0; 926 } 927 928 929 int hostapd_is_dfs_required(struct hostapd_iface *iface) 930 { 931 int n_chans, start_chan_idx; 932 933 if (!iface->conf->ieee80211h || !iface->current_mode || 934 iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) 935 return 0; 936 937 /* Get start (first) channel for current configuration */ 938 start_chan_idx = dfs_get_start_chan_idx(iface); 939 if (start_chan_idx == -1) 940 return -1; 941 942 /* Get number of used channels, depend on width */ 943 n_chans = dfs_get_used_n_chans(iface); 944 945 /* Check if any of configured channels require DFS */ 946 return dfs_check_chans_radar(iface, start_chan_idx, n_chans); 947 } 948