Remove overly complex hostapd setup sequence with n+1 callbacks

This code was originally added as a mechanism to handle long waits
during channel selection and/or radar detection. It is not currently
really used and makes the setup sequence nearly impossible to
understand. Let's get rid of the unwanted complexity. This needs to be
redesigned if it is ever needed again.
This commit is contained in:
Jouni Malinen 2008-11-21 20:39:33 +02:00
parent 2387b8c0b0
commit ddaa83ebeb
4 changed files with 159 additions and 439 deletions

View File

@ -1385,22 +1385,123 @@ static void hostapd_tx_queue_params(struct hostapd_iface *iface)
} }
/** static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
* setup_interface2 - Setup (initialize) an interface (part 2) size_t identity_len, int phase2,
* @iface: Pointer to interface data. struct eap_user *user)
* Returns: 0 on success; -1 on failure. {
* const struct hostapd_eap_user *eap_user;
* Flushes old stations, sets the channel, DFS parameters, encryption, int i, count;
* beacons, and WDS links based on the configuration.
*/ eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
static int setup_interface2(struct hostapd_iface *iface) if (eap_user == NULL)
return -1;
if (user == NULL)
return 0;
os_memset(user, 0, sizeof(*user));
count = EAP_USER_MAX_METHODS;
if (count > EAP_MAX_METHODS)
count = EAP_MAX_METHODS;
for (i = 0; i < count; i++) {
user->methods[i].vendor = eap_user->methods[i].vendor;
user->methods[i].method = eap_user->methods[i].method;
}
if (eap_user->password) {
user->password = os_malloc(eap_user->password_len);
if (user->password == NULL)
return -1;
os_memcpy(user->password, eap_user->password,
eap_user->password_len);
user->password_len = eap_user->password_len;
user->password_hash = eap_user->password_hash;
}
user->force_version = eap_user->force_version;
user->ttls_auth = eap_user->ttls_auth;
return 0;
}
static int setup_interface(struct hostapd_iface *iface)
{ {
struct hostapd_data *hapd = iface->bss[0]; struct hostapd_data *hapd = iface->bss[0];
struct hostapd_bss_config *conf = hapd->conf;
size_t i;
char country[4];
u8 *b = conf->bssid;
int freq; int freq;
size_t j; size_t j;
int ret = 0; int ret = 0;
u8 *prev_addr; u8 *prev_addr;
/*
* Initialize the driver interface and make sure that all BSSes get
* configured with a pointer to this driver interface.
*/
if (b[0] | b[1] | b[2] | b[3] | b[4] | b[5]) {
hapd->drv_priv = hostapd_driver_init_bssid(hapd, b);
} else {
hapd->drv_priv = hostapd_driver_init(hapd);
}
if (hapd->drv_priv == NULL) {
printf("%s driver initialization failed.\n",
hapd->driver ? hapd->driver->name : "Unknown");
hapd->driver = NULL;
return -1;
}
for (i = 0; i < iface->num_bss; i++) {
iface->bss[i]->driver = hapd->driver;
iface->bss[i]->drv_priv = hapd->drv_priv;
}
if (hostapd_validate_bssid_configuration(iface))
return -1;
#ifdef CONFIG_IEEE80211N
SET_2BIT_LE16(&iface->ht_op_mode,
HT_INFO_OPERATION_MODE_OP_MODE_OFFSET,
OP_MODE_PURE);
#endif /* CONFIG_IEEE80211N */
os_memcpy(country, hapd->iconf->country, 3);
country[3] = '\0';
if (hostapd_set_country(hapd, country) < 0) {
printf("Failed to set country code\n");
return -1;
}
if (hapd->iconf->ieee80211d &&
hostapd_set_ieee80211d(hapd, 1) < 0) {
printf("Failed to set ieee80211d (%d)\n",
hapd->iconf->ieee80211d);
return -1;
}
if (hapd->iconf->bridge_packets != INTERNAL_BRIDGE_DO_NOT_CONTROL &&
hostapd_set_internal_bridge(hapd, hapd->iconf->bridge_packets)) {
printf("Failed to set bridge_packets for kernel driver\n");
return -1;
}
/* TODO: merge with hostapd_driver_init() ? */
if (hostapd_wireless_event_init(hapd) < 0)
return -1;
if (hostapd_get_hw_features(iface)) {
/* Not all drivers support this yet, so continue without hw
* feature data. */
} else {
int ret = hostapd_select_hw_mode(iface);
if (ret < 0) {
printf("Could not select hw_mode and channel. (%d)\n",
ret);
return -1;
}
}
hostapd_flush_old_stations(hapd); hostapd_flush_old_stations(hapd);
hostapd_set_privacy(hapd, 0); hostapd_set_privacy(hapd, 0);
@ -1462,254 +1563,35 @@ static int setup_interface2(struct hostapd_iface *iface)
} }
static void setup_interface_start(void *eloop_data, void *user_ctx);
static void setup_interface2_handler(void *eloop_data, void *user_ctx);
/** /**
* setup_interface_finalize - Finish setup interface & call the callback * hostapd_setup_interface - Setup of an interface
* @iface: Pointer to interface data. * @iface: Pointer to interface data.
* @status: Status of the setup interface (0 on success; -1 on failure).
* Returns: 0 on success; -1 on failure (e.g., was not in progress).
*/
static int setup_interface_finalize(struct hostapd_iface *iface, int status)
{
hostapd_iface_cb cb;
if (!iface->setup_cb)
return -1;
eloop_cancel_timeout(setup_interface_start, iface, NULL);
eloop_cancel_timeout(setup_interface2_handler, iface, NULL);
hostapd_select_hw_mode_stop(iface);
cb = iface->setup_cb;
iface->setup_cb = NULL;
cb(iface, status);
return 0;
}
/**
* setup_interface2_wrapper - Wrapper for setup_interface2()
* @iface: Pointer to interface data.
* @status: Status of the hw mode select.
*
* Wrapper for setup_interface2() to calls finalize function upon completion.
*/
static void setup_interface2_wrapper(struct hostapd_iface *iface, int status)
{
int ret = status;
if (ret)
printf("Could not select hw_mode and channel. (%d)\n", ret);
else
ret = setup_interface2(iface);
setup_interface_finalize(iface, ret);
}
/**
* setup_interface2_handler - Used for immediate call of setup_interface2
* @eloop_data: Stores the struct hostapd_iface * for the interface.
* @user_ctx: Unused.
*/
static void setup_interface2_handler(void *eloop_data, void *user_ctx)
{
struct hostapd_iface *iface = eloop_data;
setup_interface2_wrapper(iface, 0);
}
static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
size_t identity_len, int phase2,
struct eap_user *user)
{
const struct hostapd_eap_user *eap_user;
int i, count;
eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
if (eap_user == NULL)
return -1;
if (user == NULL)
return 0;
os_memset(user, 0, sizeof(*user));
count = EAP_USER_MAX_METHODS;
if (count > EAP_MAX_METHODS)
count = EAP_MAX_METHODS;
for (i = 0; i < count; i++) {
user->methods[i].vendor = eap_user->methods[i].vendor;
user->methods[i].method = eap_user->methods[i].method;
}
if (eap_user->password) {
user->password = os_malloc(eap_user->password_len);
if (user->password == NULL)
return -1;
os_memcpy(user->password, eap_user->password,
eap_user->password_len);
user->password_len = eap_user->password_len;
user->password_hash = eap_user->password_hash;
}
user->force_version = eap_user->force_version;
user->ttls_auth = eap_user->ttls_auth;
return 0;
}
/**
* setup_interface1 - Setup (initialize) an interface (part 1)
* @iface: Pointer to interface data
* Returns: 0 on success, -1 on failure * Returns: 0 on success, -1 on failure
* *
* Initializes the driver interface, validates the configuration, * Initializes the driver interface, validates the configuration,
* and sets driver parameters based on the configuration. * and sets driver parameters based on the configuration.
* Schedules setup_interface2() to be called immediately or after * Flushes old stations, sets the channel, encryption,
* hardware mode setup takes place.
*/
static int setup_interface1(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_bss_config *conf = hapd->conf;
size_t i;
char country[4];
u8 *b = conf->bssid;
/*
* Initialize the driver interface and make sure that all BSSes get
* configured with a pointer to this driver interface.
*/
if (b[0] | b[1] | b[2] | b[3] | b[4] | b[5]) {
hapd->drv_priv = hostapd_driver_init_bssid(hapd, b);
} else {
hapd->drv_priv = hostapd_driver_init(hapd);
}
if (hapd->drv_priv == NULL) {
printf("%s driver initialization failed.\n",
hapd->driver ? hapd->driver->name : "Unknown");
hapd->driver = NULL;
return -1;
}
for (i = 0; i < iface->num_bss; i++) {
iface->bss[i]->driver = hapd->driver;
iface->bss[i]->drv_priv = hapd->drv_priv;
}
if (hostapd_validate_bssid_configuration(iface))
return -1;
#ifdef CONFIG_IEEE80211N
SET_2BIT_LE16(&iface->ht_op_mode,
HT_INFO_OPERATION_MODE_OP_MODE_OFFSET,
OP_MODE_PURE);
#endif /* CONFIG_IEEE80211N */
os_memcpy(country, hapd->iconf->country, 3);
country[3] = '\0';
if (hostapd_set_country(hapd, country) < 0) {
printf("Failed to set country code\n");
return -1;
}
if (hapd->iconf->ieee80211d &&
hostapd_set_ieee80211d(hapd, 1) < 0) {
printf("Failed to set ieee80211d (%d)\n",
hapd->iconf->ieee80211d);
return -1;
}
if (hapd->iconf->bridge_packets != INTERNAL_BRIDGE_DO_NOT_CONTROL &&
hostapd_set_internal_bridge(hapd, hapd->iconf->bridge_packets)) {
printf("Failed to set bridge_packets for kernel driver\n");
return -1;
}
/* TODO: merge with hostapd_driver_init() ? */
if (hostapd_wireless_event_init(hapd) < 0)
return -1;
if (hostapd_get_hw_features(iface)) {
/* Not all drivers support this yet, so continue without hw
* feature data. */
} else {
return hostapd_select_hw_mode_start(iface,
setup_interface2_wrapper);
}
eloop_register_timeout(0, 0, setup_interface2_handler, iface, NULL);
return 0;
}
/**
* setup_interface_start - Handler to start setup interface
* @eloop_data: Stores the struct hostapd_iface * for the interface.
* @user_ctx: Unused.
*
* An eloop handler is used so that all errors can be processed by the
* callback without introducing stack recursion.
*/
static void setup_interface_start(void *eloop_data, void *user_ctx)
{
struct hostapd_iface *iface = eloop_data;
int ret;
ret = setup_interface1(iface);
if (ret)
setup_interface_finalize(iface, ret);
}
/**
* hostapd_setup_interface_start - Start the setup of an interface
* @iface: Pointer to interface data.
* @cb: The function to callback when done.
* Returns: 0 if it starts successfully; cb will be called when done.
* -1 on failure; cb will not be called.
*
* Initializes the driver interface, validates the configuration,
* and sets driver parameters based on the configuration.
* Flushes old stations, sets the channel, DFS parameters, encryption,
* beacons, and WDS links based on the configuration. * beacons, and WDS links based on the configuration.
*/ */
int hostapd_setup_interface_start(struct hostapd_iface *iface, static int hostapd_setup_interface(struct hostapd_iface *iface)
hostapd_iface_cb cb)
{ {
if (iface->setup_cb) { int ret;
wpa_printf(MSG_DEBUG,
"%s: Interface setup already in progress.\n", ret = setup_interface(iface);
if (ret) {
wpa_printf(MSG_DEBUG, "%s: Unable to setup interface.",
iface->bss[0]->conf->iface); iface->bss[0]->conf->iface);
eloop_terminate();
return -1; return -1;
} else if (!hostapd_drv_none(iface->bss[0])) {
wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
iface->bss[0]->conf->iface);
} }
iface->setup_cb = cb;
eloop_register_timeout(0, 0, setup_interface_start, iface, NULL);
return 0; return 0;
} }
/**
* hostapd_setup_interace_stop - Stops the setup of an interface
* @iface: Pointer to interface data
* Returns: 0 if successfully stopped;
* -1 on failure (i.e., was not in progress)
*/
int hostapd_setup_interface_stop(struct hostapd_iface *iface)
{
return setup_interface_finalize(iface, -1);
}
static void show_version(void) static void show_version(void)
{ {
fprintf(stderr, fprintf(stderr,
@ -1897,23 +1779,6 @@ fail:
} }
/**
* setup_interface_done - Callback when an interface is done being setup.
* @iface: Pointer to interface data.
* @status: Status of the interface setup (0 on success; -1 on failure).
*/
static void setup_interface_done(struct hostapd_iface *iface, int status)
{
if (status) {
wpa_printf(MSG_DEBUG, "%s: Unable to setup interface.",
iface->bss[0]->conf->iface);
eloop_terminate();
} else if (!hostapd_drv_none(iface->bss[0]))
wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
iface->bss[0]->conf->iface);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct hapd_interfaces interfaces; struct hapd_interfaces interfaces;
@ -2001,8 +1866,7 @@ int main(int argc, char *argv[])
logger_stdout_level--; logger_stdout_level--;
} }
ret = hostapd_setup_interface_start(interfaces.iface[i], ret = hostapd_setup_interface(interfaces.iface[i]);
setup_interface_done);
if (ret) if (ret)
goto out; goto out;
@ -2047,7 +1911,6 @@ int main(int argc, char *argv[])
for (i = 0; i < interfaces.count; i++) { for (i = 0; i < interfaces.count; i++) {
if (!interfaces.iface[i]) if (!interfaces.iface[i])
continue; continue;
hostapd_setup_interface_stop(interfaces.iface[i]);
hostapd_cleanup_iface_pre(interfaces.iface[i]); hostapd_cleanup_iface_pre(interfaces.iface[i]);
for (j = 0; j < interfaces.iface[i]->num_bss; j++) { for (j = 0; j < interfaces.iface[i]->num_bss; j++) {
struct hostapd_data *hapd = struct hostapd_data *hapd =

View File

@ -1,7 +1,7 @@
/* /*
* hostapd / Initialization and configuration * hostapd / Initialization and configuration
* Host AP kernel driver * Host AP kernel driver
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007-2008, Intel Corporation * Copyright (c) 2007-2008, Intel Corporation
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -172,16 +172,6 @@ struct hostapd_data {
}; };
/**
* hostapd_iface_cb - Generic callback type for per-iface asynchronous requests
* @iface: the interface the event occured on.
* @status: 0 if the request succeeded; -1 if the request failed.
*/
typedef void (*hostapd_iface_cb)(struct hostapd_iface *iface, int status);
struct hostapd_config_change;
/** /**
* struct hostapd_iface - hostapd per-interface data structure * struct hostapd_iface - hostapd per-interface data structure
*/ */
@ -189,8 +179,6 @@ struct hostapd_iface {
char *config_fname; char *config_fname;
struct hostapd_config *conf; struct hostapd_config *conf;
hostapd_iface_cb setup_cb;
size_t num_bss; size_t num_bss;
struct hostapd_data **bss; struct hostapd_data **bss;
@ -206,7 +194,6 @@ struct hostapd_iface {
* current_mode->channels */ * current_mode->channels */
int num_rates; int num_rates;
struct hostapd_rate_data *current_rates; struct hostapd_rate_data *current_rates;
hostapd_iface_cb hw_mode_sel_cb;
u16 hw_flags; u16 hw_flags;

View File

@ -2,6 +2,7 @@
* hostapd / Hardware feature query and different modes * hostapd / Hardware feature query and different modes
* Copyright 2002-2003, Instant802 Networks, Inc. * Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -19,7 +20,6 @@
#include "hw_features.h" #include "hw_features.h"
#include "driver.h" #include "driver.h"
#include "config.h" #include "config.h"
#include "eloop.h"
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@ -169,111 +169,17 @@ static int hostapd_prepare_rates(struct hostapd_data *hapd,
} }
static void select_hw_mode_start(void *eloop_data, void *user_ctx);
static void select_hw_mode2_handler(void *eloop_data, void *user_ctx);
/** /**
* select_hw_mode_finalize - Finish select HW mode & call the callback * hostapd_select_hw_mode - Select the hardware mode
* @iface: Pointer to interface data. * @iface: Pointer to interface data.
* @status: Status of the select HW mode (0 on success; -1 on failure). * Returns: 0 on success, -1 on failure
* Returns: 0 on success; -1 on failure (e.g., was not in progress).
*/
static int select_hw_mode_finalize(struct hostapd_iface *iface, int status)
{
hostapd_iface_cb cb;
if (!iface->hw_mode_sel_cb)
return -1;
eloop_cancel_timeout(select_hw_mode_start, iface, NULL);
eloop_cancel_timeout(select_hw_mode2_handler, iface, NULL);
cb = iface->hw_mode_sel_cb;
iface->hw_mode_sel_cb = NULL;
cb(iface, status);
return 0;
}
/**
* select_hw_mode2 - Select the hardware mode (part 2)
* @iface: Pointer to interface data.
* @status: Status of auto chanel selection.
* *
* Setup the rates and passive scanning based on the configuration. * Sets up the hardware mode, channel, rates, and passive scanning
* based on the configuration.
*/ */
static void select_hw_mode2(struct hostapd_iface *iface, int status) int hostapd_select_hw_mode(struct hostapd_iface *iface)
{ {
int ret = status; int i, j, ok, ret;
if (ret)
goto fail;
if (iface->current_mode == NULL) {
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Hardware does not support configured channel");
ret = -1;
goto fail;
}
if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) {
wpa_printf(MSG_ERROR, "Failed to prepare rates table.");
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Failed to prepare rates table.");
ret = -1;
goto fail;
}
ret = hostapd_passive_scan(iface->bss[0], 0,
iface->conf->passive_scan_mode,
iface->conf->passive_scan_interval,
iface->conf->passive_scan_listen,
NULL, NULL);
if (ret) {
if (ret == -1) {
wpa_printf(MSG_DEBUG, "Passive scanning not "
"supported");
} else {
wpa_printf(MSG_ERROR, "Could not set passive "
"scanning: %s", strerror(ret));
}
ret = 0;
}
fail:
select_hw_mode_finalize(iface, ret);
}
/**
* select_hw_mode2_handler - Calls select_hw_mode2 when auto chan isn't used
* @eloop_data: Stores the struct hostapd_iface * for the interface.
* @user_ctx: Unused.
*/
static void select_hw_mode2_handler(void *eloop_data, void *user_ctx)
{
struct hostapd_iface *iface = eloop_data;
select_hw_mode2(iface, 0);
}
/**
* select_hw_mode1 - Select the hardware mode (part 1)
* @iface: Pointer to interface data.
* Returns: 0 on success; -1 on failure.
*
* Setup the hardware mode and channel based on the configuration.
* Schedules select_hw_mode2() to be called immediately or after automatic
* channel selection takes place.
*/
static int select_hw_mode1(struct hostapd_iface *iface)
{
int i, j, ok;
if (iface->num_hw_features < 1) if (iface->num_hw_features < 1)
return -1; return -1;
@ -319,72 +225,38 @@ static int select_hw_mode1(struct hostapd_iface *iface)
iface->current_mode = NULL; iface->current_mode = NULL;
} }
/* if (iface->current_mode == NULL) {
* Calls select_hw_mode2() via a handler, so that the function is hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
* always executed from eloop. HOSTAPD_LEVEL_WARNING,
*/ "Hardware does not support configured channel");
eloop_register_timeout(0, 0, select_hw_mode2_handler, iface, NULL);
return 0;
}
/**
* select_hw_mode_start - Handler to start select HW mode
* @eloop_data: Stores the struct hostapd_iface * for the interface.
* @user_ctx: Unused.
*
* An eloop handler is used so that all errors can be processed by the
* callback without introducing stack recursion.
*/
static void select_hw_mode_start(void *eloop_data, void *user_ctx)
{
struct hostapd_iface *iface = (struct hostapd_iface *)eloop_data;
int ret;
ret = select_hw_mode1(iface);
if (ret)
select_hw_mode_finalize(iface, ret);
}
/**
* hostapd_select_hw_mode_start - Start selection of the hardware mode
* @iface: Pointer to interface data.
* @cb: The function to callback when done.
* Returns: 0 if it starts successfully; cb will be called when done.
* -1 on failure; cb will not be called.
*
* Sets up the hardware mode, channel, rates, and passive scanning
* based on the configuration.
*/
int hostapd_select_hw_mode_start(struct hostapd_iface *iface,
hostapd_iface_cb cb)
{
if (iface->hw_mode_sel_cb) {
wpa_printf(MSG_DEBUG,
"%s: Hardware mode select already in progress.",
iface->bss[0]->conf->iface);
return -1; return -1;
} }
iface->hw_mode_sel_cb = cb; if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) {
wpa_printf(MSG_ERROR, "Failed to prepare rates table.");
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Failed to prepare rates table.");
return -1;
}
eloop_register_timeout(0, 0, select_hw_mode_start, iface, NULL); ret = hostapd_passive_scan(iface->bss[0], 0,
iface->conf->passive_scan_mode,
iface->conf->passive_scan_interval,
iface->conf->passive_scan_listen,
NULL, NULL);
if (ret) {
if (ret == -1) {
wpa_printf(MSG_DEBUG, "Passive scanning not "
"supported");
} else {
wpa_printf(MSG_ERROR, "Could not set passive "
"scanning: %s", strerror(ret));
}
ret = 0;
}
return 0; return ret;
}
/**
* hostapd_auto_chan_select_stop - Stops automatic channel selection
* @iface: Pointer to interface data.
* Returns: 0 if successfully stopped;
* -1 on failure (i.e., was not in progress)
*/
int hostapd_select_hw_mode_stop(struct hostapd_iface *iface)
{
return select_hw_mode_finalize(iface, -1);
} }

View File

@ -52,9 +52,7 @@ struct hostapd_hw_modes {
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
size_t num_hw_features); size_t num_hw_features);
int hostapd_get_hw_features(struct hostapd_iface *iface); int hostapd_get_hw_features(struct hostapd_iface *iface);
int hostapd_select_hw_mode_start(struct hostapd_iface *iface, int hostapd_select_hw_mode(struct hostapd_iface *iface);
hostapd_iface_cb cb);
int hostapd_select_hw_mode_stop(struct hostapd_iface *iface);
const char * hostapd_hw_mode_txt(int mode); const char * hostapd_hw_mode_txt(int mode);
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan); int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq); int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);