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/accounting.c b/src/ap/accounting.c
index 9540531..a1f67f0 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -44,7 +44,7 @@
 	msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
 			     radius_client_get_id(hapd->radius));
 	if (msg == NULL) {
-		printf("Could not create net RADIUS packet\n");
+		wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
 		return NULL;
 	}
 
@@ -55,7 +55,7 @@
 			    sta->acct_session_id_hi, sta->acct_session_id_lo);
 		if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
 					 (u8 *) buf, os_strlen(buf))) {
-			printf("Could not add Acct-Session-Id\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Session-Id");
 			goto fail;
 		}
 	} else {
@@ -64,7 +64,7 @@
 
 	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
 				       status_type)) {
-		printf("Could not add Acct-Status-Type\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Status-Type");
 		goto fail;
 	}
 
@@ -74,7 +74,7 @@
 				       hapd->conf->ieee802_1x ?
 				       RADIUS_ACCT_AUTHENTIC_RADIUS :
 				       RADIUS_ACCT_AUTHENTIC_LOCAL)) {
-		printf("Could not add Acct-Authentic\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
 		goto fail;
 	}
 
@@ -99,7 +99,7 @@
 
 		if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
 					 len)) {
-			printf("Could not add User-Name\n");
+			wpa_printf(MSG_INFO, "Could not add User-Name");
 			goto fail;
 		}
 	}
@@ -117,7 +117,7 @@
 
 			if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
 						 val, len)) {
-				printf("Could not add Class\n");
+				wpa_printf(MSG_INFO, "Could not add Class");
 				goto fail;
 			}
 		}
@@ -254,14 +254,14 @@
 			     stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
 			     RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
 	if (!msg) {
-		printf("Could not create RADIUS Accounting message\n");
+		wpa_printf(MSG_INFO, "Could not create RADIUS Accounting message");
 		return;
 	}
 
 	os_get_time(&now);
 	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
 				       now.sec - sta->acct_session_start)) {
-		printf("Could not add Acct-Session-Time\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Session-Time");
 		goto fail;
 	}
 
@@ -269,19 +269,19 @@
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_INPUT_PACKETS,
 					       data.rx_packets)) {
-			printf("Could not add Acct-Input-Packets\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Input-Packets");
 			goto fail;
 		}
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
 					       data.tx_packets)) {
-			printf("Could not add Acct-Output-Packets\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
 			goto fail;
 		}
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_INPUT_OCTETS,
 					       data.rx_bytes)) {
-			printf("Could not add Acct-Input-Octets\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets");
 			goto fail;
 		}
 		gigawords = sta->acct_input_gigawords;
@@ -292,13 +292,13 @@
 		    !radius_msg_add_attr_int32(
 			    msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
 			    gigawords)) {
-			printf("Could not add Acct-Input-Gigawords\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
 			goto fail;
 		}
 		if (!radius_msg_add_attr_int32(msg,
 					       RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
 					       data.tx_bytes)) {
-			printf("Could not add Acct-Output-Octets\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets");
 			goto fail;
 		}
 		gigawords = sta->acct_output_gigawords;
@@ -309,14 +309,14 @@
 		    !radius_msg_add_attr_int32(
 			    msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
 			    gigawords)) {
-			printf("Could not add Acct-Output-Gigawords\n");
+			wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords");
 			goto fail;
 		}
 	}
 
 	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
 				       now.sec)) {
-		printf("Could not add Event-Timestamp\n");
+		wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
 		goto fail;
 	}
 
@@ -326,7 +326,7 @@
 	if (stop && cause &&
 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
 				       cause)) {
-		printf("Could not add Acct-Terminate-Cause\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
 		goto fail;
 	}
 
@@ -400,13 +400,12 @@
 		   void *data)
 {
 	if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
-		printf("Unknown RADIUS message code\n");
+		wpa_printf(MSG_INFO, "Unknown RADIUS message code");
 		return RADIUS_RX_UNKNOWN;
 	}
 
 	if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
-		printf("Incoming RADIUS packet did not have correct "
-		       "Authenticator - dropped\n");
+		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Authenticator - dropped");
 		return RADIUS_RX_INVALID_AUTHENTICATOR;
 	}
 
@@ -432,7 +431,7 @@
 	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
 				       RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
 	{
-		printf("Could not add Acct-Terminate-Cause\n");
+		wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
 		radius_msg_free(msg);
 		return;
 	}
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 019b334..9ef221e 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -13,6 +13,7 @@
 #include "utils/common.h"
 #include "utils/list.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "drivers/driver.h"
 #include "hostapd.h"
 #include "ap_drv_ops.h"
@@ -729,14 +730,17 @@
 		err = acs_request_scan(iface);
 		if (err) {
 			wpa_printf(MSG_ERROR, "ACS: Failed to request scan");
-			acs_fail(iface);
-			return;
+			goto fail;
 		}
 
 		return;
 	}
 
 	acs_study(iface);
+	return;
+fail:
+	hostapd_acs_completed(iface, 1);
+	acs_fail(iface);
 }
 
 
@@ -791,5 +795,8 @@
 	if (err < 0)
 		return HOSTAPD_CHAN_INVALID;
 
+	hostapd_set_state(iface, HAPD_IFACE_ACS);
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_STARTED);
+
 	return HOSTAPD_CHAN_ACS;
 }
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index caf75c4..65a6f12 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -130,6 +130,13 @@
 		os_free(bss);
 		return NULL;
 	}
+	conf->bss = os_calloc(1, sizeof(struct hostapd_bss_config *));
+	if (conf->bss == NULL) {
+		os_free(conf);
+		os_free(bss);
+		return NULL;
+	}
+	conf->bss[0] = bss;
 
 	bss->radius = os_zalloc(sizeof(*bss->radius));
 	if (bss->radius == NULL) {
@@ -141,7 +148,6 @@
 	hostapd_config_defaults_bss(bss);
 
 	conf->num_bss = 1;
-	conf->bss = bss;
 
 	conf->beacon_int = 100;
 	conf->rts_threshold = -1; /* use driver default: 2347 */
@@ -397,7 +403,7 @@
 }
 
 
-static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
+void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 {
 	struct hostapd_wpa_psk *psk, *prev;
 	struct hostapd_eap_user *user, *prev_user;
@@ -432,10 +438,12 @@
 	os_free(conf->accept_mac);
 	os_free(conf->deny_mac);
 	os_free(conf->nas_identifier);
-	hostapd_config_free_radius(conf->radius->auth_servers,
-				   conf->radius->num_auth_servers);
-	hostapd_config_free_radius(conf->radius->acct_servers,
-				   conf->radius->num_acct_servers);
+	if (conf->radius) {
+		hostapd_config_free_radius(conf->radius->auth_servers,
+					   conf->radius->num_auth_servers);
+		hostapd_config_free_radius(conf->radius->acct_servers,
+					   conf->radius->num_acct_servers);
+	}
 	hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
 	hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
 	os_free(conf->rsn_preauth_interfaces);
@@ -525,6 +533,8 @@
 	os_free(conf->sae_groups);
 
 	os_free(conf->server_id);
+
+	os_free(conf);
 }
 
 
@@ -540,7 +550,7 @@
 		return;
 
 	for (i = 0; i < conf->num_bss; i++)
-		hostapd_config_free_bss(&conf->bss[i]);
+		hostapd_config_free_bss(conf->bss[i]);
 	os_free(conf->bss);
 	os_free(conf->supported_rates);
 	os_free(conf->basic_rates);
@@ -658,3 +668,209 @@
 
 	return NULL;
 }
