Cumulative patch from commit d4f1a347ceca31fd9cf14070fd000235d5f4e9c1
d4f1a34 Allow AP mode configuration with VHT enabled on 2.4 GHz
bb337dd DFS: Do not use cf1 to override freq for 20 MHz channels
0dfd2c6 Document AP mode startup functions
fee947b hostapd: Use correct wpa_printf verbosity level for message
2fe210c hostapd: Fix multi-BSS configuration file parsing regression
e4ba031 hostapd: Use start_ctrl_iface() from hostapd_add_iface()
bf7f09b Fix AP mode QoS Map configuration to be per-BSS
dc036d9 DFS: Convert hostapd_data use to hostapd_iface
2db938e hostapd: Fill in phyname automatically
5ae6449 hostapd: Add ctrl_iface STATUS command
afadaff Optimize 40 MHz HT co-ex scan on AP
7d6d737 hostapd: Add AP-ENABLED/DISABLED ctrl_iface events
e1c5faf hostapd: Track interface state
f0793bf hostapd: Wait for channel list update after country code change
ae134e1 hostapd: Add ctrl_iface events for ACS
ad08e14 hostapd: Move ctrl_iface initialization to happen earlier
c20cb02 hostapd: Remove hostapd_interface_init2()
4a5deb9 hostapd: Simplify interface initialization
186c905 DFS: Add control interface events for various DFS events
ddf5517 hostapd: Add control interface test commands for radar detection
884f1a3 nl80211: Verify radar event attributes exist before using them
71cdf6b hostapd: Fix ENABLE failure to not remove interface
18ca733 SAE: Fix group selection
65015b2 Replace unnecessary UTF-8 characters with ASCII versions
61323e7 Convert perror/printf calls to wpa_printf
3f134b4 hostapd: Accept RELOG from global control interface
b253e6f hostapd: Use wpa_printf() for hostapd_logger() to stdout
c092d83 P2P: Clear pending group formation data on group removal
9100b66 P2P: Debug print reason for specific SSID for scan
2aec4f3 Allow add-BSS operation to re-use existing netdev
5592065 hostapd: Allow a single BSS to be removed from an interface
2e2fff3 hostapd: Allow a single BSS to be added to an interface
a1fb569 hostapd: Make hostapd_interface_init_bss() available externally
66936c6 hostapd: Make hostapd_init() available externally
390e489 hostapd: Allow the first BSS in a multi-BSS setup to be removed
834ee56 nl80211: Make wpa_driver_nl80211_data::first_bss pointer
748c0ac nl80211: Fix monitor interface reference counting
08e55eb nl80211: Add a debug print for DEL_BEACON
33b0b33 hostapd: Fix error path in hostapd_add_iface()
770ecdf ACS: Do not get stuck while failing to do a subsequent scan
813d4ba DFS: Add support for multi-BSS
954e71d DFS: Reset cac_started properly
6a398dd DFS: Sanitize channel availability checks
32595da DFS: Fix HT40/VHT calculation
0648c3b hostapd: Add -T Linux tracing option
392e68e Set GTK rekey offload information after initial group key handshake
bbc706a nl80211: Add debug prints for NL80211_CMD_SET_STATION
731ca63 Update regulatory change to all virtual interface for the phy
6f2db2f hostapd: Validate configuration parameters on RELOAD command
eff0fd1 hostapd: Move generic configuration functions into src/ap
5afaa06 hostapd: Allow per-BSS (vif) configuration files
ebd79f0 hostapd: Make hostapd_config::bss array of pointers
a781e21 hostapd: Force PSK to be derived again on BSS reload
9f104b0 hostapd: Reuse hostapd_clear_old() for RELOAD command
Change-Id: I7fbb26cbd4a2960af66a4373c0e6bbe5390a4940
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 3bca385..5d51c77 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1,6 +1,6 @@
/*
* hostapd / Initialization and configuration
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "radius/radius_client.h"
#include "radius/radius_das.h"
#include "drivers/driver.h"
@@ -38,6 +39,8 @@
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
+static int setup_interface2(struct hostapd_iface *iface);
+static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
extern int wpa_debug_level;
extern struct wpa_driver_ops *wpa_drivers[];
@@ -62,10 +65,22 @@
static void hostapd_reload_bss(struct hostapd_data *hapd)
{
+ struct hostapd_ssid *ssid;
+
#ifndef CONFIG_NO_RADIUS
radius_client_reconfig(hapd->radius, hapd->conf->radius);
#endif /* CONFIG_NO_RADIUS */
+ ssid = &hapd->conf->ssid;
+ if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next &&
+ ssid->wpa_passphrase_set && ssid->wpa_passphrase) {
+ /*
+ * Force PSK to be derived again since SSID or passphrase may
+ * have changed.
+ */
+ os_free(ssid->wpa_psk);
+ ssid->wpa_psk = NULL;
+ }
if (hostapd_setup_wpa_psk(hapd->conf)) {
wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
"after reloading configuration");
@@ -160,7 +175,7 @@
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
hapd->iconf = newconf;
- hapd->conf = &newconf->bss[j];
+ hapd->conf = newconf->bss[j];
hostapd_reload_bss(hapd);
}
@@ -245,8 +260,7 @@
authsrv_deinit(hapd);
- if (hapd->interface_added &&
- hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
+ if (hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s",
hapd->conf->iface);
}
@@ -326,6 +340,8 @@
*/
static void hostapd_cleanup_iface(struct hostapd_iface *iface)
{
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+
hostapd_cleanup_iface_partial(iface);
hostapd_config_free(iface->conf);
iface->conf = NULL;
@@ -430,7 +446,7 @@
/* Determine the bits necessary to any configured BSSIDs,
if they are higher than the number of BSSIDs. */
for (j = 0; j < iface->conf->num_bss; j++) {
- if (hostapd_mac_comp_empty(iface->conf->bss[j].bssid) == 0) {
+ if (hostapd_mac_comp_empty(iface->conf->bss[j]->bssid) == 0) {
if (j)
auto_addr++;
continue;
@@ -438,7 +454,7 @@
for (i = 0; i < ETH_ALEN; i++) {
mask[i] |=
- iface->conf->bss[j].bssid[i] ^
+ iface->conf->bss[j]->bssid[i] ^
hapd->own_addr[i];
}
}
@@ -503,7 +519,7 @@
size_t i;
for (i = 0; i < conf->num_bss; i++) {
- if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) {
+ if (hostapd_mac_comp(conf->bss[i]->bssid, a) == 0) {
return 1;
}
}
@@ -597,7 +613,8 @@
/**
* hostapd_setup_bss - Per-BSS setup (initialization)
* @hapd: Pointer to BSS data
- * @first: Whether this BSS is the first BSS of an interface
+ * @first: Whether this BSS is the first BSS of an interface; -1 = not first,
+ * but interface may exist
*
* This function is used to initialize all per-BSS data structures and
* resources. This gets called in a loop for each BSS when an interface is
@@ -612,7 +629,7 @@
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
- if (!first) {
+ if (!first || first == -1) {
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
/* Allocate the next available BSSID. */
do {
@@ -632,12 +649,11 @@
}
}
- hapd->interface_added = 1;
if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
hapd->conf->iface, hapd->own_addr, hapd,
&hapd->drv_priv, force_ifname, if_addr,
hapd->conf->bridge[0] ? hapd->conf->bridge :
- NULL)) {
+ NULL, first == -1)) {
wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
MACSTR ")", MAC2STR(hapd->own_addr));
return -1;
@@ -769,14 +785,14 @@
wpa_printf(MSG_ERROR, "GAS server initialization failed");
return -1;
}
-#endif /* CONFIG_INTERWORKING */
- if (hapd->iface->interfaces &&
- hapd->iface->interfaces->ctrl_iface_init &&
- hapd->iface->interfaces->ctrl_iface_init(hapd)) {
- wpa_printf(MSG_ERROR, "Failed to setup control interface");
+ if (conf->qos_map_set_len &&
+ hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
+ conf->qos_map_set_len)) {
+ wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
return -1;
}
+#endif /* CONFIG_INTERWORKING */
if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
wpa_printf(MSG_ERROR, "VLAN initialization failed.");
@@ -850,14 +866,15 @@
if (hapd->iface->drv_max_acl_mac_addrs == 0)
return;
- if (!(conf->bss->num_accept_mac || conf->bss->num_deny_mac))
+ if (!(conf->bss[0]->num_accept_mac || conf->bss[0]->num_deny_mac))
return;
- if (conf->bss->macaddr_acl == DENY_UNLESS_ACCEPTED) {
- if (conf->bss->num_accept_mac) {
+ if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) {
+ if (conf->bss[0]->num_accept_mac) {
accept_acl = 1;
- err = hostapd_set_acl_list(hapd, conf->bss->accept_mac,
- conf->bss->num_accept_mac,
+ err = hostapd_set_acl_list(hapd,
+ conf->bss[0]->accept_mac,
+ conf->bss[0]->num_accept_mac,
accept_acl);
if (err) {
wpa_printf(MSG_DEBUG, "Failed to set accept acl");
@@ -866,11 +883,11 @@
} else {
wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file");
}
- } else if (conf->bss->macaddr_acl == ACCEPT_UNLESS_DENIED) {
- if (conf->bss->num_deny_mac) {
+ } else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) {
+ if (conf->bss[0]->num_deny_mac) {
accept_acl = 0;
- err = hostapd_set_acl_list(hapd, conf->bss->deny_mac,
- conf->bss->num_deny_mac,
+ err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac,
+ conf->bss[0]->num_deny_mac,
accept_acl);
if (err) {
wpa_printf(MSG_DEBUG, "Failed to set deny acl");
@@ -883,11 +900,85 @@
}
+static int start_ctrl_iface_bss(struct hostapd_data *hapd)
+{
+ if (!hapd->iface->interfaces ||
+ !hapd->iface->interfaces->ctrl_iface_init)
+ return 0;
+
+ if (hapd->iface->interfaces->ctrl_iface_init(hapd)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to setup control interface for %s",
+ hapd->conf->iface);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int start_ctrl_iface(struct hostapd_iface *iface)
+{
+ size_t i;
+
+ if (!iface->interfaces || !iface->interfaces->ctrl_iface_init)
+ return 0;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *hapd = iface->bss[i];
+ if (iface->interfaces->ctrl_iface_init(hapd)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to setup control interface for %s",
+ hapd->conf->iface);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_iface *iface = eloop_ctx;
+
+ if (!iface->wait_channel_update) {
+ wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it");
+ return;
+ }
+
+ /*
+ * It is possible that the existing channel list is acceptable, so try
+ * to proceed.
+ */
+ wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway");
+ setup_interface2(iface);
+}
+
+
+void hostapd_channel_list_updated(struct hostapd_iface *iface)
+{
+ if (!iface->wait_channel_update)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Channel list updated - continue setup");
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ setup_interface2(iface);
+}
+
+
static int setup_interface(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
size_t i;
- char country[4];
+
+ if (!iface->phy[0]) {
+ const char *phy = hostapd_drv_get_radio_name(hapd);
+ if (phy) {
+ wpa_printf(MSG_DEBUG, "phy: %s", phy);
+ os_strlcpy(iface->phy, phy, sizeof(iface->phy));
+ }
+ }
/*
* Make sure that all BSSes get configured with a pointer to the same
@@ -901,15 +992,49 @@
if (hostapd_validate_bssid_configuration(iface))
return -1;
+ /*
+ * Initialize control interfaces early to allow external monitoring of
+ * channel setup operations that may take considerable amount of time
+ * especially for DFS cases.
+ */
+ if (start_ctrl_iface(iface))
+ return -1;
+
if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
+ char country[4], previous_country[4];
+
+ hostapd_set_state(iface, HAPD_IFACE_COUNTRY_UPDATE);
+ if (hostapd_get_country(hapd, previous_country) < 0)
+ previous_country[0] = '\0';
+
os_memcpy(country, hapd->iconf->country, 3);
country[3] = '\0';
if (hostapd_set_country(hapd, country) < 0) {
wpa_printf(MSG_ERROR, "Failed to set country code");
return -1;
}
+
+ wpa_printf(MSG_DEBUG, "Previous country code %s, new country code %s",
+ previous_country, country);
+
+ if (os_strncmp(previous_country, country, 2) != 0) {
+ wpa_printf(MSG_DEBUG, "Continue interface setup after channel list update");
+ iface->wait_channel_update = 1;
+ eloop_register_timeout(1, 0,
+ channel_list_update_timeout,
+ iface, NULL);
+ return 0;
+ }
}
+ return setup_interface2(iface);
+}
+
+
+static int setup_interface2(struct hostapd_iface *iface)
+{
+ iface->wait_channel_update = 0;
+
if (hostapd_get_hw_features(iface)) {
/* Not all drivers support this yet, so continue without hw
* feature data. */
@@ -940,6 +1065,14 @@
}
+/**
+ * hostapd_setup_interface_complete - Complete interface setup
+ *
+ * This function is called when previous steps in the interface setup has been
+ * completed. This can also start operations, e.g., DFS, that will require
+ * additional processing before interface is ready to be enabled. Such
+ * operations will call this function from eloop callbacks when finished.
+ */
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
{
struct hostapd_data *hapd = iface->bss[0];
@@ -948,25 +1081,26 @@
if (err) {
wpa_printf(MSG_ERROR, "Interface initialization failed");
+ hostapd_set_state(iface, HAPD_IFACE_DISABLED);
eloop_terminate();
return -1;
}
wpa_printf(MSG_DEBUG, "Completing interface initialization");
- if (hapd->iconf->channel) {
+ if (iface->conf->channel) {
#ifdef NEED_AP_MLME
int res;
#endif /* NEED_AP_MLME */
- iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
+ iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
"Frequency: %d MHz",
- hostapd_hw_mode_txt(hapd->iconf->hw_mode),
- hapd->iconf->channel, iface->freq);
+ hostapd_hw_mode_txt(iface->conf->hw_mode),
+ iface->conf->channel, iface->freq);
#ifdef NEED_AP_MLME
/* Check DFS */
- res = hostapd_handle_dfs(hapd);
+ res = hostapd_handle_dfs(iface);
if (res <= 0)
return res;
#endif /* NEED_AP_MLME */
@@ -1021,6 +1155,7 @@
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
prev_addr = hapd->own_addr;
}
+ hapd = iface->bss[0];
hostapd_tx_queue_params(iface);
@@ -1045,6 +1180,8 @@
return -1;
}
+ hostapd_set_state(iface, HAPD_IFACE_ENABLED);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
if (hapd->setup_complete_cb)
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
@@ -1064,6 +1201,12 @@
* and sets driver parameters based on the configuration.
* Flushes old stations, sets the channel, encryption,
* beacons, and WDS links based on the configuration.
+ *
+ * If interface setup requires more time, e.g., to perform HT co-ex scans, ACS,
+ * or DFS operations, this function returns 0 before such operations have been
+ * completed. The pending operations are registered into eloop and will be
+ * completed from eloop callbacks. Those callbacks end up calling
+ * hostapd_setup_interface_complete() once setup has been completed.
*/
int hostapd_setup_interface(struct hostapd_iface *iface)
{
@@ -1115,13 +1258,16 @@
void hostapd_interface_deinit(struct hostapd_iface *iface)
{
- size_t j;
+ int j;
if (iface == NULL)
return;
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ iface->wait_channel_update = 0;
+
hostapd_cleanup_iface_pre(iface);
- for (j = 0; j < iface->num_bss; j++) {
+ for (j = iface->num_bss - 1; j >= 0; j--) {
struct hostapd_data *hapd = iface->bss[j];
hostapd_free_stas(hapd);
hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
@@ -1140,7 +1286,200 @@
}
-#ifdef HOSTAPD
+/**
+ * hostapd_init - Allocate and initialize per-interface data
+ * @config_file: Path to the configuration file
+ * Returns: Pointer to the allocated interface data or %NULL on failure
+ *
+ * This function is used to allocate main data structures for per-interface
+ * data. The allocated data buffer will be freed by calling
+ * hostapd_cleanup_iface().
+ */
+struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
+ const char *config_file)
+{
+ struct hostapd_iface *hapd_iface = NULL;
+ struct hostapd_config *conf = NULL;
+ struct hostapd_data *hapd;
+ size_t i;
+
+ hapd_iface = os_zalloc(sizeof(*hapd_iface));
+ if (hapd_iface == NULL)
+ goto fail;
+
+ hapd_iface->config_fname = os_strdup(config_file);
+ if (hapd_iface->config_fname == NULL)
+ goto fail;
+
+ conf = interfaces->config_read_cb(hapd_iface->config_fname);
+ if (conf == NULL)
+ goto fail;
+ hapd_iface->conf = conf;
+
+ hapd_iface->num_bss = conf->num_bss;
+ hapd_iface->bss = os_calloc(conf->num_bss,
+ sizeof(struct hostapd_data *));
+ if (hapd_iface->bss == NULL)
+ goto fail;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ hapd = hapd_iface->bss[i] =
+ hostapd_alloc_bss_data(hapd_iface, conf,
+ conf->bss[i]);
+ if (hapd == NULL)
+ goto fail;
+ hapd->msg_ctx = hapd;
+ }
+
+ return hapd_iface;
+
+fail:
+ wpa_printf(MSG_ERROR, "Failed to set up interface with %s",
+ config_file);
+ if (conf)
+ hostapd_config_free(conf);
+ if (hapd_iface) {
+ os_free(hapd_iface->config_fname);
+ os_free(hapd_iface->bss);
+ os_free(hapd_iface);
+ }
+ return NULL;
+}
+
+
+static int ifname_in_use(struct hapd_interfaces *interfaces, const char *ifname)
+{
+ size_t i, j;
+
+ for (i = 0; i < interfaces->count; i++) {
+ struct hostapd_iface *iface = interfaces->iface[i];
+ for (j = 0; j < iface->num_bss; j++) {
+ struct hostapd_data *hapd = iface->bss[j];
+ if (os_strcmp(ifname, hapd->conf->iface) == 0)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * hostapd_interface_init_bss - Read configuration file and init BSS data
+ *
+ * This function is used to parse configuration file for a BSS. This BSS is
+ * added to an existing interface sharing the same radio (if any) or a new
+ * interface is created if this is the first interface on a radio. This
+ * allocate memory for the BSS. No actual driver operations are started.
+ *
+ * This is similar to hostapd_interface_init(), but for a case where the
+ * configuration is used to add a single BSS instead of all BSSes for a radio.
+ */
+struct hostapd_iface *
+hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+ const char *config_fname, int debug)
+{
+ struct hostapd_iface *new_iface = NULL, *iface = NULL;
+ struct hostapd_data *hapd;
+ int k;
+ size_t i, bss_idx;
+
+ if (!phy || !*phy)
+ return NULL;
+
+ for (i = 0; i < interfaces->count; i++) {
+ if (os_strcmp(interfaces->iface[i]->phy, phy) == 0) {
+ iface = interfaces->iface[i];
+ break;
+ }
+ }
+
+ wpa_printf(MSG_INFO, "Configuration file: %s (phy %s)%s",
+ config_fname, phy, iface ? "" : " --> new PHY");
+ if (iface) {
+ struct hostapd_config *conf;
+ struct hostapd_bss_config **tmp_conf;
+ struct hostapd_data **tmp_bss;
+ struct hostapd_bss_config *bss;
+ const char *ifname;
+
+ /* Add new BSS to existing iface */
+ conf = interfaces->config_read_cb(config_fname);
+ if (conf == NULL)
+ return NULL;
+ if (conf->num_bss > 1) {
+ wpa_printf(MSG_ERROR, "Multiple BSSes specified in BSS-config");
+ hostapd_config_free(conf);
+ return NULL;
+ }
+
+ ifname = conf->bss[0]->iface;
+ if (ifname[0] != '\0' && ifname_in_use(interfaces, ifname)) {
+ wpa_printf(MSG_ERROR,
+ "Interface name %s already in use", ifname);
+ hostapd_config_free(conf);
+ return NULL;
+ }
+
+ tmp_conf = os_realloc_array(
+ iface->conf->bss, iface->conf->num_bss + 1,
+ sizeof(struct hostapd_bss_config *));
+ tmp_bss = os_realloc_array(iface->bss, iface->num_bss + 1,
+ sizeof(struct hostapd_data *));
+ if (tmp_bss)
+ iface->bss = tmp_bss;
+ if (tmp_conf) {
+ iface->conf->bss = tmp_conf;
+ iface->conf->last_bss = tmp_conf[0];
+ }
+ if (tmp_bss == NULL || tmp_conf == NULL) {
+ hostapd_config_free(conf);
+ return NULL;
+ }
+ bss = iface->conf->bss[iface->conf->num_bss] = conf->bss[0];
+ iface->conf->num_bss++;
+
+ hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
+ if (hapd == NULL) {
+ iface->conf->num_bss--;
+ hostapd_config_free(conf);
+ return NULL;
+ }
+ iface->conf->last_bss = bss;
+ iface->bss[iface->num_bss] = hapd;
+ hapd->msg_ctx = hapd;
+
+ bss_idx = iface->num_bss++;
+ conf->num_bss--;
+ conf->bss[0] = NULL;
+ hostapd_config_free(conf);
+ } else {
+ /* Add a new iface with the first BSS */
+ new_iface = iface = hostapd_init(interfaces, config_fname);
+ if (!iface)
+ return NULL;
+ os_strlcpy(iface->phy, phy, sizeof(iface->phy));
+ iface->interfaces = interfaces;
+ bss_idx = 0;
+ }
+
+ for (k = 0; k < debug; k++) {
+ if (iface->bss[bss_idx]->conf->logger_stdout_level > 0)
+ iface->bss[bss_idx]->conf->logger_stdout_level--;
+ }
+
+ if (iface->conf->bss[bss_idx]->iface[0] == '\0' &&
+ !hostapd_drv_none(iface->bss[bss_idx])) {
+ wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+ config_fname);
+ if (new_iface)
+ hostapd_interface_deinit_free(new_iface);
+ return NULL;
+ }
+
+ return iface;
+}
+
void hostapd_interface_deinit_free(struct hostapd_iface *iface)
{
@@ -1161,20 +1500,31 @@
{
if (hapd_iface->bss[0]->drv_priv != NULL) {
wpa_printf(MSG_ERROR, "Interface %s already enabled",
- hapd_iface->conf->bss[0].iface);
+ hapd_iface->conf->bss[0]->iface);
return -1;
}
wpa_printf(MSG_DEBUG, "Enable interface %s",
- hapd_iface->conf->bss[0].iface);
+ hapd_iface->conf->bss[0]->iface);
if (hapd_iface->interfaces == NULL ||
hapd_iface->interfaces->driver_init == NULL ||
- hapd_iface->interfaces->driver_init(hapd_iface) ||
- hostapd_setup_interface(hapd_iface)) {
- hostapd_interface_deinit_free(hapd_iface);
+ hapd_iface->interfaces->driver_init(hapd_iface))
+ return -1;
+
+ if (hostapd_setup_interface(hapd_iface)) {
+ const struct wpa_driver_ops *driver;
+ void *drv_priv;
+
+ driver = hapd_iface->bss[0]->driver;
+ drv_priv = hapd_iface->bss[0]->drv_priv;
+ if (driver && driver->hapd_deinit && drv_priv) {
+ driver->hapd_deinit(drv_priv);
+ hapd_iface->bss[0]->drv_priv = NULL;
+ }
return -1;
}
+
return 0;
}
@@ -1184,19 +1534,17 @@
size_t j;
wpa_printf(MSG_DEBUG, "Reload interface %s",
- hapd_iface->conf->bss[0].iface);
- for (j = 0; j < hapd_iface->num_bss; j++) {
- hostapd_flush_old_stations(hapd_iface->bss[j],
- WLAN_REASON_PREV_AUTH_NOT_VALID);
-
-#ifndef CONFIG_NO_RADIUS
- /* TODO: update dynamic data based on changed configuration
- * items (e.g., open/close sockets, etc.) */
- radius_client_flush(hapd_iface->bss[j]->radius, 0);
-#endif /* CONFIG_NO_RADIUS */
-
- hostapd_reload_bss(hapd_iface->bss[j]);
+ hapd_iface->conf->bss[0]->iface);
+ for (j = 0; j < hapd_iface->num_bss; j++)
+ hostapd_set_security_params(hapd_iface->conf->bss[j]);
+ if (hostapd_config_check(hapd_iface->conf) < 0) {
+ wpa_printf(MSG_ERROR, "Updated configuration is invalid");
+ return -1;
}
+ hostapd_clear_old(hapd_iface);
+ for (j = 0; j < hapd_iface->num_bss; j++)
+ hostapd_reload_bss(hapd_iface->bss[j]);
+
return 0;
}
@@ -1209,6 +1557,7 @@
if (hapd_iface == NULL)
return -1;
+ wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
driver = hapd_iface->bss[0]->driver;
drv_priv = hapd_iface->bss[0]->drv_priv;
@@ -1233,6 +1582,7 @@
wpa_printf(MSG_DEBUG, "Interface %s disabled",
hapd_iface->bss[0]->conf->iface);
+ hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED);
return 0;
}
@@ -1283,7 +1633,7 @@
return NULL;
}
- bss = conf->last_bss = conf->bss;
+ bss = conf->last_bss = conf->bss[0];
os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
bss->ctrl_interface = os_strdup(ctrl_iface);
@@ -1318,8 +1668,7 @@
for (i = 0; i < conf->num_bss; i++) {
hapd = hapd_iface->bss[i] =
- hostapd_alloc_bss_data(hapd_iface, conf,
- &conf->bss[i]);
+ hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]);
if (hapd == NULL)
return NULL;
hapd->msg_ctx = hapd;
@@ -1334,10 +1683,69 @@
int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
{
struct hostapd_config *conf = NULL;
- struct hostapd_iface *hapd_iface = NULL;
+ struct hostapd_iface *hapd_iface = NULL, *new_iface = NULL;
+ struct hostapd_data *hapd;
char *ptr;
- size_t i;
- const char *conf_file = NULL;
+ size_t i, j;
+ const char *conf_file = NULL, *phy_name = NULL;
+
+ if (os_strncmp(buf, "bss_config=", 11) == 0) {
+ char *pos;
+ phy_name = buf + 11;
+ pos = os_strchr(phy_name, ':');
+ if (!pos)
+ return -1;
+ *pos++ = '\0';
+ conf_file = pos;
+ if (!os_strlen(conf_file))
+ return -1;
+
+ hapd_iface = hostapd_interface_init_bss(interfaces, phy_name,
+ conf_file, 0);
+ if (!hapd_iface)
+ return -1;
+ for (j = 0; j < interfaces->count; j++) {
+ if (interfaces->iface[j] == hapd_iface)
+ break;
+ }
+ if (j == interfaces->count) {
+ struct hostapd_iface **tmp;
+ tmp = os_realloc_array(interfaces->iface,
+ interfaces->count + 1,
+ sizeof(struct hostapd_iface *));
+ if (!tmp) {
+ hostapd_interface_deinit_free(hapd_iface);
+ return -1;
+ }
+ interfaces->iface = tmp;
+ interfaces->iface[interfaces->count++] = hapd_iface;
+ new_iface = hapd_iface;
+ }
+
+ if (new_iface) {
+ if (interfaces->driver_init(hapd_iface) ||
+ hostapd_setup_interface(hapd_iface)) {
+ interfaces->count--;
+ goto fail;
+ }
+ } else {
+ /* Assign new BSS with bss[0]'s driver info */
+ hapd = hapd_iface->bss[hapd_iface->num_bss - 1];
+ hapd->driver = hapd_iface->bss[0]->driver;
+ hapd->drv_priv = hapd_iface->bss[0]->drv_priv;
+ os_memcpy(hapd->own_addr, hapd_iface->bss[0]->own_addr,
+ ETH_ALEN);
+
+ if (start_ctrl_iface_bss(hapd) < 0 ||
+ hostapd_setup_bss(hapd, -1)) {
+ hapd_iface->conf->num_bss--;
+ hapd_iface->num_bss--;
+ os_free(hapd);
+ return -1;
+ }
+ }
+ return 0;
+ }
ptr = os_strchr(buf, ' ');
if (ptr == NULL)
@@ -1348,7 +1756,7 @@
conf_file = ptr + 7;
for (i = 0; i < interfaces->count; i++) {
- if (!os_strcmp(interfaces->iface[i]->conf->bss[0].iface,
+ if (!os_strcmp(interfaces->iface[i]->conf->bss[0]->iface,
buf)) {
wpa_printf(MSG_INFO, "Cannot add interface - it "
"already exists");
@@ -1366,8 +1774,8 @@
if (conf_file && interfaces->config_read_cb) {
conf = interfaces->config_read_cb(conf_file);
if (conf && conf->bss)
- os_strlcpy(conf->bss->iface, buf,
- sizeof(conf->bss->iface));
+ os_strlcpy(conf->bss[0]->iface, buf,
+ sizeof(conf->bss[0]->iface));
} else
conf = hostapd_config_alloc(interfaces, buf, ptr);
if (conf == NULL || conf->bss == NULL) {
@@ -1383,14 +1791,10 @@
goto fail;
}
- if (hapd_iface->interfaces &&
- hapd_iface->interfaces->ctrl_iface_init &&
- hapd_iface->interfaces->ctrl_iface_init(hapd_iface->bss[0])) {
- wpa_printf(MSG_ERROR, "%s: Failed to setup control "
- "interface", __func__);
+ if (start_ctrl_iface(hapd_iface) < 0)
goto fail;
- }
- wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0].iface);
+
+ wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0]->iface);
return 0;
@@ -1398,23 +1802,57 @@
if (conf)
hostapd_config_free(conf);
if (hapd_iface) {
- os_free(hapd_iface->bss[interfaces->count]);
+ if (hapd_iface->bss) {
+ for (i = 0; i < hapd_iface->num_bss; i++)
+ os_free(hapd_iface->bss[i]);
+ os_free(hapd_iface->bss);
+ }
os_free(hapd_iface);
}
return -1;
}
+static int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx)
+{
+ struct hostapd_data *hapd;
+ size_t i;
+
+ if (idx > iface->num_bss || idx > iface->conf->num_bss)
+ return -1;
+ hapd = iface->bss[idx];
+ wpa_printf(MSG_INFO, "Remove BSS '%s'", hapd->conf->iface);
+
+ hostapd_free_stas(hapd);
+ hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+ hostapd_clear_wep(hapd);
+ hostapd_cleanup(hapd);
+ hostapd_config_free_bss(hapd->conf);
+ os_free(hapd);
+
+ iface->num_bss--;
+ for (i = idx; i < iface->num_bss; i++)
+ iface->bss[i] = iface->bss[i + 1];
+
+ iface->conf->num_bss--;
+ for (i = idx; i < iface->num_bss; i++)
+ iface->conf->bss[i] = iface->conf->bss[i + 1];
+
+ return 0;
+}
+
+
int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
{
struct hostapd_iface *hapd_iface;
- size_t i, k = 0;
+ size_t i, j, k = 0;
for (i = 0; i < interfaces->count; i++) {
hapd_iface = interfaces->iface[i];
if (hapd_iface == NULL)
return -1;
- if (!os_strcmp(hapd_iface->conf->bss[0].iface, buf)) {
+ if (hapd_iface->conf->num_bss == 1 &&
+ !os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
hostapd_interface_deinit_free(hapd_iface);
k = i;
@@ -1426,12 +1864,15 @@
interfaces->count--;
return 0;
}
+
+ for (j = 0; j < hapd_iface->conf->num_bss; j++) {
+ if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf))
+ return hostapd_remove_bss(hapd_iface, j);
+ }
}
return -1;
}
-#endif /* HOSTAPD */
-
/**
* hostapd_new_assoc_sta - Notify that a new station associated with the AP
@@ -1493,3 +1934,35 @@
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
ap_handle_timer, hapd, sta);
}
+
+
+const char * hostapd_state_text(enum hostapd_iface_state s)
+{
+ switch (s) {
+ case HAPD_IFACE_UNINITIALIZED:
+ return "UNINITIALIZED";
+ case HAPD_IFACE_DISABLED:
+ return "DISABLED";
+ case HAPD_IFACE_COUNTRY_UPDATE:
+ return "COUNTRY_UPDATE";
+ case HAPD_IFACE_ACS:
+ return "ACS";
+ case HAPD_IFACE_HT_SCAN:
+ return "HT_SCAN";
+ case HAPD_IFACE_DFS:
+ return "DFS";
+ case HAPD_IFACE_ENABLED:
+ return "ENABLED";
+ }
+
+ return "UNKNOWN";
+}
+
+
+void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
+{
+ wpa_printf(MSG_INFO, "%s: interface state %s->%s",
+ iface->conf->bss[0]->iface, hostapd_state_text(iface->state),
+ hostapd_state_text(s));
+ iface->state = s;
+}