hw_features.c revision 61d9df3e62aaa0e87ad05452fcb95142159a17b6
1/* 2 * hostapd / Hardware feature query and different modes 3 * Copyright 2002-2003, Instant802 Networks, Inc. 4 * Copyright 2005-2006, Devicescape Software, Inc. 5 * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * Alternatively, this software may be distributed under the terms of BSD 12 * license. 13 * 14 * See README and COPYING for more details. 15 */ 16 17#include "utils/includes.h" 18 19#include "utils/common.h" 20#include "utils/eloop.h" 21#include "common/ieee802_11_defs.h" 22#include "common/ieee802_11_common.h" 23#include "drivers/driver.h" 24#include "hostapd.h" 25#include "ap_config.h" 26#include "ap_drv_ops.h" 27#include "hw_features.h" 28 29 30void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, 31 size_t num_hw_features) 32{ 33 size_t i; 34 35 if (hw_features == NULL) 36 return; 37 38 for (i = 0; i < num_hw_features; i++) { 39 os_free(hw_features[i].channels); 40 os_free(hw_features[i].rates); 41 } 42 43 os_free(hw_features); 44} 45 46 47int hostapd_get_hw_features(struct hostapd_iface *iface) 48{ 49 struct hostapd_data *hapd = iface->bss[0]; 50 int ret = 0, i, j; 51 u16 num_modes, flags; 52 struct hostapd_hw_modes *modes; 53 54 if (hostapd_drv_none(hapd)) 55 return -1; 56 modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags); 57 if (modes == NULL) { 58 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 59 HOSTAPD_LEVEL_DEBUG, 60 "Fetching hardware channel/rate support not " 61 "supported."); 62 return -1; 63 } 64 65 iface->hw_flags = flags; 66 67 hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); 68 iface->hw_features = modes; 69 iface->num_hw_features = num_modes; 70 71 for (i = 0; i < num_modes; i++) { 72 struct hostapd_hw_modes *feature = &modes[i]; 73 /* set flag for channels we can use in current regulatory 74 * domain */ 75 for (j = 0; j < feature->num_channels; j++) { 76 /* 77 * Disable all channels that are marked not to allow 78 * IBSS operation or active scanning. In addition, 79 * disable all channels that require radar detection, 80 * since that (in addition to full DFS) is not yet 81 * supported. 82 */ 83 if (feature->channels[j].flag & 84 (HOSTAPD_CHAN_NO_IBSS | 85 HOSTAPD_CHAN_PASSIVE_SCAN | 86 HOSTAPD_CHAN_RADAR)) 87 feature->channels[j].flag |= 88 HOSTAPD_CHAN_DISABLED; 89 if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED) 90 continue; 91 wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d " 92 "chan=%d freq=%d MHz max_tx_power=%d dBm", 93 feature->mode, 94 feature->channels[j].chan, 95 feature->channels[j].freq, 96 feature->channels[j].max_tx_power); 97 } 98 } 99 100 return ret; 101} 102 103 104int hostapd_prepare_rates(struct hostapd_iface *iface, 105 struct hostapd_hw_modes *mode) 106{ 107 int i, num_basic_rates = 0; 108 int basic_rates_a[] = { 60, 120, 240, -1 }; 109 int basic_rates_b[] = { 10, 20, -1 }; 110 int basic_rates_g[] = { 10, 20, 55, 110, -1 }; 111 int *basic_rates; 112 113 if (iface->conf->basic_rates) 114 basic_rates = iface->conf->basic_rates; 115 else switch (mode->mode) { 116 case HOSTAPD_MODE_IEEE80211A: 117 basic_rates = basic_rates_a; 118 break; 119 case HOSTAPD_MODE_IEEE80211B: 120 basic_rates = basic_rates_b; 121 break; 122 case HOSTAPD_MODE_IEEE80211G: 123 basic_rates = basic_rates_g; 124 break; 125 default: 126 return -1; 127 } 128 129 i = 0; 130 while (basic_rates[i] >= 0) 131 i++; 132 os_free(iface->basic_rates); 133 iface->basic_rates = os_malloc(i * sizeof(int)); 134 if (iface->basic_rates) 135 os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int)); 136 137 os_free(iface->current_rates); 138 iface->num_rates = 0; 139 140 iface->current_rates = 141 os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data)); 142 if (!iface->current_rates) { 143 wpa_printf(MSG_ERROR, "Failed to allocate memory for rate " 144 "table."); 145 return -1; 146 } 147 148 for (i = 0; i < mode->num_rates; i++) { 149 struct hostapd_rate_data *rate; 150 151 if (iface->conf->supported_rates && 152 !hostapd_rate_found(iface->conf->supported_rates, 153 mode->rates[i])) 154 continue; 155 156 rate = &iface->current_rates[iface->num_rates]; 157 rate->rate = mode->rates[i]; 158 if (hostapd_rate_found(basic_rates, rate->rate)) { 159 rate->flags |= HOSTAPD_RATE_BASIC; 160 num_basic_rates++; 161 } 162 wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x", 163 iface->num_rates, rate->rate, rate->flags); 164 iface->num_rates++; 165 } 166 167 if ((iface->num_rates == 0 || num_basic_rates == 0) && 168 (!iface->conf->ieee80211n || !iface->conf->require_ht)) { 169 wpa_printf(MSG_ERROR, "No rates remaining in supported/basic " 170 "rate sets (%d,%d).", 171 iface->num_rates, num_basic_rates); 172 return -1; 173 } 174 175 return 0; 176} 177 178 179#ifdef CONFIG_IEEE80211N 180static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface) 181{ 182 int sec_chan, ok, j, first; 183 int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 184 184, 192 }; 185 size_t k; 186 187 if (!iface->conf->secondary_channel) 188 return 1; /* HT40 not used */ 189 190 sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4; 191 wpa_printf(MSG_DEBUG, "HT40: control channel: %d " 192 "secondary channel: %d", 193 iface->conf->channel, sec_chan); 194 195 /* Verify that HT40 secondary channel is an allowed 20 MHz 196 * channel */ 197 ok = 0; 198 for (j = 0; j < iface->current_mode->num_channels; j++) { 199 struct hostapd_channel_data *chan = 200 &iface->current_mode->channels[j]; 201 if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && 202 chan->chan == sec_chan) { 203 ok = 1; 204 break; 205 } 206 } 207 if (!ok) { 208 wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed", 209 sec_chan); 210 return 0; 211 } 212 213 /* 214 * Verify that HT40 primary,secondary channel pair is allowed per 215 * IEEE 802.11n Annex J. This is only needed for 5 GHz band since 216 * 2.4 GHz rules allow all cases where the secondary channel fits into 217 * the list of allowed channels (already checked above). 218 */ 219 if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) 220 return 1; 221 222 if (iface->conf->secondary_channel > 0) 223 first = iface->conf->channel; 224 else 225 first = sec_chan; 226 227 ok = 0; 228 for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) { 229 if (first == allowed[k]) { 230 ok = 1; 231 break; 232 } 233 } 234 if (!ok) { 235 wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed", 236 iface->conf->channel, 237 iface->conf->secondary_channel); 238 return 0; 239 } 240 241 return 1; 242} 243 244 245static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface) 246{ 247 if (iface->conf->secondary_channel > 0) { 248 iface->conf->channel += 4; 249 iface->conf->secondary_channel = -1; 250 } else { 251 iface->conf->channel -= 4; 252 iface->conf->secondary_channel = 1; 253 } 254} 255 256 257static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss, 258 int *pri_chan, int *sec_chan) 259{ 260 struct ieee80211_ht_operation *oper; 261 struct ieee802_11_elems elems; 262 263 *pri_chan = *sec_chan = 0; 264 265 ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); 266 if (elems.ht_operation && 267 elems.ht_operation_len >= sizeof(*oper)) { 268 oper = (struct ieee80211_ht_operation *) elems.ht_operation; 269 *pri_chan = oper->control_chan; 270 if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) { 271 int sec = oper->ht_param & 272 HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; 273 if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 274 *sec_chan = *pri_chan + 4; 275 else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 276 *sec_chan = *pri_chan - 4; 277 } 278 } 279} 280 281 282static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, 283 struct wpa_scan_results *scan_res) 284{ 285 int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss; 286 int bss_pri_chan, bss_sec_chan; 287 size_t i; 288 int match; 289 290 pri_chan = iface->conf->channel; 291 sec_chan = iface->conf->secondary_channel * 4; 292 pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan); 293 if (iface->conf->secondary_channel > 0) 294 sec_freq = pri_freq + 20; 295 else 296 sec_freq = pri_freq - 20; 297 298 /* 299 * Switch PRI/SEC channels if Beacons were detected on selected SEC 300 * channel, but not on selected PRI channel. 301 */ 302 pri_bss = sec_bss = 0; 303 for (i = 0; i < scan_res->num; i++) { 304 struct wpa_scan_res *bss = scan_res->res[i]; 305 if (bss->freq == pri_freq) 306 pri_bss++; 307 else if (bss->freq == sec_freq) 308 sec_bss++; 309 } 310 if (sec_bss && !pri_bss) { 311 wpa_printf(MSG_INFO, "Switch own primary and secondary " 312 "channel to get secondary channel with no Beacons " 313 "from other BSSes"); 314 ieee80211n_switch_pri_sec(iface); 315 } 316 317 /* 318 * Match PRI/SEC channel with any existing HT40 BSS on the same 319 * channels that we are about to use (if already mixed order in 320 * existing BSSes, use own preference). 321 */ 322 match = 0; 323 for (i = 0; i < scan_res->num; i++) { 324 struct wpa_scan_res *bss = scan_res->res[i]; 325 ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); 326 if (pri_chan == bss_pri_chan && 327 sec_chan == bss_sec_chan) { 328 match = 1; 329 break; 330 } 331 } 332 if (!match) { 333 for (i = 0; i < scan_res->num; i++) { 334 struct wpa_scan_res *bss = scan_res->res[i]; 335 ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, 336 &bss_sec_chan); 337 if (pri_chan == bss_sec_chan && 338 sec_chan == bss_pri_chan) { 339 wpa_printf(MSG_INFO, "Switch own primary and " 340 "secondary channel due to BSS " 341 "overlap with " MACSTR, 342 MAC2STR(bss->bssid)); 343 ieee80211n_switch_pri_sec(iface); 344 break; 345 } 346 } 347 } 348 349 return 1; 350} 351 352 353static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, 354 struct wpa_scan_results *scan_res) 355{ 356 int pri_freq, sec_freq; 357 int affected_start, affected_end; 358 size_t i; 359 360 pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 361 if (iface->conf->secondary_channel > 0) 362 sec_freq = pri_freq + 20; 363 else 364 sec_freq = pri_freq - 20; 365 affected_start = (pri_freq + sec_freq) / 2 - 25; 366 affected_end = (pri_freq + sec_freq) / 2 + 25; 367 wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 368 affected_start, affected_end); 369 for (i = 0; i < scan_res->num; i++) { 370 struct wpa_scan_res *bss = scan_res->res[i]; 371 int pri = bss->freq; 372 int sec = pri; 373 int sec_chan, pri_chan; 374 375 ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan); 376 377 if (sec_chan) { 378 if (sec_chan < pri_chan) 379 sec = pri - 20; 380 else 381 sec = pri + 20; 382 } 383 384 if ((pri < affected_start || pri > affected_end) && 385 (sec < affected_start || sec > affected_end)) 386 continue; /* not within affected channel range */ 387 388 wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR 389 " freq=%d pri=%d sec=%d", 390 MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); 391 392 if (sec_chan) { 393 if (pri_freq != pri || sec_freq != sec) { 394 wpa_printf(MSG_DEBUG, "40 MHz pri/sec " 395 "mismatch with BSS " MACSTR 396 " <%d,%d> (chan=%d%c) vs. <%d,%d>", 397 MAC2STR(bss->bssid), 398 pri, sec, pri_chan, 399 sec > pri ? '+' : '-', 400 pri_freq, sec_freq); 401 return 0; 402 } 403 } 404 405 /* TODO: 40 MHz intolerant */ 406 } 407 408 return 1; 409} 410 411 412static void ieee80211n_check_scan(struct hostapd_iface *iface) 413{ 414 struct wpa_scan_results *scan_res; 415 int oper40; 416 int res; 417 418 /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is 419 * allowed per IEEE Std 802.11-2012, 10.15.3.2 */ 420 421 iface->scan_cb = NULL; 422 423 scan_res = hostapd_driver_get_scan_results(iface->bss[0]); 424 if (scan_res == NULL) { 425 hostapd_setup_interface_complete(iface, 1); 426 return; 427 } 428 429 if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A) 430 oper40 = ieee80211n_check_40mhz_5g(iface, scan_res); 431 else 432 oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res); 433 wpa_scan_results_free(scan_res); 434 435 if (!oper40) { 436 wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on " 437 "channel pri=%d sec=%d based on overlapping BSSes", 438 iface->conf->channel, 439 iface->conf->channel + 440 iface->conf->secondary_channel * 4); 441 iface->conf->secondary_channel = 0; 442 iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; 443 } 444 445 res = ieee80211n_allowed_ht40_channel_pair(iface); 446 hostapd_setup_interface_complete(iface, !res); 447} 448 449 450static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface, 451 struct wpa_driver_scan_params *params) 452{ 453 /* Scan only the affected frequency range */ 454 int pri_freq, sec_freq; 455 int affected_start, affected_end; 456 int i, pos; 457 struct hostapd_hw_modes *mode; 458 459 if (iface->current_mode == NULL) 460 return; 461 462 pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 463 if (iface->conf->secondary_channel > 0) 464 sec_freq = pri_freq + 20; 465 else 466 sec_freq = pri_freq - 20; 467 affected_start = (pri_freq + sec_freq) / 2 - 25; 468 affected_end = (pri_freq + sec_freq) / 2 + 25; 469 wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 470 affected_start, affected_end); 471 472 mode = iface->current_mode; 473 params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); 474 if (params->freqs == NULL) 475 return; 476 pos = 0; 477 478 for (i = 0; i < mode->num_channels; i++) { 479 struct hostapd_channel_data *chan = &mode->channels[i]; 480 if (chan->flag & HOSTAPD_CHAN_DISABLED) 481 continue; 482 if (chan->freq < affected_start || 483 chan->freq > affected_end) 484 continue; 485 params->freqs[pos++] = chan->freq; 486 } 487} 488 489 490static int ieee80211n_check_40mhz(struct hostapd_iface *iface) 491{ 492 struct wpa_driver_scan_params params; 493 494 if (!iface->conf->secondary_channel) 495 return 0; /* HT40 not used */ 496 497 wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " 498 "40 MHz channel"); 499 os_memset(¶ms, 0, sizeof(params)); 500 if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) 501 ieee80211n_scan_channels_2g4(iface, ¶ms); 502 if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) { 503 wpa_printf(MSG_ERROR, "Failed to request a scan of " 504 "neighboring BSSes"); 505 os_free(params.freqs); 506 return -1; 507 } 508 os_free(params.freqs); 509 510 iface->scan_cb = ieee80211n_check_scan; 511 return 1; 512} 513 514 515static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) 516{ 517 u16 hw = iface->current_mode->ht_capab; 518 u16 conf = iface->conf->ht_capab; 519 520 if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) && 521 !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) { 522 wpa_printf(MSG_ERROR, "Driver does not support configured " 523 "HT capability [LDPC]"); 524 return 0; 525 } 526 527 if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && 528 !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { 529 wpa_printf(MSG_ERROR, "Driver does not support configured " 530 "HT capability [HT40*]"); 531 return 0; 532 } 533 534 if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) && 535 (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) { 536 wpa_printf(MSG_ERROR, "Driver does not support configured " 537 "HT capability [SMPS-*]"); 538 return 0; 539 } 540 541 if ((conf & HT_CAP_INFO_GREEN_FIELD) && 542 !(hw & HT_CAP_INFO_GREEN_FIELD)) { 543 wpa_printf(MSG_ERROR, "Driver does not support configured " 544 "HT capability [GF]"); 545 return 0; 546 } 547 548 if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) && 549 !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) { 550 wpa_printf(MSG_ERROR, "Driver does not support configured " 551 "HT capability [SHORT-GI-20]"); 552 return 0; 553 } 554 555 if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) && 556 !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) { 557 wpa_printf(MSG_ERROR, "Driver does not support configured " 558 "HT capability [SHORT-GI-40]"); 559 return 0; 560 } 561 562 if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) { 563 wpa_printf(MSG_ERROR, "Driver does not support configured " 564 "HT capability [TX-STBC]"); 565 return 0; 566 } 567 568 if ((conf & HT_CAP_INFO_RX_STBC_MASK) > 569 (hw & HT_CAP_INFO_RX_STBC_MASK)) { 570 wpa_printf(MSG_ERROR, "Driver does not support configured " 571 "HT capability [RX-STBC*]"); 572 return 0; 573 } 574 575 if ((conf & HT_CAP_INFO_DELAYED_BA) && 576 !(hw & HT_CAP_INFO_DELAYED_BA)) { 577 wpa_printf(MSG_ERROR, "Driver does not support configured " 578 "HT capability [DELAYED-BA]"); 579 return 0; 580 } 581 582 if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) && 583 !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) { 584 wpa_printf(MSG_ERROR, "Driver does not support configured " 585 "HT capability [MAX-AMSDU-7935]"); 586 return 0; 587 } 588 589 if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) && 590 !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) { 591 wpa_printf(MSG_ERROR, "Driver does not support configured " 592 "HT capability [DSSS_CCK-40]"); 593 return 0; 594 } 595 596 if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) { 597 wpa_printf(MSG_ERROR, "Driver does not support configured " 598 "HT capability [PSMP]"); 599 return 0; 600 } 601 602 if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) && 603 !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) { 604 wpa_printf(MSG_ERROR, "Driver does not support configured " 605 "HT capability [LSIG-TXOP-PROT]"); 606 return 0; 607 } 608 609 return 1; 610} 611 612#endif /* CONFIG_IEEE80211N */ 613 614 615int hostapd_check_ht_capab(struct hostapd_iface *iface) 616{ 617#ifdef CONFIG_IEEE80211N 618 int ret; 619 if (!iface->conf->ieee80211n) 620 return 0; 621 if (!ieee80211n_supported_ht_capab(iface)) 622 return -1; 623 ret = ieee80211n_check_40mhz(iface); 624 if (ret) 625 return ret; 626 if (!ieee80211n_allowed_ht40_channel_pair(iface)) 627 return -1; 628#endif /* CONFIG_IEEE80211N */ 629 630 return 0; 631} 632 633 634/** 635 * hostapd_select_hw_mode - Select the hardware mode 636 * @iface: Pointer to interface data. 637 * Returns: 0 on success, < 0 on failure 638 * 639 * Sets up the hardware mode, channel, rates, and passive scanning 640 * based on the configuration. 641 */ 642int hostapd_select_hw_mode(struct hostapd_iface *iface) 643{ 644 int i, j, ok; 645 646 if (iface->num_hw_features < 1) 647 return -1; 648 649 iface->current_mode = NULL; 650 for (i = 0; i < iface->num_hw_features; i++) { 651 struct hostapd_hw_modes *mode = &iface->hw_features[i]; 652 if (mode->mode == iface->conf->hw_mode) { 653 iface->current_mode = mode; 654 break; 655 } 656 } 657 658 if (iface->current_mode == NULL) { 659 wpa_printf(MSG_ERROR, "Hardware does not support configured " 660 "mode"); 661 hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 662 HOSTAPD_LEVEL_WARNING, 663 "Hardware does not support configured mode " 664 "(%d) (hw_mode in hostapd.conf)", 665 (int) iface->conf->hw_mode); 666 return -2; 667 } 668 669 ok = 0; 670 for (j = 0; j < iface->current_mode->num_channels; j++) { 671 struct hostapd_channel_data *chan = 672 &iface->current_mode->channels[j]; 673 if (chan->chan == iface->conf->channel) { 674 if (chan->flag & HOSTAPD_CHAN_DISABLED) { 675 wpa_printf(MSG_ERROR, 676 "channel [%i] (%i) is disabled for " 677 "use in AP mode, flags: 0x%x%s%s%s", 678 j, chan->chan, chan->flag, 679 chan->flag & HOSTAPD_CHAN_NO_IBSS ? 680 " NO-IBSS" : "", 681 chan->flag & 682 HOSTAPD_CHAN_PASSIVE_SCAN ? 683 " PASSIVE-SCAN" : "", 684 chan->flag & HOSTAPD_CHAN_RADAR ? 685 " RADAR" : ""); 686 } else { 687 ok = 1; 688 break; 689 } 690 } 691 } 692 if (ok && iface->conf->secondary_channel) { 693 int sec_ok = 0; 694 int sec_chan = iface->conf->channel + 695 iface->conf->secondary_channel * 4; 696 for (j = 0; j < iface->current_mode->num_channels; j++) { 697 struct hostapd_channel_data *chan = 698 &iface->current_mode->channels[j]; 699 if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && 700 (chan->chan == sec_chan)) { 701 sec_ok = 1; 702 break; 703 } 704 } 705 if (!sec_ok) { 706 hostapd_logger(iface->bss[0], NULL, 707 HOSTAPD_MODULE_IEEE80211, 708 HOSTAPD_LEVEL_WARNING, 709 "Configured HT40 secondary channel " 710 "(%d) not found from the channel list " 711 "of current mode (%d) %s", 712 sec_chan, iface->current_mode->mode, 713 hostapd_hw_mode_txt( 714 iface->current_mode->mode)); 715 ok = 0; 716 } 717 } 718 if (iface->conf->channel == 0) { 719 /* TODO: could request a scan of neighboring BSSes and select 720 * the channel automatically */ 721 wpa_printf(MSG_ERROR, "Channel not configured " 722 "(hw_mode/channel in hostapd.conf)"); 723 return -3; 724 } 725 if (ok == 0 && iface->conf->channel != 0) { 726 hostapd_logger(iface->bss[0], NULL, 727 HOSTAPD_MODULE_IEEE80211, 728 HOSTAPD_LEVEL_WARNING, 729 "Configured channel (%d) not found from the " 730 "channel list of current mode (%d) %s", 731 iface->conf->channel, 732 iface->current_mode->mode, 733 hostapd_hw_mode_txt(iface->current_mode->mode)); 734 iface->current_mode = NULL; 735 } 736 737 if (iface->current_mode == NULL) { 738 hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 739 HOSTAPD_LEVEL_WARNING, 740 "Hardware does not support configured channel"); 741 return -4; 742 } 743 744 return 0; 745} 746 747 748const char * hostapd_hw_mode_txt(int mode) 749{ 750 switch (mode) { 751 case HOSTAPD_MODE_IEEE80211A: 752 return "IEEE 802.11a"; 753 case HOSTAPD_MODE_IEEE80211B: 754 return "IEEE 802.11b"; 755 case HOSTAPD_MODE_IEEE80211G: 756 return "IEEE 802.11g"; 757 default: 758 return "UNKNOWN"; 759 } 760} 761 762 763int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) 764{ 765 int i; 766 767 if (!hapd->iface->current_mode) 768 return 0; 769 770 for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { 771 struct hostapd_channel_data *ch = 772 &hapd->iface->current_mode->channels[i]; 773 if (ch->chan == chan) 774 return ch->freq; 775 } 776 777 return 0; 778} 779 780 781int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) 782{ 783 int i; 784 785 if (!hapd->iface->current_mode) 786 return 0; 787 788 for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { 789 struct hostapd_channel_data *ch = 790 &hapd->iface->current_mode->channels[i]; 791 if (ch->freq == freq) 792 return ch->chan; 793 } 794 795 return 0; 796} 797