+
+
+static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
+				    struct hostapd_config *conf)
+{
+	if (bss->ieee802_1x && !bss->eap_server &&
+	    !bss->radius->auth_servers) {
+		wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
+			   "EAP authenticator configured).");
+		return -1;
+	}
+
+	if (bss->wpa) {
+		int wep, i;
+
+		wep = bss->default_wep_key_len > 0 ||
+		       bss->individual_wep_key_len > 0;
+		for (i = 0; i < NUM_WEP_KEYS; i++) {
+			if (bss->ssid.wep.keys_set) {
+				wep = 1;
+				break;
+			}
+		}
+
+		if (wep) {
+			wpa_printf(MSG_ERROR, "WEP configuration in a WPA network is not supported");
+			return -1;
+		}
+	}
+
+	if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+	    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+		wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
+			   "RADIUS checking (macaddr_acl=2) enabled.");
+		return -1;
+	}
+
+	if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+	    bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
+	    bss->ssid.wpa_psk_file == NULL &&
+	    (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
+	     bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
+		wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
+			   "is not configured.");
+		return -1;
+	}
+
+	if (hostapd_mac_comp_empty(bss->bssid) != 0) {
+		size_t i;
+
+		for (i = 0; i < conf->num_bss; i++) {
+			if (conf->bss[i] != bss &&
+			    (hostapd_mac_comp(conf->bss[i]->bssid,
+					      bss->bssid) == 0)) {
+				wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
+					   " on interface '%s' and '%s'.",
+					   MAC2STR(bss->bssid),
+					   conf->bss[i]->iface, bss->iface);
+				return -1;
+			}
+		}
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
+	    (bss->nas_identifier == NULL ||
+	     os_strlen(bss->nas_identifier) < 1 ||
+	     os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
+		wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
+			   "nas_identifier to be configured as a 1..48 octet "
+			   "string");
+		return -1;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211N
+	if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
+			   "allowed, disabling HT capabilites");
+	}
+
+	if (conf->ieee80211n &&
+	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
+			   "allowed, disabling HT capabilities");
+	}
+
+	if (conf->ieee80211n && bss->wpa &&
+	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+	    !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
+			   "requires CCMP/GCMP to be enabled, disabling HT "
+			   "capabilities");
+	}
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_WPS2
+	if (bss->wps_state && bss->ignore_broadcast_ssid) {
+		wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
+			   "configuration forced WPS to be disabled");
+		bss->wps_state = 0;
+	}
+
+	if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) {
+		wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
+			   "disabled");
+		bss->wps_state = 0;
+	}
+
+	if (bss->wps_state && bss->wpa &&
+	    (!(bss->wpa & 2) ||
+	     !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
+		wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
+			   "WPA2/CCMP forced WPS to be disabled");
+		bss->wps_state = 0;
+	}
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_HS20
+	if (bss->hs20 &&
+	    (!(bss->wpa & 2) ||
+	     !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
+		wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
+			   "configuration is required for Hotspot 2.0 "
+			   "functionality");
+		return -1;
+	}
+#endif /* CONFIG_HS20 */
+
+	return 0;
+}
+
+
+int hostapd_config_check(struct hostapd_config *conf)
+{
+	size_t i;
+
+	if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
+		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
+			   "setting the country_code");
+		return -1;
+	}
+
+	if (conf->ieee80211h && !conf->ieee80211d) {
+		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11h without "
+			   "IEEE 802.11d enabled");
+		return -1;
+	}
+
+	for (i = 0; i < conf->num_bss; i++) {
+		if (hostapd_config_check_bss(conf->bss[i], conf))
+			return -1;
+	}
+
+	return 0;
+}
+
+
+void hostapd_set_security_params(struct hostapd_bss_config *bss)
+{
+	if (bss->individual_wep_key_len == 0) {
+		/* individual keys are not use; can use key idx0 for
+		 * broadcast keys */
+		bss->broadcast_key_idx_min = 0;
+	}
+
+	if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
+		bss->rsn_pairwise = bss->wpa_pairwise;
+	bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
+						    bss->rsn_pairwise);
+
+	bss->radius->auth_server = bss->radius->auth_servers;
+	bss->radius->acct_server = bss->radius->acct_servers;
+
+	if (bss->wpa && bss->ieee802_1x) {
+		bss->ssid.security_policy = SECURITY_WPA;
+	} else if (bss->wpa) {
+		bss->ssid.security_policy = SECURITY_WPA_PSK;
+	} else if (bss->ieee802_1x) {
+		int cipher = WPA_CIPHER_NONE;
+		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+		bss->ssid.wep.default_len = bss->default_wep_key_len;
+		if (bss->default_wep_key_len)
+			cipher = bss->default_wep_key_len >= 13 ?
+				WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else if (bss->ssid.wep.keys_set) {
+		int cipher = WPA_CIPHER_WEP40;
+		if (bss->ssid.wep.len[0] >= 13)
+			cipher = WPA_CIPHER_WEP104;
+		bss->ssid.security_policy = SECURITY_STATIC_WEP;
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else {
+		bss->ssid.security_policy = SECURITY_PLAINTEXT;
+		bss->wpa_group = WPA_CIPHER_NONE;
+		bss->wpa_pairwise = WPA_CIPHER_NONE;
+		bss->rsn_pairwise = WPA_CIPHER_NONE;
+	}
+}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 4f6a739..8b73724 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -53,6 +53,8 @@
 	size_t ssid_len;
 	unsigned int ssid_set:1;
 	unsigned int utf8_ssid:1;
+	unsigned int wpa_passphrase_set:1;
+	unsigned int wpa_psk_set:1;
 
 	char vlan[IFNAMSIZ + 1];
 	secpolicy security_policy;
@@ -479,7 +481,7 @@
  * struct hostapd_config - Per-radio interface configuration
  */
 struct hostapd_config {
-	struct hostapd_bss_config *bss, *last_bss;
+	struct hostapd_bss_config **bss, *last_bss;
 	size_t num_bss;
 
 	u16 beacon_int;
@@ -553,6 +555,7 @@
 int hostapd_mac_comp_empty(const void *a);
 struct hostapd_config * hostapd_config_defaults(void);
 void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
+void hostapd_config_free_bss(struct hostapd_bss_config *conf);
 void hostapd_config_free(struct hostapd_config *conf);
 int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
 			  const u8 *addr, int *vlan_id);
@@ -568,5 +571,7 @@
 					int vlan_id);
 struct hostapd_radius_attr *
 hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
+int hostapd_config_check(struct hostapd_config *conf);
+void hostapd_set_security_params(struct hostapd_bss_config *bss);
 
 #endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 72f582d..0dc0600 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -286,7 +286,7 @@
 	char force_ifname[IFNAMSIZ];
 	u8 if_addr[ETH_ALEN];
 	return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
-			      NULL, NULL, force_ifname, if_addr, NULL);
+			      NULL, NULL, force_ifname, if_addr, NULL, 0);
 }
 
 
@@ -417,20 +417,21 @@
 int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 		   const char *ifname, const u8 *addr, void *bss_ctx,
 		   void **drv_priv, char *force_ifname, u8 *if_addr,
-		   const char *bridge)
+		   const char *bridge, int use_existing)
 {
 	if (hapd->driver == NULL || hapd->driver->if_add == NULL)
 		return -1;
 	return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
 				    bss_ctx, drv_priv, force_ifname, if_addr,
-				    bridge);
+				    bridge, use_existing);
 }
 
 
 int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 		      const char *ifname)
 {
-	if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
+	if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+	    hapd->driver->if_remove == NULL)
 		return -1;
 	return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
 }
@@ -490,7 +491,8 @@
 	case VHT_CHANWIDTH_USE_HT:
 		if (center_segment1)
 			return -1;
-		if (5000 + center_segment0 * 5 != data->center_freq1)
+		if (5000 + center_segment0 * 5 != data->center_freq1 &&
+		    2407 + center_segment0 * 5 != data->center_freq1)
 			return -1;
 		break;
 	case VHT_CHANWIDTH_80P80MHZ:
@@ -730,18 +732,20 @@
 					 len, 0);
 }
 
-int hostapd_start_dfs_cac(struct hostapd_data *hapd, int mode, int freq,
+
+int hostapd_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq,
 			  int channel, int ht_enabled, int vht_enabled,
 			  int sec_channel_offset, int vht_oper_chwidth,
 			  int center_segment0, int center_segment1)
 {
+	struct hostapd_data *hapd = iface->bss[0];
 	struct hostapd_freq_params data;
 	int res;
 
 	if (!hapd->driver || !hapd->driver->start_dfs_cac)
 		return 0;
 
-	if (!hapd->iface->conf->ieee80211h) {
+	if (!iface->conf->ieee80211h) {
 		wpa_printf(MSG_ERROR, "Can't start DFS CAC, DFS functionality "
 			   "is not enabled");
 		return -1;
@@ -751,12 +755,12 @@
 				    vht_enabled, sec_channel_offset,
 				    vht_oper_chwidth, center_segment0,
 				    center_segment1,
-				    hapd->iface->current_mode->vht_capab))
+				    iface->current_mode->vht_capab))
 		return -1;
 
 	res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
 	if (!res)
