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"
22 #include "ieee802_11.h"
26 void hostapd_free_hw_features(struct hostapd_hw_modes
*hw_features
,
27 size_t num_hw_features
)
31 if (hw_features
== NULL
)
34 for (i
= 0; i
< num_hw_features
; i
++) {
35 free(hw_features
[i
].channels
);
36 free(hw_features
[i
].rates
);
43 int hostapd_get_hw_features(struct hostapd_iface
*iface
)
45 struct hostapd_data
*hapd
= iface
->bss
[0];
48 struct hostapd_hw_modes
*modes
;
50 modes
= hostapd_get_hw_feature_data(hapd
, &num_modes
, &flags
);
52 hostapd_logger(hapd
, NULL
, HOSTAPD_MODULE_IEEE80211
,
54 "Fetching hardware channel/rate support not "
59 iface
->hw_flags
= flags
;
61 hostapd_free_hw_features(iface
->hw_features
, iface
->num_hw_features
);
62 iface
->hw_features
= modes
;
63 iface
->num_hw_features
= num_modes
;
65 for (i
= 0; i
< num_modes
; i
++) {
66 struct hostapd_hw_modes
*feature
= &modes
[i
];
67 /* set flag for channels we can use in current regulatory
69 for (j
= 0; j
< feature
->num_channels
; j
++) {
70 /* TODO: add regulatory domain lookup */
71 unsigned char power_level
= 0;
72 unsigned char antenna_max
= 0;
74 if ((feature
->mode
== HOSTAPD_MODE_IEEE80211G
||
75 feature
->mode
== HOSTAPD_MODE_IEEE80211B
) &&
76 feature
->channels
[j
].chan
>= 1 &&
77 feature
->channels
[j
].chan
<= 11) {
79 feature
->channels
[j
].flag
|=
82 feature
->channels
[j
].flag
&=
85 hostapd_set_channel_flag(hapd
, feature
->mode
,
86 feature
->channels
[j
].chan
,
87 feature
->channels
[j
].flag
,
97 static int hostapd_prepare_rates(struct hostapd_data
*hapd
,
98 struct hostapd_hw_modes
*mode
)
100 int i
, num_basic_rates
= 0;
101 int basic_rates_a
[] = { 60, 120, 240, -1 };
102 int basic_rates_b
[] = { 10, 20, -1 };
103 int basic_rates_g
[] = { 10, 20, 55, 110, -1 };
106 if (hapd
->iconf
->basic_rates
)
107 basic_rates
= hapd
->iconf
->basic_rates
;
108 else switch (mode
->mode
) {
109 case HOSTAPD_MODE_IEEE80211A
:
110 basic_rates
= basic_rates_a
;
112 case HOSTAPD_MODE_IEEE80211B
:
113 basic_rates
= basic_rates_b
;
115 case HOSTAPD_MODE_IEEE80211G
:
116 basic_rates
= basic_rates_g
;
122 if (hostapd_set_rate_sets(hapd
, hapd
->iconf
->supported_rates
,
123 basic_rates
, mode
->mode
)) {
124 printf("Failed to update rate sets in kernel module\n");
127 free(hapd
->iface
->current_rates
);
128 hapd
->iface
->num_rates
= 0;
130 hapd
->iface
->current_rates
=
131 malloc(mode
->num_rates
* sizeof(struct hostapd_rate_data
));
132 if (!hapd
->iface
->current_rates
) {
133 printf("Failed to allocate memory for rate table.\n");
137 for (i
= 0; i
< mode
->num_rates
; i
++) {
138 struct hostapd_rate_data
*rate
;
140 if (hapd
->iconf
->supported_rates
&&
141 !hostapd_rate_found(hapd
->iconf
->supported_rates
,
142 mode
->rates
[i
].rate
))
145 rate
= &hapd
->iface
->current_rates
[hapd
->iface
->num_rates
];
146 memcpy(rate
, &mode
->rates
[i
],
147 sizeof(struct hostapd_rate_data
));
148 if (hostapd_rate_found(basic_rates
, rate
->rate
)) {
149 rate
->flags
|= HOSTAPD_RATE_BASIC
;
152 rate
->flags
&= ~HOSTAPD_RATE_BASIC
;
153 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
,
154 "RATE[%d] rate=%d flags=0x%x\n",
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 printf("No rates remaining in supported/basic rate sets "
161 "(%d,%d).\n", hapd
->iface
->num_rates
, num_basic_rates
);
169 static void select_hw_mode_start(void *eloop_data
, void *user_ctx
);
170 static void select_hw_mode2_handler(void *eloop_data
, void *user_ctx
);
173 * select_hw_mode_finalize - Finish select HW mode & call the callback
174 * @iface: Pointer to interface data.
175 * @status: Status of the select HW mode (0 on success; -1 on failure).
176 * Returns: 0 on success; -1 on failure (e.g., was not in progress).
178 static int select_hw_mode_finalize(struct hostapd_iface
*iface
, int status
)
182 if (!iface
->hw_mode_sel_cb
)
185 eloop_cancel_timeout(select_hw_mode_start
, iface
, NULL
);
186 eloop_cancel_timeout(select_hw_mode2_handler
, iface
, NULL
);
188 cb
= iface
->hw_mode_sel_cb
;
190 iface
->hw_mode_sel_cb
= NULL
;
199 * select_hw_mode2 - Select the hardware mode (part 2)
200 * @iface: Pointer to interface data.
201 * @status: Status of auto chanel selection.
203 * Setup the rates and passive scanning based on the configuration.
205 static void select_hw_mode2(struct hostapd_iface
*iface
, int status
)
211 if (iface
->current_mode
== NULL
) {
212 hostapd_logger(iface
->bss
[0], NULL
, HOSTAPD_MODULE_IEEE80211
,
213 HOSTAPD_LEVEL_WARNING
,
214 "Hardware does not support configured channel");
219 if (hostapd_prepare_rates(iface
->bss
[0], iface
->current_mode
)) {
220 printf("Failed to prepare rates table.\n");
221 hostapd_logger(iface
->bss
[0], NULL
, HOSTAPD_MODULE_IEEE80211
,
222 HOSTAPD_LEVEL_WARNING
,
223 "Failed to prepare rates table.");
228 ret
= hostapd_passive_scan(iface
->bss
[0], 0,
229 iface
->conf
->passive_scan_mode
,
230 iface
->conf
->passive_scan_interval
,
231 iface
->conf
->passive_scan_listen
,
234 printf("Could not set passive scanning: %s\n", strerror(ret
));
239 select_hw_mode_finalize(iface
, ret
);
244 * select_hw_mode2_handler - Calls select_hw_mode2 when auto chan isn't used
245 * @eloop_data: Stores the struct hostapd_iface * for the interface.
248 static void select_hw_mode2_handler(void *eloop_data
, void *user_ctx
)
250 struct hostapd_iface
*iface
= eloop_data
;
252 select_hw_mode2(iface
, 0);
257 * select_hw_mode1 - Select the hardware mode (part 1)
258 * @iface: Pointer to interface data.
259 * Returns: 0 on success; -1 on failure.
261 * Setup the hardware mode and channel based on the configuration.
262 * Schedules select_hw_mode2() to be called immediately or after automatic
263 * channel selection takes place.
265 static int select_hw_mode1(struct hostapd_iface
*iface
)
269 if (iface
->num_hw_features
< 1)
272 iface
->current_mode
= NULL
;
273 for (i
= 0; i
< iface
->num_hw_features
; i
++) {
274 struct hostapd_hw_modes
*mode
= &iface
->hw_features
[i
];
275 if (mode
->mode
== (int) iface
->conf
->hw_mode
) {
276 iface
->current_mode
= mode
;
281 if (iface
->current_mode
== NULL
) {
282 printf("Hardware does not support configured mode\n");
283 hostapd_logger(iface
->bss
[0], NULL
, HOSTAPD_MODULE_IEEE80211
,
284 HOSTAPD_LEVEL_WARNING
,
285 "Hardware does not support configured mode "
286 "(%d)", (int) iface
->conf
->hw_mode
);
291 for (j
= 0; j
< iface
->current_mode
->num_channels
; j
++) {
292 struct hostapd_channel_data
*chan
=
293 &iface
->current_mode
->channels
[j
];
294 if ((chan
->flag
& HOSTAPD_CHAN_W_SCAN
) &&
295 (chan
->chan
== iface
->conf
->channel
)) {
300 if (ok
== 0 && iface
->conf
->channel
!= 0) {
301 hostapd_logger(iface
->bss
[0], NULL
,
302 HOSTAPD_MODULE_IEEE80211
,
303 HOSTAPD_LEVEL_WARNING
,
304 "Configured channel (%d) not found from the "
305 "channel list of current mode (%d) %s",
306 iface
->conf
->channel
,
307 iface
->current_mode
->mode
,
308 hostapd_hw_mode_txt(iface
->current_mode
->mode
));
309 iface
->current_mode
= NULL
;
313 * Calls select_hw_mode2() via a handler, so that the function is
314 * always executed from eloop.
316 eloop_register_timeout(0, 0, select_hw_mode2_handler
, iface
, NULL
);
322 * select_hw_mode_start - Handler to start select HW mode
323 * @eloop_data: Stores the struct hostapd_iface * for the interface.
326 * An eloop handler is used so that all errors can be processed by the
327 * callback without introducing stack recursion.
329 static void select_hw_mode_start(void *eloop_data
, void *user_ctx
)
331 struct hostapd_iface
*iface
= (struct hostapd_iface
*)eloop_data
;
335 ret
= select_hw_mode1(iface
);
337 select_hw_mode_finalize(iface
, ret
);
342 * hostapd_select_hw_mode_start - Start selection of the hardware mode
343 * @iface: Pointer to interface data.
344 * @cb: The function to callback when done.
345 * Returns: 0 if it starts successfully; cb will be called when done.
346 * -1 on failure; cb will not be called.
348 * Sets up the hardware mode, channel, rates, and passive scanning
349 * based on the configuration.
351 int hostapd_select_hw_mode_start(struct hostapd_iface
*iface
,
354 if (iface
->hw_mode_sel_cb
) {
355 wpa_printf(MSG_DEBUG
,
356 "%s: Hardware mode select already in progress.",
357 iface
->bss
[0]->conf
->iface
);
361 iface
->hw_mode_sel_cb
= cb
;
363 eloop_register_timeout(0, 0, select_hw_mode_start
, iface
, NULL
);
370 * hostapd_auto_chan_select_stop - Stops automatic channel selection
371 * @iface: Pointer to interface data.
372 * Returns: 0 if successfully stopped;
373 * -1 on failure (i.e., was not in progress)
375 int hostapd_select_hw_mode_stop(struct hostapd_iface
*iface
)
377 return select_hw_mode_finalize(iface
, -1);
381 const char * hostapd_hw_mode_txt(int mode
)
384 case HOSTAPD_MODE_IEEE80211A
:
385 return "IEEE 802.11a";
386 case HOSTAPD_MODE_IEEE80211B
:
387 return "IEEE 802.11b";
388 case HOSTAPD_MODE_IEEE80211G
:
389 return "IEEE 802.11g";
396 int hostapd_hw_get_freq(struct hostapd_data
*hapd
, int chan
)
400 if (!hapd
->iface
->current_mode
)
403 for (i
= 0; i
< hapd
->iface
->current_mode
->num_channels
; i
++) {
404 struct hostapd_channel_data
*ch
=
405 &hapd
->iface
->current_mode
->channels
[i
];
406 if (ch
->chan
== chan
)
414 int hostapd_hw_get_channel(struct hostapd_data
*hapd
, int freq
)
418 if (!hapd
->iface
->current_mode
)
421 for (i
= 0; i
< hapd
->iface
->current_mode
->num_channels
; i
++) {
422 struct hostapd_channel_data
*ch
=
423 &hapd
->iface
->current_mode
->channels
[i
];
424 if (ch
->freq
== freq
)