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