-		hapd->cac_started = 1;
+		iface->cac_started = 1;
 
 	return res;
 }
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 8a2b4dc..ce2bb91 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -1,6 +1,6 @@
 /*
  * hostapd - Driver operations
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -48,7 +48,7 @@
 int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 		   const char *ifname, const u8 *addr, void *bss_ctx,
 		   void **drv_priv, char *force_ifname, u8 *if_addr,
-		   const char *bridge);
+		   const char *bridge, int use_existing);
 int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 		      const char *ifname);
 int hostapd_set_ieee8021x(struct hostapd_data *hapd,
@@ -101,7 +101,7 @@
 		      int reassoc, u16 status, const u8 *ie, size_t len);
 int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
 		      u8 *tspec_ie, size_t tspec_ielen);
-int hostapd_start_dfs_cac(struct hostapd_data *hapd, int mode, int freq,
+int hostapd_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq,
 			  int channel, int ht_enabled, int vht_enabled,
 			  int sec_channel_offset, int vht_oper_chwidth,
 			  int center_segment0, int center_segment1);
@@ -242,4 +242,19 @@
 	return hapd->driver->get_survey(hapd->drv_priv, freq);
 }
 
+static inline int hostapd_get_country(struct hostapd_data *hapd, char *alpha2)
+{
+	if (hapd->driver == NULL || hapd->driver->get_country == NULL)
+		return -1;
+	return hapd->driver->get_country(hapd->drv_priv, alpha2);
+}
+
+static inline const char * hostapd_drv_get_radio_name(struct hostapd_data *hapd)
+{
+	if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+	    hapd->driver->get_radio_name == NULL)
+		return NULL;
+	return hapd->driver->get_radio_name(hapd->drv_priv);
+}
+
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 360001f..6c8b78f 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -540,7 +540,7 @@
 		   is_broadcast_ether_addr(mgmt->da));
 
 	if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
-		perror("handle_probe_req: send");
+		wpa_printf(MSG_INFO, "handle_probe_req: send failed");
 
 	os_free(resp);
 
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 1cb7e73..5d99566 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1,6 +1,6 @@
 /*
  * Control interface for shared AP commands
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -303,3 +303,80 @@
 
 	return 0;
 }
+
+
+int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
+			      size_t buflen)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	int len = 0, ret;
+	size_t i;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "state=%s\n"
+			  "phy=%s\n"
+			  "freq=%d\n"
+			  "num_sta_non_erp=%d\n"
+			  "num_sta_no_short_slot_time=%d\n"
+			  "num_sta_no_short_preamble=%d\n"
+			  "olbc=%d\n"
+			  "num_sta_ht_no_gf=%d\n"
+			  "num_sta_no_ht=%d\n"
+			  "num_sta_ht_20_mhz=%d\n"
+			  "olbc_ht=%d\n"
+			  "ht_op_mode=0x%x\n",
+			  hostapd_state_text(iface->state),
+			  iface->phy,
+			  iface->freq,
+			  iface->num_sta_non_erp,
+			  iface->num_sta_no_short_slot_time,
+			  iface->num_sta_no_short_preamble,
+			  iface->olbc,
+			  iface->num_sta_ht_no_gf,
+			  iface->num_sta_no_ht,
+			  iface->num_sta_ht_20mhz,
+			  iface->olbc_ht,
+			  iface->ht_op_mode);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "channel=%u\n"
+			  "secondary_channel=%d\n"
+			  "ieee80211n=%d\n"
+			  "ieee80211ac=%d\n"
+			  "vht_oper_chwidth=%d\n"
+			  "vht_oper_centr_freq_seg0_idx=%d\n"
+			  "vht_oper_centr_freq_seg1_idx=%d\n",
+			  iface->conf->channel,
+			  iface->conf->secondary_channel,
+			  iface->conf->ieee80211n,
+			  iface->conf->ieee80211ac,
+			  iface->conf->vht_oper_chwidth,
+			  iface->conf->vht_oper_centr_freq_seg0_idx,
+			  iface->conf->vht_oper_centr_freq_seg1_idx);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		struct hostapd_data *bss = iface->bss[i];
+		ret = os_snprintf(buf + len, buflen - len,
+				  "bss[%d]=%s\n"
+				  "bssid[%d]=" MACSTR "\n"
+				  "ssid[%d]=%s\n"
+				  "num_sta[%d]=%d\n",
+				  (int) i, bss->conf->iface,
+				  (int) i, MAC2STR(bss->own_addr),
+				  (int) i,
+				  wpa_ssid_txt(bss->conf->ssid.ssid,
+					       bss->conf->ssid.ssid_len),
+				  (int) i, bss->num_sta);
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+	}
+
+	return len;
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index e83f894..a22a2a7 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -1,6 +1,6 @@
 /*
  * Control interface for shared AP commands
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -19,5 +19,7 @@
 				      const char *txtaddr);
 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
 				    const char *txtaddr);
+int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
+			      size_t buflen);
 
 #endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index a30861f..0a909f4 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -11,21 +11,22 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "hostapd.h"
 #include "ap_drv_ops.h"
 #include "drivers/driver.h"
 #include "dfs.h"
 
 
-static int dfs_get_used_n_chans(struct hostapd_data *hapd)
+static int dfs_get_used_n_chans(struct hostapd_iface *iface)
 {
 	int n_chans = 1;
 
-	if (hapd->iconf->ieee80211n && hapd->iconf->secondary_channel)
+	if (iface->conf->ieee80211n && iface->conf->secondary_channel)
 		n_chans = 2;
 
-	if (hapd->iconf->ieee80211ac) {
-		switch (hapd->iconf->vht_oper_chwidth) {
+	if (iface->conf->ieee80211ac) {
+		switch (iface->conf->vht_oper_chwidth) {
 		case VHT_CHANWIDTH_USE_HT:
 			break;
 		case VHT_CHANWIDTH_80MHZ:
@@ -94,42 +95,62 @@
 }
 
 
-static int dfs_find_channel(struct hostapd_data *hapd,
+static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
+				    int first_chan_idx, int num_chans)
+{
+	struct hostapd_channel_data *first_chan, *chan;
+	int i;
+
+	if (first_chan_idx + num_chans >= mode->num_channels)
+		return 0;
+
+	first_chan = &mode->channels[first_chan_idx];
+
+	for (i = 0; i < num_chans; i++) {
+		chan = &mode->channels[first_chan_idx + i];
+
+		if (first_chan->freq + i * 20 != chan->freq)
+			return 0;
+
+		if (!dfs_channel_available(chan))
+			return 0;
+	}
+
+	return 1;
+}
+
+
+/*
+ * The function assumes HT40+ operation.
+ * Make sure to adjust the following variables after calling this:
+ *  - hapd->secondary_channel
+ *  - hapd->vht_oper_centr_freq_seg0_idx
+ *  - hapd->vht_oper_centr_freq_seg1_idx
+ */
+static int dfs_find_channel(struct hostapd_iface *iface,
 			    struct hostapd_channel_data **ret_chan,
 			    int idx)
 {
 	struct hostapd_hw_modes *mode;
-	struct hostapd_channel_data *chan, *next_chan;
-	int i, j, channel_idx = 0, n_chans;
+	struct hostapd_channel_data *chan;
+	int i, channel_idx = 0, n_chans;
 
-	mode = hapd->iface->current_mode;
-	n_chans = dfs_get_used_n_chans(hapd);
+	mode = iface->current_mode;
+	n_chans = dfs_get_used_n_chans(iface);
 
 	wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
 	for (i = 0; i < mode->num_channels; i++) {
 		chan = &mode->channels[i];
 
-		/* Skip not available channels */
-		if (!dfs_channel_available(chan))
+		/* Skip HT40/VHT incompatible channels */
+		if (iface->conf->ieee80211n &&
+		    iface->conf->secondary_channel &&
+		    !dfs_is_chan_allowed(chan, n_chans))
 			continue;
 
-		/* Skip HT40/VHT uncompatible channels */
-		if (hapd->iconf->ieee80211n &&
-		    hapd->iconf->secondary_channel) {
-			if (!dfs_is_chan_allowed(chan, n_chans))
-				continue;
-
-			for (j = 1; j < n_chans; j++) {
-				next_chan = &mode->channels[i + j];
-				if (!dfs_channel_available(next_chan))
-					break;
-			}
-			if (j != n_chans)
-				continue;
-
-			/* Set HT40+ */
-			hapd->iconf->secondary_channel = 1;
-		}
+		/* Skip incompatible chandefs */
+		if (!dfs_chan_range_available(mode, i, n_chans))
+			continue;
 
 		if (ret_chan && idx == channel_idx) {
 			wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
@@ -143,67 +164,69 @@
 }
 
 
-static void dfs_adjust_vht_center_freq(struct hostapd_data *hapd,
-				       struct hostapd_channel_data *chan)
+static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
+				       struct hostapd_channel_data *chan,
+				       u8 *vht_oper_centr_freq_seg0_idx,
+				       u8 *vht_oper_centr_freq_seg1_idx)
 {
-	if (!hapd->iconf->ieee80211ac)
+	if (!iface->conf->ieee80211ac)
 		return;
 
 	if (!chan)
 		return;
 
-	switch (hapd->iconf->vht_oper_chwidth) {
+	*vht_oper_centr_freq_seg1_idx = 0;
+
+	switch (iface->conf->vht_oper_chwidth) {
 	case VHT_CHANWIDTH_USE_HT:
-		if (hapd->iconf->secondary_channel == 1)
-			hapd->iconf->vht_oper_centr_freq_seg0_idx =
-				chan->chan + 2;
-		else if (hapd->iconf->secondary_channel == -1)
-			hapd->iconf->vht_oper_centr_freq_seg0_idx =
-				chan->chan - 2;
+		if (iface->conf->secondary_channel == 1)
+			*vht_oper_centr_freq_seg0_idx = chan->chan + 2;
+		else if (iface->conf->secondary_channel == -1)
+			*vht_oper_centr_freq_seg0_idx = chan->chan - 2;
 		else
-			hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan;
+			*vht_oper_centr_freq_seg0_idx = chan->chan;
 		break;
 	case VHT_CHANWIDTH_80MHZ:
-		hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan + 6;
+		*vht_oper_centr_freq_seg0_idx = chan->chan + 6;
 		break;
 	case VHT_CHANWIDTH_160MHZ:
-		hapd->iconf->vht_oper_centr_freq_seg0_idx =
-						chan->chan + 14;
+		*vht_oper_centr_freq_seg0_idx = chan->chan + 14;
 		break;
 	default:
 		wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
 		break;
 	}
 
-	wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d",
-		   hapd->iconf->vht_oper_centr_freq_seg0_idx);
+	wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
+		   *vht_oper_centr_freq_seg0_idx,
+		   *vht_oper_centr_freq_seg1_idx);
 }
 
 
 /* Return start channel idx we will use for mode->channels[idx] */
