00001
00018 #include "includes.h"
00019
00020 #include "hostapd.h"
00021 #include "ieee802_11_defs.h"
00022 #include "ieee802_11_common.h"
00023 #include "eloop.h"
00024 #include "hw_features.h"
00025 #include "driver_i.h"
00026 #include "config.h"
00027
00028
00029 void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
00030 size_t num_hw_features)
00031 {
00032 size_t i;
00033
00034 if (hw_features == NULL)
00035 return;
00036
00037 for (i = 0; i < num_hw_features; i++) {
00038 os_free(hw_features[i].channels);
00039 os_free(hw_features[i].rates);
00040 }
00041
00042 os_free(hw_features);
00043 }
00044
00045
00046 int hostapd_get_hw_features(struct hostapd_iface *iface)
00047 {
00048 struct hostapd_data *hapd = iface->bss[0];
00049 int ret = 0, i, j;
00050 u16 num_modes, flags;
00051 struct hostapd_hw_modes *modes;
00052
00053 if (hostapd_drv_none(hapd))
00054 return -1;
00055 modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
00056 if (modes == NULL) {
00057 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
00058 HOSTAPD_LEVEL_DEBUG,
00059 "Fetching hardware channel/rate support not "
00060 "supported.");
00061 return -1;
00062 }
00063
00064 iface->hw_flags = flags;
00065
00066 hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
00067 iface->hw_features = modes;
00068 iface->num_hw_features = num_modes;
00069
00070 for (i = 0; i < num_modes; i++) {
00071 struct hostapd_hw_modes *feature = &modes[i];
00072
00073
00074 for (j = 0; j < feature->num_channels; j++) {
00075
00076
00077
00078
00079
00080
00081
00082 if (feature->channels[j].flag &
00083 (HOSTAPD_CHAN_NO_IBSS |
00084 HOSTAPD_CHAN_PASSIVE_SCAN |
00085 HOSTAPD_CHAN_RADAR))
00086 feature->channels[j].flag |=
00087 HOSTAPD_CHAN_DISABLED;
00088 if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
00089 continue;
00090 wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
00091 "chan=%d freq=%d MHz max_tx_power=%d dBm",
00092 feature->mode,
00093 feature->channels[j].chan,
00094 feature->channels[j].freq,
00095 feature->channels[j].max_tx_power);
00096 }
00097 }
00098
00099 return ret;
00100 }
00101
00102
00103 static int hostapd_prepare_rates(struct hostapd_data *hapd,
00104 struct hostapd_hw_modes *mode)
00105 {
00106 int i, num_basic_rates = 0;
00107 int basic_rates_a[] = { 60, 120, 240, -1 };
00108 int basic_rates_b[] = { 10, 20, -1 };
00109 int basic_rates_g[] = { 10, 20, 55, 110, -1 };
00110 int *basic_rates;
00111
00112 if (hapd->iconf->basic_rates)
00113 basic_rates = hapd->iconf->basic_rates;
00114 else switch (mode->mode) {
00115 case HOSTAPD_MODE_IEEE80211A:
00116 basic_rates = basic_rates_a;
00117 break;
00118 case HOSTAPD_MODE_IEEE80211B:
00119 basic_rates = basic_rates_b;
00120 break;
00121 case HOSTAPD_MODE_IEEE80211G:
00122 basic_rates = basic_rates_g;
00123 break;
00124 default:
00125 return -1;
00126 }
00127
00128 if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates,
00129 basic_rates, mode->mode)) {
00130 wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel "
00131 "module");
00132 }
00133
00134 os_free(hapd->iface->current_rates);
00135 hapd->iface->num_rates = 0;
00136
00137 hapd->iface->current_rates =
00138 os_malloc(mode->num_rates * sizeof(struct hostapd_rate_data));
00139 if (!hapd->iface->current_rates) {
00140 wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
00141 "table.");
00142 return -1;
00143 }
00144
00145 for (i = 0; i < mode->num_rates; i++) {
00146 struct hostapd_rate_data *rate;
00147
00148 if (hapd->iconf->supported_rates &&
00149 !hostapd_rate_found(hapd->iconf->supported_rates,
00150 mode->rates[i].rate))
00151 continue;
00152
00153 rate = &hapd->iface->current_rates[hapd->iface->num_rates];
00154 os_memcpy(rate, &mode->rates[i],
00155 sizeof(struct hostapd_rate_data));
00156 if (hostapd_rate_found(basic_rates, rate->rate)) {
00157 rate->flags |= HOSTAPD_RATE_BASIC;
00158 num_basic_rates++;
00159 } else
00160 rate->flags &= ~HOSTAPD_RATE_BASIC;
00161 wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
00162 hapd->iface->num_rates, rate->rate, rate->flags);
00163 hapd->iface->num_rates++;
00164 }
00165
00166 if (hapd->iface->num_rates == 0 || num_basic_rates == 0) {
00167 wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
00168 "rate sets (%d,%d).",
00169 hapd->iface->num_rates, num_basic_rates);
00170 return -1;
00171 }
00172
00173 return 0;
00174 }
00175
00176
00177 #ifdef CONFIG_IEEE80211N
00178 static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
00179 {
00180 int sec_chan, ok, j, first;
00181 int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
00182 184, 192 };
00183 size_t k;
00184
00185 if (!iface->conf->secondary_channel)
00186 return 1;
00187
00188 sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4;
00189 wpa_printf(MSG_DEBUG, "HT40: control channel: %d "
00190 "secondary channel: %d",
00191 iface->conf->channel, sec_chan);
00192
00193
00194
00195 ok = 0;
00196 for (j = 0; j < iface->current_mode->num_channels; j++) {
00197 struct hostapd_channel_data *chan =
00198 &iface->current_mode->channels[j];
00199 if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
00200 chan->chan == sec_chan) {
00201 ok = 1;
00202 break;
00203 }
00204 }
00205 if (!ok) {
00206 wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
00207 sec_chan);
00208 return 0;
00209 }
00210
00211
00212
00213
00214
00215
00216
00217 if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
00218 return 1;
00219
00220 if (iface->conf->secondary_channel > 0)
00221 first = iface->conf->channel;
00222 else
00223 first = sec_chan;
00224
00225 ok = 0;
00226 for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) {
00227 if (first == allowed[k]) {
00228 ok = 1;
00229 break;
00230 }
00231 }
00232 if (!ok) {
00233 wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
00234 iface->conf->channel,
00235 iface->conf->secondary_channel);
00236 return 0;
00237 }
00238
00239 return 1;
00240 }
00241
00242
00243 static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
00244 {
00245 if (iface->conf->secondary_channel > 0) {
00246 iface->conf->channel += 4;
00247 iface->conf->secondary_channel = -1;
00248 } else {
00249 iface->conf->channel -= 4;
00250 iface->conf->secondary_channel = 1;
00251 }
00252 }
00253
00254
00255 static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
00256 int *pri_chan, int *sec_chan)
00257 {
00258 struct ieee80211_ht_operation *oper;
00259 struct ieee802_11_elems elems;
00260
00261 *pri_chan = *sec_chan = 0;
00262
00263 ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
00264 if (elems.ht_operation &&
00265 elems.ht_operation_len >= sizeof(*oper)) {
00266 oper = (struct ieee80211_ht_operation *) elems.ht_operation;
00267 *pri_chan = oper->control_chan;
00268 if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) {
00269 if (oper->ht_param &
00270 HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
00271 *sec_chan = *pri_chan + 4;
00272 else if (oper->ht_param &
00273 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
00274 *sec_chan = *pri_chan - 4;
00275 }
00276 }
00277 }
00278
00279
00280 static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
00281 struct wpa_scan_results *scan_res)
00282 {
00283 int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss;
00284 int bss_pri_chan, bss_sec_chan;
00285 size_t i;
00286 int match;
00287
00288 pri_chan = iface->conf->channel;
00289 sec_chan = iface->conf->secondary_channel * 4;
00290 pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
00291 if (iface->conf->secondary_channel > 0)
00292 sec_freq = pri_freq + 20;
00293 else
00294 sec_freq = pri_freq - 20;
00295
00296
00297
00298
00299
00300 pri_bss = sec_bss = 0;
00301 for (i = 0; i < scan_res->num; i++) {
00302 struct wpa_scan_res *bss = scan_res->res[i];
00303 if (bss->freq == pri_freq)
00304 pri_bss++;
00305 else if (bss->freq == sec_freq)
00306 sec_bss++;
00307 }
00308 if (sec_bss && !pri_bss) {
00309 wpa_printf(MSG_INFO, "Switch own primary and secondary "
00310 "channel to get secondary channel with no Beacons "
00311 "from other BSSes");
00312 ieee80211n_switch_pri_sec(iface);
00313 }
00314
00315
00316
00317
00318
00319
00320 match = 0;
00321 for (i = 0; i < scan_res->num; i++) {
00322 struct wpa_scan_res *bss = scan_res->res[i];
00323 ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
00324 if (pri_chan == bss_pri_chan &&
00325 sec_chan == bss_sec_chan) {
00326 match = 1;
00327 break;
00328 }
00329 }
00330 if (!match) {
00331 for (i = 0; i < scan_res->num; i++) {
00332 struct wpa_scan_res *bss = scan_res->res[i];
00333 ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan,
00334 &bss_sec_chan);
00335 if (pri_chan == bss_sec_chan &&
00336 sec_chan == bss_pri_chan) {
00337 wpa_printf(MSG_INFO, "Switch own primary and "
00338 "secondary channel due to BSS "
00339 "overlap with " MACSTR,
00340 MAC2STR(bss->bssid));
00341 ieee80211n_switch_pri_sec(iface);
00342 break;
00343 }
00344 }
00345 }
00346
00347 return 1;
00348 }
00349
00350
00351 static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
00352 struct wpa_scan_results *scan_res)
00353 {
00354 int pri_freq, sec_freq;
00355 int affected_start, affected_end;
00356 size_t i;
00357
00358 pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
00359 if (iface->conf->secondary_channel > 0)
00360 sec_freq = pri_freq + 20;
00361 else
00362 sec_freq = pri_freq - 20;
00363 affected_start = (pri_freq + sec_freq) / 2 - 25;
00364 affected_end = (pri_freq + sec_freq) / 2 + 25;
00365 wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
00366 affected_start, affected_end);
00367 for (i = 0; i < scan_res->num; i++) {
00368 struct wpa_scan_res *bss = scan_res->res[i];
00369 int pri = bss->freq;
00370 int sec = pri;
00371 int sec_chan, pri_chan;
00372
00373 ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
00374
00375 if (sec_chan) {
00376 if (sec_chan < pri_chan)
00377 sec = pri - 20;
00378 else
00379 sec = pri + 20;
00380 }
00381
00382 if ((pri < affected_start || pri > affected_end) &&
00383 (sec < affected_start || sec > affected_end))
00384 continue;
00385
00386 wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
00387 " freq=%d pri=%d sec=%d",
00388 MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
00389
00390 if (sec_chan) {
00391 if (pri_freq != pri || sec_freq != sec) {
00392 wpa_printf(MSG_DEBUG, "40 MHz pri/sec "
00393 "mismatch with BSS " MACSTR
00394 " <%d,%d> (chan=%d%c) vs. <%d,%d>",
00395 MAC2STR(bss->bssid),
00396 pri, sec, pri_chan,
00397 sec > pri ? '+' : '-',
00398 pri_freq, sec_freq);
00399 return 0;
00400 }
00401 }
00402
00403
00404 }
00405
00406 return 1;
00407 }
00408
00409
00410 static void ieee80211n_check_scan(struct hostapd_iface *iface)
00411 {
00412 struct wpa_scan_results *scan_res;
00413 int oper40;
00414
00415
00416
00417
00418 iface->scan_cb = NULL;
00419
00420 scan_res = hostapd_driver_get_scan_results(iface->bss[0]);
00421 if (scan_res == NULL) {
00422 hostapd_setup_interface_complete(iface, 1);
00423 return;
00424 }
00425
00426 if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A)
00427 oper40 = ieee80211n_check_40mhz_5g(iface, scan_res);
00428 else
00429 oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
00430 wpa_scan_results_free(scan_res);
00431
00432 if (!oper40) {
00433 wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
00434 "channel pri=%d sec=%d based on overlapping BSSes",
00435 iface->conf->channel,
00436 iface->conf->channel +
00437 iface->conf->secondary_channel * 4);
00438 iface->conf->secondary_channel = 0;
00439 iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
00440 }
00441
00442 hostapd_setup_interface_complete(iface, 0);
00443 }
00444
00445
00446 static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
00447 {
00448 struct wpa_driver_scan_params params;
00449
00450 if (!iface->conf->secondary_channel)
00451 return 0;
00452
00453 wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
00454 "40 MHz channel");
00455 os_memset(¶ms, 0, sizeof(params));
00456
00457 if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) {
00458 wpa_printf(MSG_ERROR, "Failed to request a scan of "
00459 "neighboring BSSes");
00460 return -1;
00461 }
00462
00463 iface->scan_cb = ieee80211n_check_scan;
00464 return 1;
00465 }
00466
00467
00468 static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
00469 {
00470 u16 hw = iface->current_mode->ht_capab;
00471 u16 conf = iface->conf->ht_capab;
00472
00473 if (!iface->conf->ieee80211n)
00474 return 1;
00475
00476 if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) &&
00477 !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) {
00478 wpa_printf(MSG_ERROR, "Driver does not support configured "
00479 "HT capability [LDPC]");
00480 return 0;
00481 }
00482
00483 if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
00484 !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
00485 wpa_printf(MSG_ERROR, "Driver does not support configured "
00486 "HT capability [HT40*]");
00487 return 0;
00488 }
00489
00490 if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
00491 (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
00492 wpa_printf(MSG_ERROR, "Driver does not support configured "
00493 "HT capability [SMPS-*]");
00494 return 0;
00495 }
00496
00497 if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
00498 !(hw & HT_CAP_INFO_GREEN_FIELD)) {
00499 wpa_printf(MSG_ERROR, "Driver does not support configured "
00500 "HT capability [GF]");
00501 return 0;
00502 }
00503
00504 if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) &&
00505 !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) {
00506 wpa_printf(MSG_ERROR, "Driver does not support configured "
00507 "HT capability [SHORT-GI-20]");
00508 return 0;
00509 }
00510
00511 if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) &&
00512 !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) {
00513 wpa_printf(MSG_ERROR, "Driver does not support configured "
00514 "HT capability [SHORT-GI-40]");
00515 return 0;
00516 }
00517
00518 if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) {
00519 wpa_printf(MSG_ERROR, "Driver does not support configured "
00520 "HT capability [TX-STBC]");
00521 return 0;
00522 }
00523
00524 if ((conf & HT_CAP_INFO_RX_STBC_MASK) >
00525 (hw & HT_CAP_INFO_RX_STBC_MASK)) {
00526 wpa_printf(MSG_ERROR, "Driver does not support configured "
00527 "HT capability [RX-STBC*]");
00528 return 0;
00529 }
00530
00531 if ((conf & HT_CAP_INFO_DELAYED_BA) &&
00532 !(hw & HT_CAP_INFO_DELAYED_BA)) {
00533 wpa_printf(MSG_ERROR, "Driver does not support configured "
00534 "HT capability [DELAYED-BA]");
00535 return 0;
00536 }
00537
00538 if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) &&
00539 !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) {
00540 wpa_printf(MSG_ERROR, "Driver does not support configured "
00541 "HT capability [MAX-AMSDU-7935]");
00542 return 0;
00543 }
00544
00545 if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) &&
00546 !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) {
00547 wpa_printf(MSG_ERROR, "Driver does not support configured "
00548 "HT capability [DSSS_CCK-40]");
00549 return 0;
00550 }
00551
00552 if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) {
00553 wpa_printf(MSG_ERROR, "Driver does not support configured "
00554 "HT capability [PSMP]");
00555 return 0;
00556 }
00557
00558 if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) &&
00559 !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) {
00560 wpa_printf(MSG_ERROR, "Driver does not support configured "
00561 "HT capability [LSIG-TXOP-PROT]");
00562 return 0;
00563 }
00564
00565 return 1;
00566 }
00567
00568 #endif
00569
00570
00571 int hostapd_check_ht_capab(struct hostapd_iface *iface)
00572 {
00573 #ifdef CONFIG_IEEE80211N
00574 int ret;
00575 ret = ieee80211n_check_40mhz(iface);
00576 if (ret)
00577 return ret;
00578 if (!ieee80211n_allowed_ht40_channel_pair(iface))
00579 return -1;
00580 if (!ieee80211n_supported_ht_capab(iface))
00581 return -1;
00582 #endif
00583
00584 return 0;
00585 }
00586
00587
00597 int hostapd_select_hw_mode(struct hostapd_iface *iface)
00598 {
00599 int i, j, ok;
00600
00601 if (iface->num_hw_features < 1)
00602 return -1;
00603
00604 iface->current_mode = NULL;
00605 for (i = 0; i < iface->num_hw_features; i++) {
00606 struct hostapd_hw_modes *mode = &iface->hw_features[i];
00607 if (mode->mode == iface->conf->hw_mode) {
00608 iface->current_mode = mode;
00609 break;
00610 }
00611 }
00612
00613 if (iface->current_mode == NULL) {
00614 wpa_printf(MSG_ERROR, "Hardware does not support configured "
00615 "mode");
00616 hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
00617 HOSTAPD_LEVEL_WARNING,
00618 "Hardware does not support configured mode "
00619 "(%d)", (int) iface->conf->hw_mode);
00620 return -1;
00621 }
00622
00623 ok = 0;
00624 for (j = 0; j < iface->current_mode->num_channels; j++) {
00625 struct hostapd_channel_data *chan =
00626 &iface->current_mode->channels[j];
00627 if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
00628 (chan->chan == iface->conf->channel)) {
00629 ok = 1;
00630 break;
00631 }
00632 }
00633 if (iface->conf->channel == 0) {
00634
00635
00636 wpa_printf(MSG_ERROR, "Channel not configured "
00637 "(hw_mode/channel in hostapd.conf)");
00638 return -1;
00639 }
00640 if (ok == 0 && iface->conf->channel != 0) {
00641 hostapd_logger(iface->bss[0], NULL,
00642 HOSTAPD_MODULE_IEEE80211,
00643 HOSTAPD_LEVEL_WARNING,
00644 "Configured channel (%d) not found from the "
00645 "channel list of current mode (%d) %s",
00646 iface->conf->channel,
00647 iface->current_mode->mode,
00648 hostapd_hw_mode_txt(iface->current_mode->mode));
00649 iface->current_mode = NULL;
00650 }
00651
00652 if (iface->current_mode == NULL) {
00653 hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
00654 HOSTAPD_LEVEL_WARNING,
00655 "Hardware does not support configured channel");
00656 return -1;
00657 }
00658
00659 if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) {
00660 wpa_printf(MSG_ERROR, "Failed to prepare rates table.");
00661 hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
00662 HOSTAPD_LEVEL_WARNING,
00663 "Failed to prepare rates table.");
00664 return -1;
00665 }
00666
00667 return 0;
00668 }
00669
00670
00671 const char * hostapd_hw_mode_txt(int mode)
00672 {
00673 switch (mode) {
00674 case HOSTAPD_MODE_IEEE80211A:
00675 return "IEEE 802.11a";
00676 case HOSTAPD_MODE_IEEE80211B:
00677 return "IEEE 802.11b";
00678 case HOSTAPD_MODE_IEEE80211G:
00679 return "IEEE 802.11g";
00680 default:
00681 return "UNKNOWN";
00682 }
00683 }
00684
00685
00686 int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
00687 {
00688 int i;
00689
00690 if (!hapd->iface->current_mode)
00691 return 0;
00692
00693 for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
00694 struct hostapd_channel_data *ch =
00695 &hapd->iface->current_mode->channels[i];
00696 if (ch->chan == chan)
00697 return ch->freq;
00698 }
00699
00700 return 0;
00701 }
00702
00703
00704 int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
00705 {
00706 int i;
00707
00708 if (!hapd->iface->current_mode)
00709 return 0;
00710
00711 for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
00712 struct hostapd_channel_data *ch =
00713 &hapd->iface->current_mode->channels[i];
00714 if (ch->freq == freq)
00715 return ch->chan;
00716 }
00717
00718 return 0;
00719 }
00720