xref: /netbsd/external/bsd/wpa/dist/src/ap/hw_features.c (revision 6550d01e)
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-2009, 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 
30 void 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 
47 int 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 
104 static int hostapd_prepare_rates(struct hostapd_data *hapd,
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 (hapd->iconf->basic_rates)
114 		basic_rates = hapd->iconf->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 	if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates,
130 				  basic_rates, mode->mode)) {
131 		wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel "
132 			   "module");
133 	}
134 
135 	os_free(hapd->iface->current_rates);
136 	hapd->iface->num_rates = 0;
137 
138 	hapd->iface->current_rates =
139 		os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data));
140 	if (!hapd->iface->current_rates) {
141 		wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
142 			   "table.");
143 		return -1;
144 	}
145 
146 	for (i = 0; i < mode->num_rates; i++) {
147 		struct hostapd_rate_data *rate;
148 
149 		if (hapd->iconf->supported_rates &&
150 		    !hostapd_rate_found(hapd->iconf->supported_rates,
151 					mode->rates[i]))
152 			continue;
153 
154 		rate = &hapd->iface->current_rates[hapd->iface->num_rates];
155 		rate->rate = mode->rates[i];
156 		if (hostapd_rate_found(basic_rates, rate->rate)) {
157 			rate->flags |= HOSTAPD_RATE_BASIC;
158 			num_basic_rates++;
159 		}
160 		wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
161 			   hapd->iface->num_rates, rate->rate, rate->flags);
162 		hapd->iface->num_rates++;
163 	}
164 
165 	if (hapd->iface->num_rates == 0 || num_basic_rates == 0) {
166 		wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
167 			   "rate sets (%d,%d).",
168 			   hapd->iface->num_rates, num_basic_rates);
169 		return -1;
170 	}
171 
172 	return 0;
173 }
174 
175 
176 #ifdef CONFIG_IEEE80211N
177 static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
178 {
179 	int sec_chan, ok, j, first;
180 	int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
181 			  184, 192 };
182 	size_t k;
183 
184 	if (!iface->conf->secondary_channel)
185 		return 1; /* HT40 not used */
186 
187 	sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4;
188 	wpa_printf(MSG_DEBUG, "HT40: control channel: %d  "
189 		   "secondary channel: %d",
190 		   iface->conf->channel, sec_chan);
191 
192 	/* Verify that HT40 secondary channel is an allowed 20 MHz
193 	 * channel */
194 	ok = 0;
195 	for (j = 0; j < iface->current_mode->num_channels; j++) {
196 		struct hostapd_channel_data *chan =
197 			&iface->current_mode->channels[j];
198 		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
199 		    chan->chan == sec_chan) {
200 			ok = 1;
201 			break;
202 		}
203 	}
204 	if (!ok) {
205 		wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
206 			   sec_chan);
207 		return 0;
208 	}
209 
210 	/*
211 	 * Verify that HT40 primary,secondary channel pair is allowed per
212 	 * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
213 	 * 2.4 GHz rules allow all cases where the secondary channel fits into
214 	 * the list of allowed channels (already checked above).
215 	 */
216 	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
217 		return 1;
218 
219 	if (iface->conf->secondary_channel > 0)
220 		first = iface->conf->channel;
221 	else
222 		first = sec_chan;
223 
224 	ok = 0;
225 	for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) {
226 		if (first == allowed[k]) {
227 			ok = 1;
228 			break;
229 		}
230 	}
231 	if (!ok) {
232 		wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
233 			   iface->conf->channel,
234 			   iface->conf->secondary_channel);
235 		return 0;
236 	}
237 
238 	return 1;
239 }
240 
241 
242 static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
243 {
244 	if (iface->conf->secondary_channel > 0) {
245 		iface->conf->channel += 4;
246 		iface->conf->secondary_channel = -1;
247 	} else {
248 		iface->conf->channel -= 4;
249 		iface->conf->secondary_channel = 1;
250 	}
251 }
252 
253 
254 static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
255 					int *pri_chan, int *sec_chan)
256 {
257 	struct ieee80211_ht_operation *oper;
258 	struct ieee802_11_elems elems;
259 
260 	*pri_chan = *sec_chan = 0;
261 
262 	ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
263 	if (elems.ht_operation &&
264 	    elems.ht_operation_len >= sizeof(*oper)) {
265 		oper = (struct ieee80211_ht_operation *) elems.ht_operation;
266 		*pri_chan = oper->control_chan;
267 		if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) {
268 			if (oper->ht_param &
269 			    HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
270 				*sec_chan = *pri_chan + 4;
271 			else if (oper->ht_param &
272 				 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
273 				*sec_chan = *pri_chan - 4;
274 		}
275 	}
276 }
277 
278 
279 static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
280 				     struct wpa_scan_results *scan_res)
281 {
282 	int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss;
283 	int bss_pri_chan, bss_sec_chan;
284 	size_t i;
285 	int match;
286 
287 	pri_chan = iface->conf->channel;
288 	sec_chan = iface->conf->secondary_channel * 4;
289 	pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
290 	if (iface->conf->secondary_channel > 0)
291 		sec_freq = pri_freq + 20;
292 	else
293 		sec_freq = pri_freq - 20;
294 
295 	/*
296 	 * Switch PRI/SEC channels if Beacons were detected on selected SEC
297 	 * channel, but not on selected PRI channel.
298 	 */
299 	pri_bss = sec_bss = 0;
300 	for (i = 0; i < scan_res->num; i++) {
301 		struct wpa_scan_res *bss = scan_res->res[i];
302 		if (bss->freq == pri_freq)
303 			pri_bss++;
304 		else if (bss->freq == sec_freq)
305 			sec_bss++;
306 	}
307 	if (sec_bss && !pri_bss) {
308 		wpa_printf(MSG_INFO, "Switch own primary and secondary "
309 			   "channel to get secondary channel with no Beacons "
310 			   "from other BSSes");
311 		ieee80211n_switch_pri_sec(iface);
312 	}
313 
314 	/*
315 	 * Match PRI/SEC channel with any existing HT40 BSS on the same
316 	 * channels that we are about to use (if already mixed order in
317 	 * existing BSSes, use own preference).
318 	 */
319 	match = 0;
320 	for (i = 0; i < scan_res->num; i++) {
321 		struct wpa_scan_res *bss = scan_res->res[i];
322 		ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
323 		if (pri_chan == bss_pri_chan &&
324 		    sec_chan == bss_sec_chan) {
325 			match = 1;
326 			break;
327 		}
328 	}
329 	if (!match) {
330 		for (i = 0; i < scan_res->num; i++) {
331 			struct wpa_scan_res *bss = scan_res->res[i];
332 			ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan,
333 						    &bss_sec_chan);
334 			if (pri_chan == bss_sec_chan &&
335 			    sec_chan == bss_pri_chan) {
336 				wpa_printf(MSG_INFO, "Switch own primary and "
337 					   "secondary channel due to BSS "
338 					   "overlap with " MACSTR,
339 					   MAC2STR(bss->bssid));
340 				ieee80211n_switch_pri_sec(iface);
341 				break;
342 			}
343 		}
344 	}
345 
346 	return 1;
347 }
348 
349 
350 static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
351 				      struct wpa_scan_results *scan_res)
352 {
353 	int pri_freq, sec_freq;
354 	int affected_start, affected_end;
355 	size_t i;
356 
357 	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
358 	if (iface->conf->secondary_channel > 0)
359 		sec_freq = pri_freq + 20;
360 	else
361 		sec_freq = pri_freq - 20;
362 	affected_start = (pri_freq + sec_freq) / 2 - 25;
363 	affected_end = (pri_freq + sec_freq) / 2 + 25;
364 	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
365 		   affected_start, affected_end);
366 	for (i = 0; i < scan_res->num; i++) {
367 		struct wpa_scan_res *bss = scan_res->res[i];
368 		int pri = bss->freq;
369 		int sec = pri;
370 		int sec_chan, pri_chan;
371 
372 		ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
373 
374 		if (sec_chan) {
375 			if (sec_chan < pri_chan)
376 				sec = pri - 20;
377 			else
378 				sec = pri + 20;
379 		}
380 
381 		if ((pri < affected_start || pri > affected_end) &&
382 		    (sec < affected_start || sec > affected_end))
383 			continue; /* not within affected channel range */
384 
385 		wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
386 			   " freq=%d pri=%d sec=%d",
387 			   MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
388 
389 		if (sec_chan) {
390 			if (pri_freq != pri || sec_freq != sec) {
391 				wpa_printf(MSG_DEBUG, "40 MHz pri/sec "
392 					   "mismatch with BSS " MACSTR
393 					   " <%d,%d> (chan=%d%c) vs. <%d,%d>",
394 					   MAC2STR(bss->bssid),
395 					   pri, sec, pri_chan,
396 					   sec > pri ? '+' : '-',
397 					   pri_freq, sec_freq);
398 				return 0;
399 			}
400 		}
401 
402 		/* TODO: 40 MHz intolerant */
403 	}
404 
405 	return 1;
406 }
407 
408 
409 static void wpa_scan_results_free(struct wpa_scan_results *res)
410 {
411 	size_t i;
412 
413 	if (res == NULL)
414 		return;
415 
416 	for (i = 0; i < res->num; i++)
417 		os_free(res->res[i]);
418 	os_free(res->res);
419 	os_free(res);
420 }
421 
422 
423 static void ieee80211n_check_scan(struct hostapd_iface *iface)
424 {
425 	struct wpa_scan_results *scan_res;
426 	int oper40;
427 
428 	/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
429 	 * allowed per IEEE 802.11n/D7.0, 11.14.3.2 */
430 
431 	iface->scan_cb = NULL;
432 
433 	scan_res = hostapd_driver_get_scan_results(iface->bss[0]);
434 	if (scan_res == NULL) {
435 		hostapd_setup_interface_complete(iface, 1);
436 		return;
437 	}
438 
439 	if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A)
440 		oper40 = ieee80211n_check_40mhz_5g(iface, scan_res);
441 	else
442 		oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
443 	wpa_scan_results_free(scan_res);
444 
445 	if (!oper40) {
446 		wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
447 			   "channel pri=%d sec=%d based on overlapping BSSes",
448 			   iface->conf->channel,
449 			   iface->conf->channel +
450 			   iface->conf->secondary_channel * 4);
451 		iface->conf->secondary_channel = 0;
452 		iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
453 	}
454 
455 	hostapd_setup_interface_complete(iface, 0);
456 }
457 
458 
459 static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
460 {
461 	struct wpa_driver_scan_params params;
462 
463 	if (!iface->conf->secondary_channel)
464 		return 0; /* HT40 not used */
465 
466 	wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
467 		   "40 MHz channel");
468 	os_memset(&params, 0, sizeof(params));
469 	/* TODO: scan only the needed frequency */
470 	if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
471 		wpa_printf(MSG_ERROR, "Failed to request a scan of "
472 			   "neighboring BSSes");
473 		return -1;
474 	}
475 
476 	iface->scan_cb = ieee80211n_check_scan;
477 	return 1;
478 }
479 
480 
481 static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
482 {
483 	u16 hw = iface->current_mode->ht_capab;
484 	u16 conf = iface->conf->ht_capab;
485 
486 	if (!iface->conf->ieee80211n)
487 		return 1;
488 
489 	if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) &&
490 	    !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) {
491 		wpa_printf(MSG_ERROR, "Driver does not support configured "
492 			   "HT capability [LDPC]");
493 		return 0;
494 	}
495 
496 	if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
497 	    !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
498 		wpa_printf(MSG_ERROR, "Driver does not support configured "
499 			   "HT capability [HT40*]");
500 		return 0;
501 	}
502 
503 	if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
504 	    (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
505 		wpa_printf(MSG_ERROR, "Driver does not support configured "
506 			   "HT capability [SMPS-*]");
507 		return 0;
508 	}
509 
510 	if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
511 	    !(hw & HT_CAP_INFO_GREEN_FIELD)) {
512 		wpa_printf(MSG_ERROR, "Driver does not support configured "
513 			   "HT capability [GF]");
514 		return 0;
515 	}
516 
517 	if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) &&
518 	    !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) {
519 		wpa_printf(MSG_ERROR, "Driver does not support configured "
520 			   "HT capability [SHORT-GI-20]");
521 		return 0;
522 	}
523 
524 	if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) &&
525 	    !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) {
526 		wpa_printf(MSG_ERROR, "Driver does not support configured "
527 			   "HT capability [SHORT-GI-40]");
528 		return 0;
529 	}
530 
531 	if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) {
532 		wpa_printf(MSG_ERROR, "Driver does not support configured "
533 			   "HT capability [TX-STBC]");
534 		return 0;
535 	}
536 
537 	if ((conf & HT_CAP_INFO_RX_STBC_MASK) >
538 	    (hw & HT_CAP_INFO_RX_STBC_MASK)) {
539 		wpa_printf(MSG_ERROR, "Driver does not support configured "
540 			   "HT capability [RX-STBC*]");
541 		return 0;
542 	}
543 
544 	if ((conf & HT_CAP_INFO_DELAYED_BA) &&
545 	    !(hw & HT_CAP_INFO_DELAYED_BA)) {
546 		wpa_printf(MSG_ERROR, "Driver does not support configured "
547 			   "HT capability [DELAYED-BA]");
548 		return 0;
549 	}
550 
551 	if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) &&
552 	    !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) {
553 		wpa_printf(MSG_ERROR, "Driver does not support configured "
554 			   "HT capability [MAX-AMSDU-7935]");
555 		return 0;
556 	}
557 
558 	if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) &&
559 	    !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) {
560 		wpa_printf(MSG_ERROR, "Driver does not support configured "
561 			   "HT capability [DSSS_CCK-40]");
562 		return 0;
563 	}
564 
565 	if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) {
566 		wpa_printf(MSG_ERROR, "Driver does not support configured "
567 			   "HT capability [PSMP]");
568 		return 0;
569 	}
570 
571 	if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) &&
572 	    !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) {
573 		wpa_printf(MSG_ERROR, "Driver does not support configured "
574 			   "HT capability [LSIG-TXOP-PROT]");
575 		return 0;
576 	}
577 
578 	return 1;
579 }
580 
581 #endif /* CONFIG_IEEE80211N */
582 
583 
584 int hostapd_check_ht_capab(struct hostapd_iface *iface)
585 {
586 #ifdef CONFIG_IEEE80211N
587 	int ret;
588 	ret = ieee80211n_check_40mhz(iface);
589 	if (ret)
590 		return ret;
591 	if (!ieee80211n_allowed_ht40_channel_pair(iface))
592 		return -1;
593 	if (!ieee80211n_supported_ht_capab(iface))
594 		return -1;
595 #endif /* CONFIG_IEEE80211N */
596 
597 	return 0;
598 }
599 
600 
601 /**
602  * hostapd_select_hw_mode - Select the hardware mode
603  * @iface: Pointer to interface data.
604  * Returns: 0 on success, -1 on failure
605  *
606  * Sets up the hardware mode, channel, rates, and passive scanning
607  * based on the configuration.
608  */
609 int hostapd_select_hw_mode(struct hostapd_iface *iface)
610 {
611 	int i, j, ok;
612 
613 	if (iface->num_hw_features < 1)
614 		return -1;
615 
616 	iface->current_mode = NULL;
617 	for (i = 0; i < iface->num_hw_features; i++) {
618 		struct hostapd_hw_modes *mode = &iface->hw_features[i];
619 		if (mode->mode == iface->conf->hw_mode) {
620 			iface->current_mode = mode;
621 			break;
622 		}
623 	}
624 
625 	if (iface->current_mode == NULL) {
626 		wpa_printf(MSG_ERROR, "Hardware does not support configured "
627 			   "mode");
628 		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
629 			       HOSTAPD_LEVEL_WARNING,
630 			       "Hardware does not support configured mode "
631 			       "(%d)", (int) iface->conf->hw_mode);
632 		return -1;
633 	}
634 
635 	ok = 0;
636 	for (j = 0; j < iface->current_mode->num_channels; j++) {
637 		struct hostapd_channel_data *chan =
638 			&iface->current_mode->channels[j];
639 		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
640 		    (chan->chan == iface->conf->channel)) {
641 			ok = 1;
642 			break;
643 		}
644 	}
645 	if (iface->conf->channel == 0) {
646 		/* TODO: could request a scan of neighboring BSSes and select
647 		 * the channel automatically */
648 		wpa_printf(MSG_ERROR, "Channel not configured "
649 			   "(hw_mode/channel in hostapd.conf)");
650 		return -1;
651 	}
652 	if (ok == 0 && iface->conf->channel != 0) {
653 		hostapd_logger(iface->bss[0], NULL,
654 			       HOSTAPD_MODULE_IEEE80211,
655 			       HOSTAPD_LEVEL_WARNING,
656 			       "Configured channel (%d) not found from the "
657 			       "channel list of current mode (%d) %s",
658 			       iface->conf->channel,
659 			       iface->current_mode->mode,
660 			       hostapd_hw_mode_txt(iface->current_mode->mode));
661 		iface->current_mode = NULL;
662 	}
663 
664 	if (iface->current_mode == NULL) {
665 		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
666 			       HOSTAPD_LEVEL_WARNING,
667 			       "Hardware does not support configured channel");
668 		return -1;
669 	}
670 
671 	if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) {
672 		wpa_printf(MSG_ERROR, "Failed to prepare rates table.");
673 		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
674 					   HOSTAPD_LEVEL_WARNING,
675 					   "Failed to prepare rates table.");
676 		return -1;
677 	}
678 
679 	return 0;
680 }
681 
682 
683 const char * hostapd_hw_mode_txt(int mode)
684 {
685 	switch (mode) {
686 	case HOSTAPD_MODE_IEEE80211A:
687 		return "IEEE 802.11a";
688 	case HOSTAPD_MODE_IEEE80211B:
689 		return "IEEE 802.11b";
690 	case HOSTAPD_MODE_IEEE80211G:
691 		return "IEEE 802.11g";
692 	default:
693 		return "UNKNOWN";
694 	}
695 }
696 
697 
698 int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
699 {
700 	int i;
701 
702 	if (!hapd->iface->current_mode)
703 		return 0;
704 
705 	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
706 		struct hostapd_channel_data *ch =
707 			&hapd->iface->current_mode->channels[i];
708 		if (ch->chan == chan)
709 			return ch->freq;
710 	}
711 
712 	return 0;
713 }
714 
715 
716 int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
717 {
718 	int i;
719 
720 	if (!hapd->iface->current_mode)
721 		return 0;
722 
723 	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
724 		struct hostapd_channel_data *ch =
725 			&hapd->iface->current_mode->channels[i];
726 		if (ch->freq == freq)
727 			return ch->chan;
728 	}
729 
730 	return 0;
731 }
732