-static int dfs_get_start_chan_idx(struct hostapd_data *hapd)
+static int dfs_get_start_chan_idx(struct hostapd_iface *iface)
 {
 	struct hostapd_hw_modes *mode;
 	struct hostapd_channel_data *chan;
-	int channel_no = hapd->iconf->channel;
+	int channel_no = iface->conf->channel;
 	int res = -1, i;
 
 	/* HT40- */
-	if (hapd->iconf->ieee80211n && hapd->iconf->secondary_channel == -1)
+	if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
 		channel_no -= 4;
 
 	/* VHT */
-	if (hapd->iconf->ieee80211ac) {
-		switch (hapd->iconf->vht_oper_chwidth) {
+	if (iface->conf->ieee80211ac) {
+		switch (iface->conf->vht_oper_chwidth) {
 		case VHT_CHANWIDTH_USE_HT:
 			break;
 		case VHT_CHANWIDTH_80MHZ:
 			channel_no =
-				hapd->iconf->vht_oper_centr_freq_seg0_idx - 6;
+				iface->conf->vht_oper_centr_freq_seg0_idx - 6;
 			break;
 		case VHT_CHANWIDTH_160MHZ:
 			channel_no =
-				hapd->iconf->vht_oper_centr_freq_seg0_idx - 14;
+				iface->conf->vht_oper_centr_freq_seg0_idx - 14;
 			break;
 		default:
 			wpa_printf(MSG_INFO,
@@ -214,7 +237,7 @@
 	}
 
 	/* Get idx */
-	mode = hapd->iface->current_mode;
+	mode = iface->current_mode;
 	for (i = 0; i < mode->num_channels; i++) {
 		chan = &mode->channels[i];
 		if (chan->chan == channel_no) {
@@ -231,14 +254,14 @@
 
 
 /* At least one channel have radar flag */
-static int dfs_check_chans_radar(struct hostapd_data *hapd, int start_chan_idx,
-				 int n_chans)
+static int dfs_check_chans_radar(struct hostapd_iface *iface,
+				 int start_chan_idx, int n_chans)
 {
 	struct hostapd_channel_data *channel;
 	struct hostapd_hw_modes *mode;
 	int i, res = 0;
 
-	mode = hapd->iface->current_mode;
+	mode = iface->current_mode;
 
 	for (i = 0; i < n_chans; i++) {
 		channel = &mode->channels[start_chan_idx + i];
@@ -251,14 +274,14 @@
 
 
 /* All channels available */
-static int dfs_check_chans_available(struct hostapd_data *hapd,
+static int dfs_check_chans_available(struct hostapd_iface *iface,
 				     int start_chan_idx, int n_chans)
 {
 	struct hostapd_channel_data *channel;
 	struct hostapd_hw_modes *mode;
 	int i;
 
-	mode = hapd->iface->current_mode;
+	mode = iface->current_mode;
 
 	for(i = 0; i < n_chans; i++) {
 		channel = &mode->channels[start_chan_idx + i];
@@ -272,7 +295,7 @@
 
 
 /* At least one channel unavailable */
-static int dfs_check_chans_unavailable(struct hostapd_data *hapd,
+static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
 				       int start_chan_idx,
 				       int n_chans)
 {
@@ -280,7 +303,7 @@
 	struct hostapd_hw_modes *mode;
 	int i, res = 0;
 
-	mode = hapd->iface->current_mode;
+	mode = iface->current_mode;
 
 	for(i = 0; i < n_chans; i++) {
 		channel = &mode->channels[start_chan_idx + i];
@@ -295,51 +318,63 @@
 }
 
 
-static struct hostapd_channel_data * dfs_get_valid_channel(
-	struct hostapd_data *hapd)
+static struct hostapd_channel_data *
+dfs_get_valid_channel(struct hostapd_iface *iface,
+		      int *secondary_channel,
+		      u8 *vht_oper_centr_freq_seg0_idx,
+		      u8 *vht_oper_centr_freq_seg1_idx)
 {
 	struct hostapd_hw_modes *mode;
 	struct hostapd_channel_data *chan = NULL;
-	int channel_idx, new_channel_idx;
+	int num_available_chandefs;
+	int chan_idx;
 	u32 _rand;
 
 	wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
 
-	if (hapd->iface->current_mode == NULL)
+	if (iface->current_mode == NULL)
 		return NULL;
 
-	mode = hapd->iface->current_mode;
+	mode = iface->current_mode;
 	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
 		return NULL;
 
-	/* get random available channel */
-	channel_idx = dfs_find_channel(hapd, NULL, 0);
-	if (channel_idx > 0) {
-		os_get_random((u8 *) &_rand, sizeof(_rand));
-		new_channel_idx = _rand % channel_idx;
-		dfs_find_channel(hapd, &chan, new_channel_idx);
-	}
+	/* Get the count first */
+	num_available_chandefs = dfs_find_channel(iface, NULL, 0);
+	if (num_available_chandefs == 0)
+		return NULL;
 
-	/* VHT */
-	dfs_adjust_vht_center_freq(hapd, chan);
+	os_get_random((u8 *) &_rand, sizeof(_rand));
+	chan_idx = _rand % num_available_chandefs;
+	dfs_find_channel(iface, &chan, chan_idx);
+
+	/* dfs_find_channel() calculations assume HT40+ */
+	if (iface->conf->secondary_channel)
+		*secondary_channel = 1;
+	else
+		*secondary_channel = 0;
+
+	dfs_adjust_vht_center_freq(iface, chan,
+				   vht_oper_centr_freq_seg0_idx,
+				   vht_oper_centr_freq_seg1_idx);
 
 	return chan;
 }
 
 
-static int set_dfs_state_freq(struct hostapd_data *hapd, int freq, u32 state)
+static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
 {
 	struct hostapd_hw_modes *mode;
 	struct hostapd_channel_data *chan = NULL;
 	int i;
 
-	mode = hapd->iface->current_mode;
+	mode = iface->current_mode;
 	if (mode == NULL)
 		return 0;
 
 	wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
-	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
-		chan = &hapd->iface->current_mode->channels[i];
+	for (i = 0; i < iface->current_mode->num_channels; i++) {
+		chan = &iface->current_mode->channels[i];
 		if (chan->freq == freq) {
 			if (chan->flag & HOSTAPD_CHAN_RADAR) {
 				chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
@@ -353,7 +388,7 @@
 }
 
 
-static int set_dfs_state(struct hostapd_data *hapd, int freq, int ht_enabled,
+static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
 			 int chan_offset, int chan_width, int cf1,
 			 int cf2, u32 state)
 {
@@ -362,7 +397,7 @@
 	int frequency = freq;
 	int ret = 0;
 
-	mode = hapd->iface->current_mode;
+	mode = iface->current_mode;
 	if (mode == NULL)
 		return 0;
 
@@ -376,7 +411,8 @@
 	case CHAN_WIDTH_20_NOHT:
 	case CHAN_WIDTH_20:
 		n_chans = 1;
-		frequency = cf1;
+		if (frequency == 0)
+			frequency = cf1;
 		break;
 	case CHAN_WIDTH_40:
 		n_chans = 2;
@@ -399,7 +435,7 @@
 	wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
 		   n_chans);
 	for (i = 0; i < n_chans; i++) {
-		ret += set_dfs_state_freq(hapd, frequency, state);
+		ret += set_dfs_state_freq(iface, frequency, state);
 		frequency = frequency + 20;
 	}
 
@@ -407,7 +443,7 @@
 }
 
 
-static int dfs_are_channels_overlapped(struct hostapd_data *hapd, int freq,
+static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
 				       int chan_width, int cf1, int cf2)
 {
 	int start_chan_idx;
@@ -418,12 +454,12 @@
 	int res = 0;
 
 	/* Our configuration */
-	mode = hapd->iface->current_mode;
-	start_chan_idx = dfs_get_start_chan_idx(hapd);
-	n_chans = dfs_get_used_n_chans(hapd);
+	mode = iface->current_mode;
+	start_chan_idx = dfs_get_start_chan_idx(iface);
+	n_chans = dfs_get_used_n_chans(iface);
 
 	/* Check we are on DFS channel(s) */
-	if (!dfs_check_chans_radar(hapd, start_chan_idx, n_chans))
+	if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
 		return 0;
 
 	/* Reported via radar event */
@@ -431,7 +467,8 @@
 	case CHAN_WIDTH_20_NOHT:
 	case CHAN_WIDTH_20:
 		radar_n_chans = 1;
-		frequency = cf1;
+		if (frequency == 0)
+			frequency = cf1;
 		break;
 	case CHAN_WIDTH_40:
 		radar_n_chans = 2;
@@ -477,22 +514,24 @@
  * 0 - channel/ap setup will be continued after CAC
  * -1 - hit critical error
  */
-int hostapd_handle_dfs(struct hostapd_data *hapd)
+int hostapd_handle_dfs(struct hostapd_iface *iface)
 {
 	struct hostapd_channel_data *channel;
 	int res, n_chans, start_chan_idx;
 
+	iface->cac_started = 0;
+
 	do {
 		/* Get start (first) channel for current configuration */
-		start_chan_idx = dfs_get_start_chan_idx(hapd);
+		start_chan_idx = dfs_get_start_chan_idx(iface);
 		if (start_chan_idx == -1)
 			return -1;
 
 		/* Get number of used channels, depend on width */
-		n_chans = dfs_get_used_n_chans(hapd);
+		n_chans = dfs_get_used_n_chans(iface);
 
 		/* Check if any of configured channels require DFS */
-		res = dfs_check_chans_radar(hapd, start_chan_idx, n_chans);
+		res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
 		wpa_printf(MSG_DEBUG,
 			   "DFS %d channels required radar detection",
 			   res);
@@ -500,7 +539,7 @@
 			return 1;
 
 		/* Check if all channels are DFS available */
-		res = dfs_check_chans_available(hapd, start_chan_idx, n_chans);
+		res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
 		wpa_printf(MSG_DEBUG,
 			   "DFS all channels available, (SKIP CAC): %s",
 			   res ? "yes" : "no");
@@ -508,32 +547,44 @@
 			return 1;
 
 		/* Check if any of configured channels is unavailable */
-		res = dfs_check_chans_unavailable(hapd, start_chan_idx,
+		res = dfs_check_chans_unavailable(iface, start_chan_idx,
 						  n_chans);
 		wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
 			   res, res ? "yes": "no");
 		if (res) {
-			channel = dfs_get_valid_channel(hapd);
+			int sec;
+			u8 cf1, cf2;
+
+			channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2);
 			if (!channel) {
 				wpa_printf(MSG_ERROR, "could not get valid channel");
 				return -1;
 			}
-			hapd->iconf->channel = channel->chan;
-			hapd->iface->freq = channel->freq;
+
+			iface->freq = channel->freq;
+			iface->conf->channel = channel->chan;
+			iface->conf->secondary_channel = sec;
+			iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
+			iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
 		}
 	} while (res);
 
 	/* Finally start CAC */
-	wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", hapd->iface->freq);
-	if (hostapd_start_dfs_cac(hapd, hapd->iconf->hw_mode,
-				  hapd->iface->freq,
-				  hapd->iconf->channel,
-				  hapd->iconf->ieee80211n,
-				  hapd->iconf->ieee80211ac,
-				  hapd->iconf->secondary_channel,
-				  hapd->iconf->vht_oper_chwidth,
-				  hapd->iconf->vht_oper_centr_freq_seg0_idx,
-				  hapd->iconf->vht_oper_centr_freq_seg1_idx)) {
+	hostapd_set_state(iface, HAPD_IFACE_DFS);
+	wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
+		"freq=%d chan=%d sec_chan=%d",
+		iface->freq,
+		iface->conf->channel, iface->conf->secondary_channel);
+	if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+				  iface->freq,
+				  iface->conf->channel,
+				  iface->conf->ieee80211n,
+				  iface->conf->ieee80211ac,
+				  iface->conf->secondary_channel,
+				  iface->conf->vht_oper_chwidth,
+				  iface->conf->vht_oper_centr_freq_seg0_idx,
+				  iface->conf->vht_oper_centr_freq_seg1_idx)) {
 		wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed");
 		return -1;
 	}
@@ -542,81 +593,119 @@
 }
 
 
-int hostapd_dfs_complete_cac(struct hostapd_data *hapd, int success, int freq,
+int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
 			     int ht_enabled, int chan_offset, int chan_width,
 			     int cf1, int cf2)
 {
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
+		"success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+		success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
 	if (success) {
 		/* Complete iface/ap configuration */
-		set_dfs_state(hapd, freq, ht_enabled, chan_offset,
+		set_dfs_state(iface, freq, ht_enabled, chan_offset,
 			      chan_width, cf1, cf2,
 			      HOSTAPD_CHAN_DFS_AVAILABLE);
-		hapd->cac_started = 0;
-		hostapd_setup_interface_complete(hapd->iface, 0);
+		iface->cac_started = 0;
+		hostapd_setup_interface_complete(iface, 0);
 	}
 
 	return 0;
 }
 
 
-static int hostapd_dfs_start_channel_switch(struct hostapd_data *hapd)
+static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
 {
 	struct hostapd_channel_data *channel;
 	int err = 1;
+	int secondary_channel;
+	u8 vht_oper_centr_freq_seg0_idx;
+	u8 vht_oper_centr_freq_seg1_idx;
 
 	wpa_printf(MSG_DEBUG, "%s called", __func__);
-	channel = dfs_get_valid_channel(hapd);
+	channel = dfs_get_valid_channel(iface, &secondary_channel,
+					&vht_oper_centr_freq_seg0_idx,
+					&vht_oper_centr_freq_seg1_idx);
 	if (channel) {
-		hapd->iconf->channel = channel->chan;
-		hapd->iface->freq = channel->freq;
+		wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
+			   channel->chan);
+		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+			"freq=%d chan=%d sec_chan=%d", channel->freq,
+			channel->chan, secondary_channel);
+
+		iface->freq = channel->freq;
+		iface->conf->channel = channel->chan;
+		iface->conf->secondary_channel = secondary_channel;
+		iface->conf->vht_oper_centr_freq_seg0_idx =
+			vht_oper_centr_freq_seg0_idx;
+		iface->conf->vht_oper_centr_freq_seg1_idx =
+			vht_oper_centr_freq_seg1_idx;
 		err = 0;
-	}
-
-	if (!hapd->cac_started) {
-		wpa_printf(MSG_DEBUG, "DFS radar detected");
-		hapd->driver->stop_ap(hapd->drv_priv);
 	} else {
-		wpa_printf(MSG_DEBUG, "DFS radar detected during CAC");
-		hapd->cac_started = 0;
+		wpa_printf(MSG_ERROR, "No valid channel available");
 	}
 
-	hostapd_setup_interface_complete(hapd->iface, err);
+	if (iface->cac_started) {
+		wpa_printf(MSG_DEBUG, "DFS radar detected during CAC");
+		iface->cac_started = 0;
+		/* FIXME: Wait for channel(s) to become available if no channel
+		 * has been found */
+		hostapd_setup_interface_complete(iface, err);
+		return err;
+	}
+
+	if (err) {
+		/* FIXME: Wait for channel(s) to become available */
+		hostapd_disable_iface(iface);
+		return err;
+	}
+
+	wpa_printf(MSG_DEBUG, "DFS radar detected");
+	hostapd_disable_iface(iface);
+	hostapd_enable_iface(iface);
 	return 0;
 }
 
 
-int hostapd_dfs_radar_detected(struct hostapd_data *hapd, int freq,
+int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
 			       int ht_enabled, int chan_offset, int chan_width,
 			       int cf1, int cf2)
 {
 	int res;
 
-	if (!hapd->iconf->ieee80211h)
+	if (!iface->conf->ieee80211h)
 		return 0;
 
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
+		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
 	/* mark radar frequency as invalid */
-	res = set_dfs_state(hapd, freq, ht_enabled, chan_offset,
+	res = set_dfs_state(iface, freq, ht_enabled, chan_offset,
 			    chan_width, cf1, cf2,
 			    HOSTAPD_CHAN_DFS_UNAVAILABLE);
 
 	/* Skip if reported radar event not overlapped our channels */
-	res = dfs_are_channels_overlapped(hapd, freq, chan_width, cf1, cf2);
+	res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
 	if (!res)
 		return 0;
 
 	/* radar detected while operating, switch the channel. */
-	res = hostapd_dfs_start_channel_switch(hapd);
+	res = hostapd_dfs_start_channel_switch(iface);
 
 	return res;
 }
 
 
-int hostapd_dfs_nop_finished(struct hostapd_data *hapd, int freq,
+int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
 			     int ht_enabled, int chan_offset, int chan_width,
 			     int cf1, int cf2)
 {
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
+		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
 	/* TODO add correct implementation here */
-	set_dfs_state(hapd, freq, ht_enabled, chan_offset, chan_width, cf1, cf2,
-		      HOSTAPD_CHAN_DFS_USABLE);
+	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
 	return 0;
 }
diff --git a/src/ap/dfs.h b/src/ap/dfs.h
index c9f0578..859ff79 100644
--- a/src/ap/dfs.h
+++ b/src/ap/dfs.h
@@ -9,16 +9,16 @@
 #ifndef DFS_H
 #define DFS_H
 
-int hostapd_handle_dfs(struct hostapd_data *hapd);
+int hostapd_handle_dfs(struct hostapd_iface *iface);
 
-int hostapd_dfs_complete_cac(struct hostapd_data *hapd, int success, int freq,
+int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
 			     int ht_enabled, int chan_offset, int chan_width,
 			     int cf1, int cf2);
-int hostapd_dfs_radar_detected(struct hostapd_data *hapd, int freq,
+int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
 			       int ht_enabled,
 			       int chan_offset, int chan_width,
 			       int cf1, int cf2);
-int hostapd_dfs_nop_finished(struct hostapd_data *hapd, int freq,
+int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
 			     int ht_enabled,
 			     int chan_offset, int chan_width, int cf1, int cf2);
 
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index b30da14..0f4b12e 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -799,7 +799,7 @@
 					     struct dfs_event *radar)
 {
 	wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
-	hostapd_dfs_radar_detected(hapd, radar->freq, radar->ht_enabled,
+	hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled,
 				   radar->chan_offset, radar->chan_width,
 				   radar->cf1, radar->cf2);
 }
@@ -809,7 +809,7 @@
 					   struct dfs_event *radar)
 {
 	wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
-	hostapd_dfs_complete_cac(hapd, 1, radar->freq, radar->ht_enabled,
+	hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled,
 				 radar->chan_offset, radar->chan_width,
 				 radar->cf1, radar->cf2);
 }
@@ -819,7 +819,7 @@
 					  struct dfs_event *radar)
 {
 	wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
-	hostapd_dfs_complete_cac(hapd, 0, radar->freq, radar->ht_enabled,
+	hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled,
 				 radar->chan_offset, radar->chan_width,
 				 radar->cf1, radar->cf2);
 }
@@ -829,7 +829,7 @@
 					   struct dfs_event *radar)
 {
 	wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
-	hostapd_dfs_nop_finished(hapd, radar->freq, radar->ht_enabled,
+	hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled,
 				 radar->chan_offset, radar->chan_width,
 				 radar->cf1, radar->cf2);
 }
@@ -1007,6 +1007,7 @@
 		/* TODO: check this. hostapd_get_hw_features() initializes
 		 * too much stuff. */
 		/* hostapd_get_hw_features(hapd->iface); */
+		hostapd_channel_list_updated(hapd->iface);
 		break;
 #endif /* NEED_AP_MLME */
 	default:
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;
+}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index d79c3e5..05bcb62 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -1,6 +1,6 @@
 /*
  * hostapd / Initialization and configuration
- * Copyright (c) 2002-2009, 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.
@@ -99,7 +99,6 @@
 	struct hostapd_iface *iface;
 	struct hostapd_config *iconf;
 	struct hostapd_bss_config *conf;
-	int interface_added; /* virtual interface added for this BSS */
 
 	u8 own_addr[ETH_ALEN];
 
@@ -152,9 +151,6 @@
 
 	int parameter_set_count;
 
-	/* DFS specific parameters */
-	int cac_started;
-
 	/* Time Advertisement */
 	u8 time_update_counter;
 	struct wpabuf *time_adv;
@@ -250,10 +246,24 @@
 	void *owner;
 	char *config_fname;
 	struct hostapd_config *conf;
+	char phy[16]; /* Name of the PHY (radio) */
+
+	enum hostapd_iface_state {
+		HAPD_IFACE_UNINITIALIZED,
+		HAPD_IFACE_DISABLED,
+		HAPD_IFACE_COUNTRY_UPDATE,
+		HAPD_IFACE_ACS,
+		HAPD_IFACE_HT_SCAN,
+		HAPD_IFACE_DFS,
+		HAPD_IFACE_ENABLED
+	} state;
 
 	size_t num_bss;
 	struct hostapd_data **bss;
 
+	unsigned int wait_channel_update:1;
+	unsigned int cac_started:1;
+
 	int num_ap; /* number of entries in ap_list */
 	struct ap_info *ap_list; /* AP info list head */
 	struct ap_info *ap_hash[STA_HASH_SIZE];
@@ -348,6 +358,11 @@
 int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
 void hostapd_interface_deinit(struct hostapd_iface *iface);
 void hostapd_interface_free(struct hostapd_iface *iface);
+struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
+				    const char *config_file);
+struct hostapd_iface *
+hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+			   const char *config_fname, int debug);
 void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
 			   int reassoc);
 void hostapd_interface_deinit_free(struct hostapd_iface *iface);
@@ -356,6 +371,9 @@
 int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
 int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
 int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
+void hostapd_channel_list_updated(struct hostapd_iface *iface);
+void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
+const char * hostapd_state_text(enum hostapd_iface_state s);
 
 /* utils.c */
 int hostapd_register_probereq_cb(struct hostapd_data *hapd,
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index d2831d4..e95e0e1 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -20,6 +20,7 @@
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
 #include "drivers/driver.h"
 #include "hostapd.h"
 #include "ap_config.h"
@@ -531,6 +532,47 @@
 }
 
 
+static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
+					struct wpa_driver_scan_params *params)
+{
+	/* Scan only the affected frequency range */
+	int pri_freq;
+	int affected_start, affected_end;
+	int i, pos;
+	struct hostapd_hw_modes *mode;
+
+	if (iface->current_mode == NULL)
+		return;
+
+	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+	if (iface->conf->secondary_channel > 0) {
+		affected_start = pri_freq - 10;
+		affected_end = pri_freq + 30;
+	} else {
+		affected_start = pri_freq - 30;
+		affected_end = pri_freq + 10;
+	}
+	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+		   affected_start, affected_end);
+
+	mode = iface->current_mode;
+	params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
+	if (params->freqs == NULL)
+		return;
+	pos = 0;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		struct hostapd_channel_data *chan = &mode->channels[i];
+		if (chan->flag & HOSTAPD_CHAN_DISABLED)
+			continue;
+		if (chan->freq < affected_start ||
+		    chan->freq > affected_end)
+			continue;
+		params->freqs[pos++] = chan->freq;
+	}
+}
+
+
 static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
 {
 	struct wpa_driver_scan_params params;
@@ -538,11 +580,14 @@
 	if (!iface->conf->secondary_channel)
 		return 0; /* HT40 not used */
 
+	hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
 	wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
 		   "40 MHz channel");
 	os_memset(&params, 0, sizeof(params));
 	if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
 		ieee80211n_scan_channels_2g4(iface, &params);
+	else
+		ieee80211n_scan_channels_5g(iface, &params);
 	if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
 		wpa_printf(MSG_ERROR, "Failed to request a scan of "
 			   "neighboring BSSes");
@@ -857,14 +902,21 @@
 
 	switch (hostapd_check_chans(iface)) {
 	case HOSTAPD_CHAN_VALID:
+		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
+			ACS_EVENT_COMPLETED "freq=%d channel=%d",
+			hostapd_hw_get_freq(iface->bss[0],
+					    iface->conf->channel),
+			iface->conf->channel);
 		break;
 	case HOSTAPD_CHAN_ACS:
 		wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
+		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
 		hostapd_notify_bad_chans(iface);
 		goto out;
 	case HOSTAPD_CHAN_INVALID:
 	default:
 		wpa_printf(MSG_ERROR, "ACS picked unusable channels");
+		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
 		hostapd_notify_bad_chans(iface);
 		goto out;
 	}
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
index be55c69..bad080f 100644
--- a/src/ap/iapp.c
+++ b/src/ap/iapp.c
@@ -204,7 +204,7 @@
 	addr.sin_port = htons(IAPP_UDP_PORT);
 	if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
 		   (struct sockaddr *) &addr, sizeof(addr)) < 0)
