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, Jouni Malinen <j@w1.fi>
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.
11 * Alternatively, this software may be distributed under the terms of BSD
14 * See README and COPYING for more details.
21 #include "common/ieee802_11_defs.h"
22 #include "common/ieee802_11_common.h"
24 #include "hw_features.h"
29 void hostapd_free_hw_features(struct hostapd_hw_modes
*hw_features
,
30 size_t num_hw_features
)
34 if (hw_features
== NULL
)
37 for (i
= 0; i
< num_hw_features
; i
++) {
38 os_free(hw_features
[i
].channels
);
39 os_free(hw_features
[i
].rates
);
46 int hostapd_get_hw_features(struct hostapd_iface
*iface
)
48 struct hostapd_data
*hapd
= iface
->bss
[0];
51 struct hostapd_hw_modes
*modes
;
53 if (hostapd_drv_none(hapd
))
55 modes
= hostapd_get_hw_feature_data(hapd
, &num_modes
, &flags
);
57 hostapd_logger(hapd
, NULL
, HOSTAPD_MODULE_IEEE80211
,
59 "Fetching hardware channel/rate support not "
64 iface
->hw_flags
= flags
;
66 hostapd_free_hw_features(iface
->hw_features
, iface
->num_hw_features
);
67 iface
->hw_features
= modes
;
68 iface
->num_hw_features
= num_modes
;
70 for (i
= 0; i
< num_modes
; i
++) {
71 struct hostapd_hw_modes
*feature
= &modes
[i
];
72 /* set flag for channels we can use in current regulatory
74 for (j
= 0; j
< feature
->num_channels
; j
++) {
76 * Disable all channels that are marked not to allow
77 * IBSS operation or active scanning. In addition,
78 * disable all channels that require radar detection,
79 * since that (in addition to full DFS) is not yet
82 if (feature
->channels
[j
].flag
&
83 (HOSTAPD_CHAN_NO_IBSS
|
84 HOSTAPD_CHAN_PASSIVE_SCAN
|
86 feature
->channels
[j
].flag
|=
87 HOSTAPD_CHAN_DISABLED
;
88 if (feature
->channels
[j
].flag
& HOSTAPD_CHAN_DISABLED
)
90 wpa_printf(MSG_MSGDUMP
, "Allowed channel: mode=%d "
91 "chan=%d freq=%d MHz max_tx_power=%d dBm",
93 feature
->channels
[j
].chan
,
94 feature
->channels
[j
].freq
,
95 feature
->channels
[j
].max_tx_power
);
103 static int hostapd_prepare_rates(struct hostapd_data
*hapd
,
104 struct hostapd_hw_modes
*mode
)
106 int i
, num_basic_rates
= 0;
107 int basic_rates_a
[] = { 60, 120, 240, -1 };
108 int basic_rates_b
[] = { 10, 20, -1 };
109 int basic_rates_g
[] = { 10, 20, 55, 110, -1 };
112 if (hapd
->iconf
->basic_rates
)
113 basic_rates
= hapd
->iconf
->basic_rates
;
114 else switch (mode
->mode
) {
115 case HOSTAPD_MODE_IEEE80211A
:
116 basic_rates
= basic_rates_a
;
118 case HOSTAPD_MODE_IEEE80211B
:
119 basic_rates
= basic_rates_b
;
121 case HOSTAPD_MODE_IEEE80211G
:
122 basic_rates
= basic_rates_g
;
128 if (hostapd_set_rate_sets(hapd
, hapd
->iconf
->supported_rates
,
129 basic_rates
, mode
->mode
)) {
130 wpa_printf(MSG_ERROR
, "Failed to update rate sets in kernel "
134 os_free(hapd
->iface
->current_rates
);
135 hapd
->iface
->num_rates
= 0;
137 hapd
->iface
->current_rates
=
138 os_zalloc(mode
->num_rates
* sizeof(struct hostapd_rate_data
));
139 if (!hapd
->iface
->current_rates
) {
140 wpa_printf(MSG_ERROR
, "Failed to allocate memory for rate "
145 for (i
= 0; i
< mode
->num_rates
; i
++) {
146 struct hostapd_rate_data
*rate
;
148 if (hapd
->iconf
->supported_rates
&&
149 !hostapd_rate_found(hapd
->iconf
->supported_rates
,
153 rate
= &hapd
->iface
->current_rates
[hapd
->iface
->num_rates
];
154 rate
->rate
= mode
->rates
[i
];
155 if (hostapd_rate_found(basic_rates
, rate
->rate
)) {
156 rate
->flags
|= HOSTAPD_RATE_BASIC
;
159 wpa_printf(MSG_DEBUG
, "RATE[%d] rate=%d flags=0x%x",
160 hapd
->iface
->num_rates
, rate
->rate
, rate
->flags
);
161 hapd
->iface
->num_rates
++;
164 if (hapd
->iface
->num_rates
== 0 || num_basic_rates
== 0) {
165 wpa_printf(MSG_ERROR
, "No rates remaining in supported/basic "
166 "rate sets (%d,%d).",
167 hapd
->iface
->num_rates
, num_basic_rates
);
175 #ifdef CONFIG_IEEE80211N
176 static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface
*iface
)
178 int sec_chan
, ok
, j
, first
;
179 int allowed
[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
183 if (!iface
->conf
->secondary_channel
)
184 return 1; /* HT40 not used */
186 sec_chan
= iface
->conf
->channel
+ iface
->conf
->secondary_channel
* 4;
187 wpa_printf(MSG_DEBUG
, "HT40: control channel: %d "
188 "secondary channel: %d",
189 iface
->conf
->channel
, sec_chan
);
191 /* Verify that HT40 secondary channel is an allowed 20 MHz
194 for (j
= 0; j
< iface
->current_mode
->num_channels
; j
++) {
195 struct hostapd_channel_data
*chan
=
196 &iface
->current_mode
->channels
[j
];
197 if (!(chan
->flag
& HOSTAPD_CHAN_DISABLED
) &&
198 chan
->chan
== sec_chan
) {
204 wpa_printf(MSG_ERROR
, "HT40 secondary channel %d not allowed",
210 * Verify that HT40 primary,secondary channel pair is allowed per
211 * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
212 * 2.4 GHz rules allow all cases where the secondary channel fits into
213 * the list of allowed channels (already checked above).
215 if (iface
->current_mode
->mode
!= HOSTAPD_MODE_IEEE80211A
)
218 if (iface
->conf
->secondary_channel
> 0)
219 first
= iface
->conf
->channel
;
224 for (k
= 0; k
< sizeof(allowed
) / sizeof(allowed
[0]); k
++) {
225 if (first
== allowed
[k
]) {
231 wpa_printf(MSG_ERROR
, "HT40 channel pair (%d, %d) not allowed",
232 iface
->conf
->channel
,
233 iface
->conf
->secondary_channel
);
241 static void ieee80211n_switch_pri_sec(struct hostapd_iface
*iface
)
243 if (iface
->conf
->secondary_channel
> 0) {
244 iface
->conf
->channel
+= 4;
245 iface
->conf
->secondary_channel
= -1;
247 iface
->conf
->channel
-= 4;
248 iface
->conf
->secondary_channel
= 1;
253 static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res
*bss
,
254 int *pri_chan
, int *sec_chan
)
256 struct ieee80211_ht_operation
*oper
;
257 struct ieee802_11_elems elems
;
259 *pri_chan
= *sec_chan
= 0;
261 ieee802_11_parse_elems((u8
*) (bss
+ 1), bss
->ie_len
, &elems
, 0);
262 if (elems
.ht_operation
&&
263 elems
.ht_operation_len
>= sizeof(*oper
)) {
264 oper
= (struct ieee80211_ht_operation
*) elems
.ht_operation
;
265 *pri_chan
= oper
->control_chan
;
266 if (oper
->ht_param
& HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH
) {
268 HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE
)
269 *sec_chan
= *pri_chan
+ 4;
270 else if (oper
->ht_param
&
271 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW
)
272 *sec_chan
= *pri_chan
- 4;
278 static int ieee80211n_check_40mhz_5g(struct hostapd_iface
*iface
,
279 struct wpa_scan_results
*scan_res
)
281 int pri_chan
, sec_chan
, pri_freq
, sec_freq
, pri_bss
, sec_bss
;
282 int bss_pri_chan
, bss_sec_chan
;
286 pri_chan
= iface
->conf
->channel
;
287 sec_chan
= iface
->conf
->secondary_channel
* 4;
288 pri_freq
= hostapd_hw_get_freq(iface
->bss
[0], pri_chan
);
289 if (iface
->conf
->secondary_channel
> 0)
290 sec_freq
= pri_freq
+ 20;
292 sec_freq
= pri_freq
- 20;
295 * Switch PRI/SEC channels if Beacons were detected on selected SEC
296 * channel, but not on selected PRI channel.
298 pri_bss
= sec_bss
= 0;
299 for (i
= 0; i
< scan_res
->num
; i
++) {
300 struct wpa_scan_res
*bss
= scan_res
->res
[i
];
301 if (bss
->freq
== pri_freq
)
303 else if (bss
->freq
== sec_freq
)
306 if (sec_bss
&& !pri_bss
) {
307 wpa_printf(MSG_INFO
, "Switch own primary and secondary "
308 "channel to get secondary channel with no Beacons "
310 ieee80211n_switch_pri_sec(iface
);
314 * Match PRI/SEC channel with any existing HT40 BSS on the same
315 * channels that we are about to use (if already mixed order in
316 * existing BSSes, use own preference).
319 for (i
= 0; i
< scan_res
->num
; i
++) {
320 struct wpa_scan_res
*bss
= scan_res
->res
[i
];
321 ieee80211n_get_pri_sec_chan(bss
, &bss_pri_chan
, &bss_sec_chan
);
322 if (pri_chan
== bss_pri_chan
&&
323 sec_chan
== bss_sec_chan
) {
329 for (i
= 0; i
< scan_res
->num
; i
++) {
330 struct wpa_scan_res
*bss
= scan_res
->res
[i
];
331 ieee80211n_get_pri_sec_chan(bss
, &bss_pri_chan
,
333 if (pri_chan
== bss_sec_chan
&&
334 sec_chan
== bss_pri_chan
) {
335 wpa_printf(MSG_INFO
, "Switch own primary and "
336 "secondary channel due to BSS "
337 "overlap with " MACSTR
,
338 MAC2STR(bss
->bssid
));
339 ieee80211n_switch_pri_sec(iface
);
349 static int ieee80211n_check_40mhz_2g4(struct hostapd_iface
*iface
,
350 struct wpa_scan_results
*scan_res
)
352 int pri_freq
, sec_freq
;
353 int affected_start
, affected_end
;
356 pri_freq
= hostapd_hw_get_freq(iface
->bss
[0], iface
->conf
->channel
);
357 if (iface
->conf
->secondary_channel
> 0)
358 sec_freq
= pri_freq
+ 20;
360 sec_freq
= pri_freq
- 20;
361 affected_start
= (pri_freq
+ sec_freq
) / 2 - 25;
362 affected_end
= (pri_freq
+ sec_freq
) / 2 + 25;
363 wpa_printf(MSG_DEBUG
, "40 MHz affected channel range: [%d,%d] MHz",
364 affected_start
, affected_end
);
365 for (i
= 0; i
< scan_res
->num
; i
++) {
366 struct wpa_scan_res
*bss
= scan_res
->res
[i
];
369 int sec_chan
, pri_chan
;
371 ieee80211n_get_pri_sec_chan(bss
, &pri_chan
, &sec_chan
);
374 if (sec_chan
< pri_chan
)
380 if ((pri
< affected_start
|| pri
> affected_end
) &&
381 (sec
< affected_start
|| sec
> affected_end
))
382 continue; /* not within affected channel range */
384 wpa_printf(MSG_DEBUG
, "Neighboring BSS: " MACSTR
385 " freq=%d pri=%d sec=%d",
386 MAC2STR(bss
->bssid
), bss
->freq
, pri_chan
, sec_chan
);
389 if (pri_freq
!= pri
|| sec_freq
!= sec
) {
390 wpa_printf(MSG_DEBUG
, "40 MHz pri/sec "
391 "mismatch with BSS " MACSTR
392 " <%d,%d> (chan=%d%c) vs. <%d,%d>",
395 sec
> pri
? '+' : '-',
401 /* TODO: 40 MHz intolerant */
408 static void ieee80211n_check_scan(struct hostapd_iface
*iface
)
410 struct wpa_scan_results
*scan_res
;
413 /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
414 * allowed per IEEE 802.11n/D7.0, 11.14.3.2 */
416 iface
->scan_cb
= NULL
;
418 scan_res
= hostapd_driver_get_scan_results(iface
->bss
[0]);
419 if (scan_res
== NULL
) {
420 hostapd_setup_interface_complete(iface
, 1);
424 if (iface
->current_mode
->mode
== HOSTAPD_MODE_IEEE80211A
)
425 oper40
= ieee80211n_check_40mhz_5g(iface
, scan_res
);
427 oper40
= ieee80211n_check_40mhz_2g4(iface
, scan_res
);
428 wpa_scan_results_free(scan_res
);
431 wpa_printf(MSG_INFO
, "20/40 MHz operation not permitted on "
432 "channel pri=%d sec=%d based on overlapping BSSes",
433 iface
->conf
->channel
,
434 iface
->conf
->channel
+
435 iface
->conf
->secondary_channel
* 4);
436 iface
->conf
->secondary_channel
= 0;
437 iface
->conf
->ht_capab
&= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET
;
440 hostapd_setup_interface_complete(iface
, 0);
444 static int ieee80211n_check_40mhz(struct hostapd_iface
*iface
)
446 struct wpa_driver_scan_params params
;
448 if (!iface
->conf
->secondary_channel
)
449 return 0; /* HT40 not used */
451 wpa_printf(MSG_DEBUG
, "Scan for neighboring BSSes prior to enabling "
453 os_memset(¶ms
, 0, sizeof(params
));
454 /* TODO: scan only the needed frequency */
455 if (hostapd_driver_scan(iface
->bss
[0], ¶ms
) < 0) {
456 wpa_printf(MSG_ERROR
, "Failed to request a scan of "
457 "neighboring BSSes");
461 iface
->scan_cb
= ieee80211n_check_scan
;
466 static int ieee80211n_supported_ht_capab(struct hostapd_iface
*iface
)
468 u16 hw
= iface
->current_mode
->ht_capab
;
469 u16 conf
= iface
->conf
->ht_capab
;
471 if (!iface
->conf
->ieee80211n
)
474 if ((conf
& HT_CAP_INFO_LDPC_CODING_CAP
) &&
475 !(hw
& HT_CAP_INFO_LDPC_CODING_CAP
)) {
476 wpa_printf(MSG_ERROR
, "Driver does not support configured "
477 "HT capability [LDPC]");
481 if ((conf
& HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET
) &&
482 !(hw
& HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET
)) {
483 wpa_printf(MSG_ERROR
, "Driver does not support configured "
484 "HT capability [HT40*]");
488 if ((conf
& HT_CAP_INFO_SMPS_MASK
) != (hw
& HT_CAP_INFO_SMPS_MASK
) &&
489 (conf
& HT_CAP_INFO_SMPS_MASK
) != HT_CAP_INFO_SMPS_DISABLED
) {
490 wpa_printf(MSG_ERROR
, "Driver does not support configured "
491 "HT capability [SMPS-*]");
495 if ((conf
& HT_CAP_INFO_GREEN_FIELD
) &&
496 !(hw
& HT_CAP_INFO_GREEN_FIELD
)) {
497 wpa_printf(MSG_ERROR
, "Driver does not support configured "
498 "HT capability [GF]");
502 if ((conf
& HT_CAP_INFO_SHORT_GI20MHZ
) &&
503 !(hw
& HT_CAP_INFO_SHORT_GI20MHZ
)) {
504 wpa_printf(MSG_ERROR
, "Driver does not support configured "
505 "HT capability [SHORT-GI-20]");
509 if ((conf
& HT_CAP_INFO_SHORT_GI40MHZ
) &&
510 !(hw
& HT_CAP_INFO_SHORT_GI40MHZ
)) {
511 wpa_printf(MSG_ERROR
, "Driver does not support configured "
512 "HT capability [SHORT-GI-40]");
516 if ((conf
& HT_CAP_INFO_TX_STBC
) && !(hw
& HT_CAP_INFO_TX_STBC
)) {
517 wpa_printf(MSG_ERROR
, "Driver does not support configured "
518 "HT capability [TX-STBC]");
522 if ((conf
& HT_CAP_INFO_RX_STBC_MASK
) >
523 (hw
& HT_CAP_INFO_RX_STBC_MASK
)) {
524 wpa_printf(MSG_ERROR
, "Driver does not support configured "
525 "HT capability [RX-STBC*]");
529 if ((conf
& HT_CAP_INFO_DELAYED_BA
) &&
530 !(hw
& HT_CAP_INFO_DELAYED_BA
)) {
531 wpa_printf(MSG_ERROR
, "Driver does not support configured "
532 "HT capability [DELAYED-BA]");
536 if ((conf
& HT_CAP_INFO_MAX_AMSDU_SIZE
) &&
537 !(hw
& HT_CAP_INFO_MAX_AMSDU_SIZE
)) {
538 wpa_printf(MSG_ERROR
, "Driver does not support configured "
539 "HT capability [MAX-AMSDU-7935]");
543 if ((conf
& HT_CAP_INFO_DSSS_CCK40MHZ
) &&
544 !(hw
& HT_CAP_INFO_DSSS_CCK40MHZ
)) {
545 wpa_printf(MSG_ERROR
, "Driver does not support configured "
546 "HT capability [DSSS_CCK-40]");
550 if ((conf
& HT_CAP_INFO_PSMP_SUPP
) && !(hw
& HT_CAP_INFO_PSMP_SUPP
)) {
551 wpa_printf(MSG_ERROR
, "Driver does not support configured "
552 "HT capability [PSMP]");
556 if ((conf
& HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT
) &&
557 !(hw
& HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT
)) {
558 wpa_printf(MSG_ERROR
, "Driver does not support configured "
559 "HT capability [LSIG-TXOP-PROT]");
566 #endif /* CONFIG_IEEE80211N */
569 int hostapd_check_ht_capab(struct hostapd_iface
*iface
)
571 #ifdef CONFIG_IEEE80211N
573 ret
= ieee80211n_check_40mhz(iface
);
576 if (!ieee80211n_allowed_ht40_channel_pair(iface
))
578 if (!ieee80211n_supported_ht_capab(iface
))
580 #endif /* CONFIG_IEEE80211N */
587 * hostapd_select_hw_mode - Select the hardware mode
588 * @iface: Pointer to interface data.
589 * Returns: 0 on success, -1 on failure
591 * Sets up the hardware mode, channel, rates, and passive scanning
592 * based on the configuration.
594 int hostapd_select_hw_mode(struct hostapd_iface
*iface
)
598 if (iface
->num_hw_features
< 1)
601 iface
->current_mode
= NULL
;
602 for (i
= 0; i
< iface
->num_hw_features
; i
++) {
603 struct hostapd_hw_modes
*mode
= &iface
->hw_features
[i
];
604 if (mode
->mode
== iface
->conf
->hw_mode
) {
605 iface
->current_mode
= mode
;
610 if (iface
->current_mode
== NULL
) {
611 wpa_printf(MSG_ERROR
, "Hardware does not support configured "
613 hostapd_logger(iface
->bss
[0], NULL
, HOSTAPD_MODULE_IEEE80211
,
614 HOSTAPD_LEVEL_WARNING
,
615 "Hardware does not support configured mode "
616 "(%d)", (int) iface
->conf
->hw_mode
);
621 for (j
= 0; j
< iface
->current_mode
->num_channels
; j
++) {
622 struct hostapd_channel_data
*chan
=
623 &iface
->current_mode
->channels
[j
];
624 if (!(chan
->flag
& HOSTAPD_CHAN_DISABLED
) &&
625 (chan
->chan
== iface
->conf
->channel
)) {
630 if (iface
->conf
->channel
== 0) {
631 /* TODO: could request a scan of neighboring BSSes and select
632 * the channel automatically */
633 wpa_printf(MSG_ERROR
, "Channel not configured "
634 "(hw_mode/channel in hostapd.conf)");
637 if (ok
== 0 && iface
->conf
->channel
!= 0) {
638 hostapd_logger(iface
->bss
[0], NULL
,
639 HOSTAPD_MODULE_IEEE80211
,
640 HOSTAPD_LEVEL_WARNING
,
641 "Configured channel (%d) not found from the "
642 "channel list of current mode (%d) %s",
643 iface
->conf
->channel
,
644 iface
->current_mode
->mode
,
645 hostapd_hw_mode_txt(iface
->current_mode
->mode
));
646 iface
->current_mode
= NULL
;
649 if (iface
->current_mode
== NULL
) {
650 hostapd_logger(iface
->bss
[0], NULL
, HOSTAPD_MODULE_IEEE80211
,
651 HOSTAPD_LEVEL_WARNING
,
652 "Hardware does not support configured channel");
656 if (hostapd_prepare_rates(iface
->bss
[0], iface
->current_mode
)) {
657 wpa_printf(MSG_ERROR
, "Failed to prepare rates table.");
658 hostapd_logger(iface
->bss
[0], NULL
, HOSTAPD_MODULE_IEEE80211
,
659 HOSTAPD_LEVEL_WARNING
,
660 "Failed to prepare rates table.");
668 const char * hostapd_hw_mode_txt(int mode
)
671 case HOSTAPD_MODE_IEEE80211A
:
672 return "IEEE 802.11a";
673 case HOSTAPD_MODE_IEEE80211B
:
674 return "IEEE 802.11b";
675 case HOSTAPD_MODE_IEEE80211G
:
676 return "IEEE 802.11g";
683 int hostapd_hw_get_freq(struct hostapd_data
*hapd
, int chan
)
687 if (!hapd
->iface
->current_mode
)
690 for (i
= 0; i
< hapd
->iface
->current_mode
->num_channels
; i
++) {
691 struct hostapd_channel_data
*ch
=
692 &hapd
->iface
->current_mode
->channels
[i
];
693 if (ch
->chan
== chan
)
701 int hostapd_hw_get_channel(struct hostapd_data
*hapd
, int freq
)
705 if (!hapd
->iface
->current_mode
)
708 for (i
= 0; i
< hapd
->iface
->current_mode
->num_channels
; i
++) {
709 struct hostapd_channel_data
*ch
=
710 &hapd
->iface
->current_mode
->channels
[i
];
711 if (ch
->freq
== freq
)