2 * hostapd / Hardware feature query and different modes
3 * Copyright 2002-2003, Instant802 Networks, Inc.
4 * Copyright 2005-2006, Devicescape Software, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * Alternatively, this software may be distributed under the terms of BSD
13 * See README and COPYING for more details.
19 #include "hw_features.h"
25 void hostapd_free_hw_features(struct hostapd_hw_modes
*hw_features
,
26 size_t num_hw_features
)
30 if (hw_features
== NULL
)
33 for (i
= 0; i
< num_hw_features
; i
++) {
34 os_free(hw_features
[i
].channels
);
35 os_free(hw_features
[i
].rates
);
42 int hostapd_get_hw_features(struct hostapd_iface
*iface
)
44 struct hostapd_data
*hapd
= iface
->bss
[0];
47 struct hostapd_hw_modes
*modes
;
49 modes
= hostapd_get_hw_feature_data(hapd
, &num_modes
, &flags
);
51 hostapd_logger(hapd
, NULL
, HOSTAPD_MODULE_IEEE80211
,
53 "Fetching hardware channel/rate support not "
58 iface
->hw_flags
= flags
;
60 hostapd_free_hw_features(iface
->hw_features
, iface
->num_hw_features
);
61 iface
->hw_features
= modes
;
62 iface
->num_hw_features
= num_modes
;
64 for (i
= 0; i
< num_modes
; i
++) {
65 struct hostapd_hw_modes
*feature
= &modes
[i
];
66 /* set flag for channels we can use in current regulatory
68 for (j
= 0; j
< feature
->num_channels
; j
++) {
69 /* TODO: add regulatory domain lookup */
70 unsigned char power_level
= 0;
71 unsigned char antenna_max
= 0;
73 if ((feature
->mode
== HOSTAPD_MODE_IEEE80211G
||
74 feature
->mode
== HOSTAPD_MODE_IEEE80211B
) &&
75 feature
->channels
[j
].chan
>= 1 &&
76 feature
->channels
[j
].chan
<= 11) {
78 feature
->channels
[j
].flag
|=
81 feature
->channels
[j
].flag
&=
84 hostapd_set_channel_flag(hapd
, feature
->mode
,
85 feature
->channels
[j
].chan
,
86 feature
->channels
[j
].flag
,
96 static int hostapd_prepare_rates(struct hostapd_data
*hapd
,
97 struct hostapd_hw_modes
*mode
)
99 int i
, num_basic_rates
= 0;
100 int basic_rates_a
[] = { 60, 120, 240, -1 };
101 int basic_rates_b
[] = { 10, 20, -1 };
102 int basic_rates_g
[] = { 10, 20, 55, 110, -1 };
105 if (hapd
->iconf
->basic_rates
)
106 basic_rates
= hapd
->iconf
->basic_rates
;
107 else switch (mode
->mode
) {
108 case HOSTAPD_MODE_IEEE80211A
:
109 basic_rates
= basic_rates_a
;
111 case HOSTAPD_MODE_IEEE80211B
:
112 basic_rates
= basic_rates_b
;
114 case HOSTAPD_MODE_IEEE80211G
:
115 basic_rates
= basic_rates_g
;
121 if (hostapd_set_rate_sets(hapd
, hapd
->iconf
->supported_rates
,
122 basic_rates
, mode
->mode
)) {
123 wpa_printf(MSG_ERROR
, "Failed to update rate sets in kernel "
127 os_free(hapd
->iface
->current_rates
);
128 hapd
->iface
->num_rates
= 0;
130 hapd
->iface
->current_rates
=
131 os_malloc(mode
->num_rates
* sizeof(struct hostapd_rate_data
));
132 if (!hapd
->iface
->current_rates
) {
133 wpa_printf(MSG_ERROR
, "Failed to allocate memory for rate "
138 for (i
= 0; i
< mode
->num_rates
; i
++) {
139 struct hostapd_rate_data
*rate
;
141 if (hapd
->iconf
->supported_rates
&&
142 !hostapd_rate_found(hapd
->iconf
->supported_rates
,
143 mode
->rates
[i
].rate
))
146 rate
= &hapd
->iface
->current_rates
[hapd
->iface
->num_rates
];
147 os_memcpy(rate
, &mode
->rates
[i
],
148 sizeof(struct hostapd_rate_data
));
149 if (hostapd_rate_found(basic_rates
, rate
->rate
)) {
150 rate
->flags
|= HOSTAPD_RATE_BASIC
;
153 rate
->flags
&= ~HOSTAPD_RATE_BASIC
;
154 wpa_printf(MSG_DEBUG
, "RATE[%d] rate=%d flags=0x%x",
155 hapd
->iface
->num_rates
, rate
->rate
, rate
->flags
);
156 hapd
->iface
->num_rates
++;
159 if (hapd
->iface
->num_rates
== 0 || num_basic_rates
== 0) {
160 wpa_printf(MSG_ERROR
, "No rates remaining in supported/basic "
161 "rate sets (%d,%d).",
162 hapd
->iface
->num_rates
, num_basic_rates
);
170 static void select_hw_mode_start(void *eloop_data
, void *user_ctx
);
171 static void select_hw_mode2_handler(void *eloop_data
, void *user_ctx
);
174 * select_hw_mode_finalize - Finish select HW mode & call the callback
175 * @iface: Pointer to interface data.
176 * @status: Status of the select HW mode (0 on success; -1 on failure).
177 * Returns: 0 on success; -1 on failure (e.g., was not in progress).
179 static int select_hw_mode_finalize(struct hostapd_iface
*iface
, int status
)
183 if (!iface
->hw_mode_sel_cb
)
186 eloop_cancel_timeout(select_hw_mode_start
, iface
, NULL
);
187 eloop_cancel_timeout(select_hw_mode2_handler
, iface
, NULL
);
189 cb
= iface
->hw_mode_sel_cb
;
191 iface
->hw_mode_sel_cb
= NULL
;
200 * select_hw_mode2 - Select the hardware mode (part 2)
201 * @iface: Pointer to interface data.
202 * @status: Status of auto chanel selection.
204 * Setup the rates and passive scanning based on the configuration.
206 static void select_hw_mode2(struct hostapd_iface
*iface
, int status
)
212 if (iface
->current_mode
== NULL
) {
213 hostapd_logger(iface
->bss
[0], NULL
, HOSTAPD_MODULE_IEEE80211
,
214 HOSTAPD_LEVEL_WARNING
,
215 "Hardware does not support configured channel");
220 if (hostapd_prepare_rates(iface
->bss
[0], iface
->current_mode
)) {
221 wpa_printf(MSG_ERROR
, "Failed to prepare rates table.");
222 hostapd_logger(iface
->bss
[0], NULL
, HOSTAPD_MODULE_IEEE80211
,
223 HOSTAPD_LEVEL_WARNING
,
224 "Failed to prepare rates table.");
229 ret
= hostapd_passive_scan(iface
->bss
[0], 0,
230 iface
->conf
->passive_scan_mode
,
231 iface
->conf
->passive_scan_interval
,
232 iface
->conf
->passive_scan_listen
,
235 wpa_printf(MSG_ERROR
, "Could not set passive scanning: %s",
241 select_hw_mode_finalize(iface
, ret
);
246 * select_hw_mode2_handler - Calls select_hw_mode2 when auto chan isn't used
247 * @eloop_data: Stores the struct hostapd_iface * for the interface.
250 static void select_hw_mode2_handler(void *eloop_data
, void *user_ctx
)
252 struct hostapd_iface
*iface
= eloop_data
;
254 select_hw_mode2(iface
, 0);
259 * select_hw_mode1 - Select the hardware mode (part 1)
260 * @iface: Pointer to interface data.
261 * Returns: 0 on success; -1 on failure.
263 * Setup the hardware mode and channel based on the configuration.
264 * Schedules select_hw_mode2() to be called immediately or after automatic
265 * channel selection takes place.
267 static int select_hw_mode1(struct hostapd_iface
*iface
)
271 if (iface
->num_hw_features
< 1)
274 iface
->current_mode
= NULL
;
275 for (i
= 0; i
< iface
->num_hw_features
; i
++) {
276 struct hostapd_hw_modes
*mode
= &iface
->hw_features
[i
];
277 if (mode
->mode
== (int) iface
->conf
->hw_mode
) {
278 iface
->current_mode
= mode
;
283 if (iface
->current_mode
== NULL
) {
284 wpa_printf(MSG_ERROR
, "Hardware does not support configured "
286 hostapd_logger(iface
->bss
[0], NULL
, HOSTAPD_MODULE_IEEE80211
,
287 HOSTAPD_LEVEL_WARNING
,
288 "Hardware does not support configured mode "
289 "(%d)", (int) iface
->conf
->hw_mode
);
294 for (j
= 0; j
< iface
->current_mode
->num_channels
; j
++) {
295 struct hostapd_channel_data
*chan
=
296 &iface
->current_mode
->channels
[j
];
297 if ((chan
->flag
& HOSTAPD_CHAN_W_SCAN
) &&
298 (chan
->chan
== iface
->conf
->channel
)) {
303 if (ok
== 0 && iface
->conf
->channel
!= 0) {
304 hostapd_logger(iface
->bss
[0], NULL
,
305 HOSTAPD_MODULE_IEEE80211
,
306 HOSTAPD_LEVEL_WARNING
,
307 "Configured channel (%d) not found from the "
308 "channel list of current mode (%d) %s",
309 iface
->conf
->channel
,
310 iface
->current_mode
->mode
,
311 hostapd_hw_mode_txt(iface
->current_mode
->mode
));
312 iface
->current_mode
= NULL
;
316 * Calls select_hw_mode2() via a handler, so that the function is
317 * always executed from eloop.
319 eloop_register_timeout(0, 0, select_hw_mode2_handler
, iface
, NULL
);
325 * select_hw_mode_start - Handler to start select HW mode
326 * @eloop_data: Stores the struct hostapd_iface * for the interface.
329 * An eloop handler is used so that all errors can be processed by the
330 * callback without introducing stack recursion.
332 static void select_hw_mode_start(void *eloop_data
, void *user_ctx
)
334 struct hostapd_iface
*iface
= (struct hostapd_iface
*)eloop_data
;
338 ret
= select_hw_mode1(iface
);
340 select_hw_mode_finalize(iface
, ret
);
345 * hostapd_select_hw_mode_start - Start selection of the hardware mode
346 * @iface: Pointer to interface data.
347 * @cb: The function to callback when done.
348 * Returns: 0 if it starts successfully; cb will be called when done.
349 * -1 on failure; cb will not be called.
351 * Sets up the hardware mode, channel, rates, and passive scanning
352 * based on the configuration.
354 int hostapd_select_hw_mode_start(struct hostapd_iface
*iface
,
357 if (iface
->hw_mode_sel_cb
) {
358 wpa_printf(MSG_DEBUG
,
359 "%s: Hardware mode select already in progress.",
360 iface
->bss
[0]->conf
->iface
);
364 iface
->hw_mode_sel_cb
= cb
;
366 eloop_register_timeout(0, 0, select_hw_mode_start
, iface
, NULL
);
373 * hostapd_auto_chan_select_stop - Stops automatic channel selection
374 * @iface: Pointer to interface data.
375 * Returns: 0 if successfully stopped;
376 * -1 on failure (i.e., was not in progress)
378 int hostapd_select_hw_mode_stop(struct hostapd_iface
*iface
)
380 return select_hw_mode_finalize(iface
, -1);
384 const char * hostapd_hw_mode_txt(int mode
)
387 case HOSTAPD_MODE_IEEE80211A
:
388 return "IEEE 802.11a";
389 case HOSTAPD_MODE_IEEE80211B
:
390 return "IEEE 802.11b";
391 case HOSTAPD_MODE_IEEE80211G
:
392 return "IEEE 802.11g";
399 int hostapd_hw_get_freq(struct hostapd_data
*hapd
, int chan
)
403 if (!hapd
->iface
->current_mode
)
406 for (i
= 0; i
< hapd
->iface
->current_mode
->num_channels
; i
++) {
407 struct hostapd_channel_data
*ch
=
408 &hapd
->iface
->current_mode
->channels
[i
];
409 if (ch
->chan
== chan
)
417 int hostapd_hw_get_channel(struct hostapd_data
*hapd
, int freq
)
421 if (!hapd
->iface
->current_mode
)
424 for (i
= 0; i
< hapd
->iface
->current_mode
->num_channels
; i
++) {
425 struct hostapd_channel_data
*ch
=
426 &hapd
->iface
->current_mode
->channels
[i
];
427 if (ch
->freq
== freq
)