-		perror("sendto[IAPP-ADD]");
+		wpa_printf(MSG_INFO, "sendto[IAPP-ADD]: %s", strerror(errno));
 }
 
 
@@ -231,7 +231,7 @@
 				   * FIX: what is correct RW with 802.11? */
 
 	if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
-		perror("send[L2 Update]");
+		wpa_printf(MSG_INFO, "send[L2 Update]: %s", strerror(errno));
 }
 
 
@@ -276,8 +276,8 @@
 	struct sta_info *sta;
 
 	if (len != sizeof(*add)) {
-		printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
-		       len, (unsigned long) sizeof(*add));
+		wpa_printf(MSG_INFO, "Invalid IAPP-ADD packet length %d (expected %lu)",
+			   len, (unsigned long) sizeof(*add));
 		return;
 	}
 
@@ -326,7 +326,8 @@
 	len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (len < 0) {
-		perror("recvfrom");
+		wpa_printf(MSG_INFO, "iapp_receive_udp - recvfrom: %s",
+			   strerror(errno));
 		return;
 	}
 
@@ -350,17 +351,18 @@
 		       hdr->version, hdr->command,
 		       be_to_host16(hdr->identifier), hlen);
 	if (hdr->version != IAPP_VERSION) {
-		printf("Dropping IAPP frame with unknown version %d\n",
-		       hdr->version);
+		wpa_printf(MSG_INFO, "Dropping IAPP frame with unknown version %d",
+			   hdr->version);
 		return;
 	}
 	if (hlen > len) {
-		printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
+		wpa_printf(MSG_INFO, "Underflow IAPP frame (hlen=%d len=%d)",
+			   hlen, len);
 		return;
 	}
 	if (hlen < len) {
-		printf("Ignoring %d extra bytes from IAPP frame\n",
-		       len - hlen);
+		wpa_printf(MSG_INFO, "Ignoring %d extra bytes from IAPP frame",
+			   len - hlen);
 		len = hlen;
 	}
 
@@ -376,7 +378,7 @@
 		/* TODO: process */
 		break;
 	default:
-		printf("Unknown IAPP command %d\n", hdr->command);
+		wpa_printf(MSG_INFO, "Unknown IAPP command %d", hdr->command);
 		break;
 	}
 }
@@ -403,7 +405,8 @@
 
 	iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (iapp->udp_sock < 0) {
-		perror("socket[PF_INET,SOCK_DGRAM]");
+		wpa_printf(MSG_INFO, "iapp_init - socket[PF_INET,SOCK_DGRAM]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
@@ -411,35 +414,38 @@
 	os_memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
 	if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
-		perror("ioctl(SIOCGIFINDEX)");
+		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFINDEX): %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 	ifindex = ifr.ifr_ifindex;
 
 	if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
-		perror("ioctl(SIOCGIFADDR)");
+		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFADDR): %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
 	if (paddr->sin_family != AF_INET) {
-		printf("Invalid address family %i (SIOCGIFADDR)\n",
-		       paddr->sin_family);
+		wpa_printf(MSG_INFO, "IAPP: Invalid address family %i (SIOCGIFADDR)",
+			   paddr->sin_family);
 		iapp_deinit(iapp);
 		return NULL;
 	}
 	iapp->own.s_addr = paddr->sin_addr.s_addr;
 
 	if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
-		perror("ioctl(SIOCGIFBRDADDR)");
+		wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFBRDADDR): %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
 	if (paddr->sin_family != AF_INET) {
-		printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
-		       paddr->sin_family);
+		wpa_printf(MSG_INFO, "Invalid address family %i (SIOCGIFBRDADDR)",
+			   paddr->sin_family);
 		iapp_deinit(iapp);
 		return NULL;
 	}
@@ -450,7 +456,8 @@
 	uaddr.sin_port = htons(IAPP_UDP_PORT);
 	if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
 		 sizeof(uaddr)) < 0) {
-		perror("bind[UDP]");
+		wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
@@ -461,14 +468,16 @@
 	mreq.imr_ifindex = 0;
 	if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
 		       sizeof(mreq)) < 0) {
-		perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
+		wpa_printf(MSG_INFO, "iapp_init - setsockopt[UDP,IP_ADD_MEMBERSHIP]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 
 	iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
 	if (iapp->packet_sock < 0) {
-		perror("socket[PF_PACKET,SOCK_RAW]");
+		wpa_printf(MSG_INFO, "iapp_init - socket[PF_PACKET,SOCK_RAW]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
@@ -478,19 +487,20 @@
 	addr.sll_ifindex = ifindex;
 	if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
 		 sizeof(addr)) < 0) {
-		perror("bind[PACKET]");
+		wpa_printf(MSG_INFO, "iapp_init - bind[PACKET]: %s",
+			   strerror(errno));
 		iapp_deinit(iapp);
 		return NULL;
 	}
 
 	if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
 				     iapp, NULL)) {
-		printf("Could not register read socket for IAPP.\n");
+		wpa_printf(MSG_INFO, "Could not register read socket for IAPP");
 		iapp_deinit(iapp);
 		return NULL;
 	}
 
-	printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
+	wpa_printf(MSG_INFO, "IEEE 802.11F (IAPP) using interface %s", iface);
 
 	/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
 	 * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
@@ -515,7 +525,8 @@
 		mreq.imr_ifindex = 0;
 		if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
 			       &mreq, sizeof(mreq)) < 0) {
-			perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
+			wpa_printf(MSG_INFO, "iapp_deinit - setsockopt[UDP,IP_DEL_MEMBERSHIP]: %s",
+				   strerror(errno));
 		}
 
 		eloop_unregister_read_sock(iapp->udp_sock);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index c7db7f4..d553caa 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -286,7 +286,7 @@
 		   MAC2STR(dst), auth_alg, auth_transaction,
 		   resp, (unsigned long) ies_len);
 	if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
-		perror("send_auth_reply: send");
+		wpa_printf(MSG_INFO, "send_auth_reply: send");
 
 	os_free(buf);
 }
@@ -552,8 +552,8 @@
 	char *radius_cui = NULL;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
-		printf("handle_auth - too short payload (len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
+			   (unsigned long) len);
 		return;
 	}
 
@@ -601,23 +601,23 @@
 #endif /* CONFIG_SAE */
 	      ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
 	       auth_alg == WLAN_AUTH_SHARED_KEY))) {
-		printf("Unsupported authentication algorithm (%d)\n",
-		       auth_alg);
+		wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
+			   auth_alg);
 		resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
 		goto fail;
 	}
 
 	if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
 	      (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
-		printf("Unknown authentication transaction number (%d)\n",
-		       auth_transaction);
+		wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
+			   auth_transaction);
 		resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
 		goto fail;
 	}
 
 	if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
-		printf("Station " MACSTR " not allowed to authenticate.\n",
-		       MAC2STR(mgmt->sa));
+		wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
+			   MAC2STR(mgmt->sa));
 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
@@ -628,8 +628,8 @@
 				      &psk, &identity, &radius_cui);
 
 	if (res == HOSTAPD_ACL_REJECT) {
-		printf("Station " MACSTR " not allowed to authenticate.\n",
-		       MAC2STR(mgmt->sa));
+		wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
+			   MAC2STR(mgmt->sa));
 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
@@ -1255,8 +1255,8 @@
 
 	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
 				      sizeof(mgmt->u.assoc_req))) {
-		printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
-		       "\n", reassoc, (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
+			   reassoc, (unsigned long) len);
 		return;
 	}
 
@@ -1442,8 +1442,8 @@
 	struct sta_info *sta;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
-		printf("handle_disassoc - too short payload (len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)",
+			   (unsigned long) len);
 		return;
 	}
 
@@ -1453,8 +1453,8 @@
 
 	sta = ap_get_sta(hapd, mgmt->sa);
 	if (sta == NULL) {
-		printf("Station " MACSTR " trying to disassociate, but it "
-		       "is not associated.\n", MAC2STR(mgmt->sa));
+		wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated",
+			   MAC2STR(mgmt->sa));
 		return;
 	}
 
@@ -1528,8 +1528,8 @@
 	struct ieee802_11_elems elems;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
-		printf("handle_beacon - too short payload (len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
+			   (unsigned long) len);
 		return;
 	}
 
@@ -1749,8 +1749,8 @@
 	      stype == WLAN_FC_STYPE_ACTION) &&
 #endif /* CONFIG_P2P */
 	    os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
-		printf("MGMT: BSSID=" MACSTR " not our address\n",
-		       MAC2STR(mgmt->bssid));
+		wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
+			   MAC2STR(mgmt->bssid));
 		return;
 	}
 
@@ -1817,8 +1817,8 @@
 	}
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
-		printf("handle_auth_cb - too short payload (len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
+			   (unsigned long) len);
 		return;
 	}
 
@@ -1828,8 +1828,8 @@
 
 	sta = ap_get_sta(hapd, mgmt->da);
 	if (!sta) {
-		printf("handle_auth_cb: STA " MACSTR " not found\n",
-		       MAC2STR(mgmt->da));
+		wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
+			   MAC2STR(mgmt->da));
 		return;
 	}
 
@@ -1879,15 +1879,15 @@
 
 	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
 				      sizeof(mgmt->u.assoc_resp))) {
-		printf("handle_assoc_cb(reassoc=%d) - too short payload "
-		       "(len=%lu)\n", reassoc, (unsigned long) len);
+		wpa_printf(MSG_INFO, "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
+			   reassoc, (unsigned long) len);
 		return;
 	}
 
 	sta = ap_get_sta(hapd, mgmt->da);
 	if (!sta) {
-		printf("handle_assoc_cb: STA " MACSTR " not found\n",
-		       MAC2STR(mgmt->da));
+		wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
+			   MAC2STR(mgmt->da));
 		return;
 	}
 
@@ -2103,7 +2103,7 @@
 		wpa_printf(MSG_DEBUG, "mgmt::action cb");
 		break;
 	default:
-		printf("unknown mgmt cb frame subtype %d\n", stype);
+		wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
 		break;
 	}
 }
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 4172218..76688b5 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -69,7 +69,7 @@
 		  WLAN_SA_QUERY_TR_ID_LEN);
 	end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
 	if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
-		perror("ieee802_11_send_sa_query_req: send");
+		wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
 }
 
 
@@ -107,7 +107,7 @@
 		  WLAN_SA_QUERY_TR_ID_LEN);
 	end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
 	if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
-		perror("ieee80211_mgmt_sa_query_request: send");
+		wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
 }
 
 
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index da6f67c..59241cb 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -453,7 +453,7 @@
 	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
 			     sm->radius_identifier);
 	if (msg == NULL) {
-		printf("Could not create net RADIUS packet\n");
+		wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
 		return;
 	}
 
@@ -462,7 +462,7 @@
 	if (sm->identity &&
 	    !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
 				 sm->identity, sm->identity_len)) {
-		printf("Could not add User-Name\n");
+		wpa_printf(MSG_INFO, "Could not add User-Name");
 		goto fail;
 	}
 
@@ -476,12 +476,12 @@
 	if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
 					    RADIUS_ATTR_FRAMED_MTU) &&
 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
-		printf("Could not add Framed-MTU\n");
+		wpa_printf(MSG_INFO, "Could not add Framed-MTU");
 		goto fail;
 	}
 
 	if (eap && !radius_msg_add_eap(msg, eap, len)) {
-		printf("Could not add EAP-Message\n");
+		wpa_printf(MSG_INFO, "Could not add EAP-Message");
 		goto fail;
 	}
 
@@ -493,8 +493,7 @@
 		int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
 					       RADIUS_ATTR_STATE);
 		if (res < 0) {
-			printf("Could not copy State attribute from previous "
-			       "Access-Challenge\n");
+			wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge");
 			goto fail;
 		}
 		if (res > 0) {
@@ -544,7 +543,7 @@
 	data = (u8 *) (eap + 1);
 
 	if (len < sizeof(*eap) + 1) {
-		printf("handle_eap_response: too short response data\n");
+		wpa_printf(MSG_INFO, "handle_eap_response: too short response data");
 		return;
 	}
 
@@ -572,7 +571,7 @@
 	u16 eap_len;
 
 	if (len < sizeof(*eap)) {
-		printf("   too short EAP packet\n");
+		wpa_printf(MSG_INFO, "   too short EAP packet");
 		return;
 	}
 
@@ -665,7 +664,7 @@
 	}
 
 	if (len < sizeof(*hdr)) {
-		printf("   too short IEEE 802.1X packet\n");
+		wpa_printf(MSG_INFO, "   too short IEEE 802.1X packet");
 		return;
 	}
 
@@ -675,7 +674,7 @@
 		   hdr->version, hdr->type, datalen);
 
 	if (len - sizeof(*hdr) < datalen) {
-		printf("   frame too short for this IEEE 802.1X packet\n");
+		wpa_printf(MSG_INFO, "   frame too short for this IEEE 802.1X packet");
 		if (sta->eapol_sm)
 			sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
 		return;
@@ -1277,15 +1276,14 @@
 			   "EAP-Message");
 	} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
 				     req, 1)) {
-		printf("Incoming RADIUS packet did not have correct "
-		       "Message-Authenticator - dropped\n");
+		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
 		return RADIUS_RX_INVALID_AUTHENTICATOR;
 	}
 
 	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
 	    hdr->code != RADIUS_CODE_ACCESS_REJECT &&
 	    hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
-		printf("Unknown RADIUS message code\n");
+		wpa_printf(MSG_INFO, "Unknown RADIUS message code");
 		return RADIUS_RX_UNKNOWN;
 	}
 
@@ -1449,7 +1447,7 @@
 	if (eapol->default_wep_key == NULL ||
 	    random_get_bytes(eapol->default_wep_key,
 			     hapd->conf->default_wep_key_len)) {
-		printf("Could not generate random WEP key.\n");
+		wpa_printf(MSG_INFO, "Could not generate random WEP key");
 		os_free(eapol->default_wep_key);
 		eapol->default_wep_key = NULL;
 		return -1;
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index d21c82f..2851672 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -157,7 +157,7 @@
 	len = ((u8 *) (t + 1)) - buf;
 
 	if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
-		perror("wmm_send_action: send");
+		wpa_printf(MSG_INFO, "wmm_send_action: send failed");
 }