Update to new version 0.8.16 from BRCM

Sync with main tree commit b8349523e460493fa0b4de36c689595109e45e91
Author: Neeraj Kumar Garg <neerajkg@broadcom.com>
Date:   Tue Dec 27 23:21:45 2011 +0200
    P2P: Reject p2p_group_add if forced frequency is not acceptable

Change-Id: Icb4541a371b05c270e80440d7a7fdea7f33ff61e
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index dbfb058..03421b3 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -236,6 +236,7 @@
 void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	struct radius_msg *msg;
+	struct os_time t;
 	int interval;
 
 	if (sta->acct_session_started)
@@ -247,7 +248,8 @@
 		       "starting accounting session %08X-%08X",
 		       sta->acct_session_id_hi, sta->acct_session_id_lo);
 
-	time(&sta->acct_session_start);
+	os_get_time(&t);
+	sta->acct_session_start = t.sec;
 	sta->last_rx_bytes = sta->last_tx_bytes = 0;
 	sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
 	hostapd_drv_sta_clear_stats(hapd, sta->addr);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index e77716b..b24cd90 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -426,6 +426,8 @@
 		ssid->dyn_vlan_keys = NULL;
 	}
 
+	os_free(conf->time_zone);
+
 #ifdef CONFIG_IEEE80211R
 	{
 		struct ft_remote_r0kh *r0kh, *r0kh_prev;
@@ -467,6 +469,12 @@
 	os_free(conf->model_url);
 	os_free(conf->upc);
 #endif /* CONFIG_WPS */
+
+	os_free(conf->roaming_consortium);
+
+#ifdef CONFIG_RADIUS_TEST
+	os_free(conf->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
 }
 
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 09eed5a..485092d 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -104,7 +104,6 @@
 	u8 addr[ETH_ALEN];
 };
 
-#define EAP_USER_MAX_METHODS 8
 struct hostapd_eap_user {
 	struct hostapd_eap_user *next;
 	u8 *identity;
@@ -112,7 +111,7 @@
 	struct {
 		int vendor;
 		u32 method;
-	} methods[EAP_USER_MAX_METHODS];
+	} methods[EAP_MAX_METHODS];
 	u8 *password;
 	size_t password_len;
 	int phase2;
@@ -142,6 +141,13 @@
 };
 
 
+#define MAX_ROAMING_CONSORTIUM_LEN 15
+
+struct hostapd_roaming_consortium {
+	u8 len;
+	u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
+};
+
 /**
  * struct hostapd_bss_config - Per-BSS configuration
  */
@@ -213,6 +219,11 @@
 	/* dot11AssociationSAQueryRetryTimeout (in TUs) */
 	int assoc_sa_query_retry_timeout;
 #endif /* CONFIG_IEEE80211W */
+	enum {
+		PSK_RADIUS_IGNORED = 0,
+		PSK_RADIUS_ACCEPTED = 1,
+		PSK_RADIUS_REQUIRED = 2
+	} wpa_psk_radius;
 	int wpa_pairwise;
 	int wpa_group;
 	int wpa_group_rekey;
@@ -329,11 +340,38 @@
 	int p2p;
 
 	int disassoc_low_ack;
+	int skip_inactivity_poll;
 
 #define TDLS_PROHIBIT BIT(0)
 #define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
 	int tdls;
 	int disable_11n;
+
+	/* IEEE 802.11v */
+	int time_advertisement;
+	char *time_zone;
+
+	/* IEEE 802.11u - Interworking */
+	int interworking;
+	int access_network_type;
+	int internet;
+	int asra;
+	int esr;
+	int uesa;
+	int venue_info_set;
+	u8 venue_group;
+	u8 venue_type;
+	u8 hessid[ETH_ALEN];
+
+	/* IEEE 802.11u - Roaming Consortium list */
+	unsigned int roaming_consortium_count;
+	struct hostapd_roaming_consortium *roaming_consortium;
+
+	u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
+
+#ifdef CONFIG_RADIUS_TEST
+	char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
 };
 
 
@@ -354,12 +392,6 @@
 		LONG_PREAMBLE = 0,
 		SHORT_PREAMBLE = 1
 	} preamble;
-	enum {
-		CTS_PROTECTION_AUTOMATIC = 0,
-		CTS_PROTECTION_FORCE_ENABLED = 1,
-		CTS_PROTECTION_FORCE_DISABLED = 2,
-		CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3,
-	} cts_protection_type;
 
 	int *supported_rates;
 	int *basic_rates;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 0b6836c..429c187 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -41,117 +41,159 @@
 }
 
 
-int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf **beacon_ret,
+			       struct wpabuf **proberesp_ret,
+			       struct wpabuf **assocresp_ret)
 {
-	struct wpabuf *beacon, *proberesp, *assocresp = NULL;
-	int ret;
+	struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL;
+	u8 buf[200], *pos;
 
-	if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
-		return 0;
+	*beacon_ret = *proberesp_ret = *assocresp_ret = NULL;
 
-	beacon = hapd->wps_beacon_ie;
-	proberesp = hapd->wps_probe_resp_ie;
-
-#ifdef CONFIG_P2P
-	if (hapd->wps_beacon_ie == NULL && hapd->p2p_beacon_ie == NULL)
-		beacon = NULL;
-	else {
-		beacon = wpabuf_alloc((hapd->wps_beacon_ie ?
-				       wpabuf_len(hapd->wps_beacon_ie) : 0) +
-				      (hapd->p2p_beacon_ie ?
-				       wpabuf_len(hapd->p2p_beacon_ie) : 0));
-		if (beacon == NULL)
-			return -1;
-		if (hapd->wps_beacon_ie)
-			wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
-		if (hapd->p2p_beacon_ie)
-			wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
+	pos = buf;
+	pos = hostapd_eid_time_adv(hapd, pos);
+	if (pos != buf) {
+		if (wpabuf_resize(&beacon, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(beacon, buf, pos - buf);
+	}
+	pos = hostapd_eid_time_zone(hapd, pos);
+	if (pos != buf) {
+		if (wpabuf_resize(&proberesp, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(proberesp, buf, pos - buf);
 	}
 
-	if (hapd->wps_probe_resp_ie == NULL && hapd->p2p_probe_resp_ie == NULL)
-		proberesp = NULL;
-	else {
-		proberesp = wpabuf_alloc(
-			(hapd->wps_probe_resp_ie ?
-			 wpabuf_len(hapd->wps_probe_resp_ie) : 0) +
-			(hapd->p2p_probe_resp_ie ?
-			 wpabuf_len(hapd->p2p_probe_resp_ie) : 0));
-		if (proberesp == NULL) {
-			wpabuf_free(beacon);
-			return -1;
-		}
-		if (hapd->wps_probe_resp_ie)
-			wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
-		if (hapd->p2p_probe_resp_ie)
-			wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
+	pos = buf;
+	pos = hostapd_eid_ext_capab(hapd, pos);
+	if (pos != buf) {
+		if (wpabuf_resize(&assocresp, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(assocresp, buf, pos - buf);
+	}
+	pos = hostapd_eid_interworking(hapd, pos);
+	pos = hostapd_eid_adv_proto(hapd, pos);
+	pos = hostapd_eid_roaming_consortium(hapd, pos);
+	if (pos != buf) {
+		if (wpabuf_resize(&beacon, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(beacon, buf, pos - buf);
+
+		if (wpabuf_resize(&proberesp, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(proberesp, buf, pos - buf);
+	}
+
+	if (hapd->wps_beacon_ie) {
+		if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) <
+		    0)
+			goto fail;
+		wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
+	}
+
+	if (hapd->wps_probe_resp_ie) {
+		if (wpabuf_resize(&proberesp,
+				  wpabuf_len(hapd->wps_probe_resp_ie)) < 0)
+			goto fail;
+		wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
+	}
+
+#ifdef CONFIG_P2P
+	if (hapd->p2p_beacon_ie) {
+		if (wpabuf_resize(&beacon, wpabuf_len(hapd->p2p_beacon_ie)) <
+		    0)
+			goto fail;
+		wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
+	}
+
+	if (hapd->p2p_probe_resp_ie) {
+		if (wpabuf_resize(&proberesp,
+				  wpabuf_len(hapd->p2p_probe_resp_ie)) < 0)
+			goto fail;
+		wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
 	}
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_P2P_MANAGER
 	if (hapd->conf->p2p & P2P_MANAGE) {
-		struct wpabuf *a;
-
-		a = wpabuf_alloc(100 + (beacon ? wpabuf_len(beacon) : 0));
-		if (a) {
+		if (wpabuf_resize(&beacon, 100) == 0) {
 			u8 *start, *p;
-			if (beacon)
-				wpabuf_put_buf(a, beacon);
-			if (beacon != hapd->wps_beacon_ie)
-				wpabuf_free(beacon);
-			start = wpabuf_put(a, 0);
+			start = wpabuf_put(beacon, 0);
 			p = hostapd_eid_p2p_manage(hapd, start);
-			wpabuf_put(a, p - start);
-			beacon = a;
+			wpabuf_put(beacon, p - start);
 		}
 
-		a = wpabuf_alloc(100 + (proberesp ? wpabuf_len(proberesp) :
-					0));
-		if (a) {
+		if (wpabuf_resize(&proberesp, 100) == 0) {
 			u8 *start, *p;
-			if (proberesp)
-				wpabuf_put_buf(a, proberesp);
-			if (proberesp != hapd->wps_probe_resp_ie)
-				wpabuf_free(proberesp);
-			start = wpabuf_put(a, 0);
+			start = wpabuf_put(proberesp, 0);
 			p = hostapd_eid_p2p_manage(hapd, start);
-			wpabuf_put(a, p - start);
-			proberesp = a;
+			wpabuf_put(proberesp, p - start);
 		}
 	}
 #endif /* CONFIG_P2P_MANAGER */
 
 #ifdef CONFIG_WPS2
-	if (hapd->conf->wps_state)
-		assocresp = wps_build_assoc_resp_ie();
+	if (hapd->conf->wps_state) {
+		struct wpabuf *a = wps_build_assoc_resp_ie();
+		if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
+			wpabuf_put_buf(assocresp, a);
+		wpabuf_free(a);
+	}
 #endif /* CONFIG_WPS2 */
 
 #ifdef CONFIG_P2P_MANAGER
 	if (hapd->conf->p2p & P2P_MANAGE) {
-		struct wpabuf *a;
-		a = wpabuf_alloc(100 + (assocresp ? wpabuf_len(assocresp) :
-					0));
-		if (a) {
+		if (wpabuf_resize(&assocresp, 100) == 0) {
 			u8 *start, *p;
-			start = wpabuf_put(a, 0);
+			start = wpabuf_put(assocresp, 0);
 			p = hostapd_eid_p2p_manage(hapd, start);
-			wpabuf_put(a, p - start);
-			if (assocresp) {
-				wpabuf_put_buf(a, assocresp);
-				wpabuf_free(assocresp);
-			}
-			assocresp = a;
+			wpabuf_put(assocresp, p - start);
 		}
 	}
 #endif /* CONFIG_P2P_MANAGER */
 
+	*beacon_ret = beacon;
+	*proberesp_ret = proberesp;
+	*assocresp_ret = assocresp;
+
+	return 0;
+
+fail:
+	wpabuf_free(beacon);
+	wpabuf_free(proberesp);
+	wpabuf_free(assocresp);
+	return -1;
+}
+
+
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf *beacon,
+			       struct wpabuf *proberesp,
+			       struct wpabuf *assocresp)
+{
+	wpabuf_free(beacon);
+	wpabuf_free(proberesp);
+	wpabuf_free(assocresp);
+}
+
+
+int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
+{
+	struct wpabuf *beacon, *proberesp, *assocresp;
+	int ret;
+
+	if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
+		return 0;
+
+	if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
+	    0)
+		return -1;
+
 	ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp,
 					  assocresp);
 
-	if (beacon != hapd->wps_beacon_ie)
-		wpabuf_free(beacon);
-	if (proberesp != hapd->wps_probe_resp_ie)
-		wpabuf_free(proberesp);
-	wpabuf_free(assocresp);
+	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
 
 	return ret;
 }
@@ -211,74 +253,6 @@
 }
 
 
-static int hostapd_set_ap_isolate(struct hostapd_data *hapd, int value)
-{
-	if (hapd->driver == NULL || hapd->driver->set_intra_bss == NULL)
-		return 0;
-	return hapd->driver->set_intra_bss(hapd->drv_priv, !value);
-}
-
-
-int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection)
-{
-	int ret = 0;
-	int preamble;
-#ifdef CONFIG_IEEE80211N
-	u8 buf[60], *ht_capab, *ht_oper, *pos;
-
-	pos = buf;
-	ht_capab = pos;
-	pos = hostapd_eid_ht_capabilities(hapd, pos);
-	ht_oper = pos;
-	pos = hostapd_eid_ht_operation(hapd, pos);
-	if (pos > ht_oper && ht_oper > ht_capab &&
-	    hostapd_set_ht_params(hapd, ht_capab + 2, ht_capab[1],
-				  ht_oper + 2, ht_oper[1])) {
-		wpa_printf(MSG_ERROR, "Could not set HT capabilities "
-			   "for kernel driver");
-		ret = -1;
-	}
-
-#endif /* CONFIG_IEEE80211N */
-
-	if (hostapd_set_cts_protect(hapd, use_protection)) {
-		wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel "
-			   "driver");
-		ret = -1;
-	}
-
-	if (hapd->iface->current_mode &&
-	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
-	    hostapd_set_short_slot_time(hapd,
-					hapd->iface->num_sta_no_short_slot_time
-					> 0 ? 0 : 1)) {
-		wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option "
-			   "in kernel driver");
-		ret = -1;
-	}
-
-	if (hapd->iface->num_sta_no_short_preamble == 0 &&
-	    hapd->iconf->preamble == SHORT_PREAMBLE)
-		preamble = SHORT_PREAMBLE;
-	else
-		preamble = LONG_PREAMBLE;
-	if (hostapd_set_preamble(hapd, preamble)) {
-		wpa_printf(MSG_ERROR, "Could not set preamble for kernel "
-			   "driver");
-		ret = -1;
-	}
-
-	if (hostapd_set_ap_isolate(hapd, hapd->conf->isolate) &&
-	    hapd->conf->isolate) {
-		wpa_printf(MSG_ERROR, "Could not enable AP isolation in "
-			   "kernel driver");
-		ret = -1;
-	}
-
-	return ret;
-}
-
-
 int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
 {
 	char force_ifname[IFNAMSIZ];
@@ -310,11 +284,41 @@
 }
 
 
+int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
+			 u16 auth_alg)
+{
+	if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
+		return 0;
+	return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
+}
+
+
+int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
+		     u16 seq, u16 status, const u8 *ie, size_t len)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_auth == NULL)
+		return 0;
+	return hapd->driver->sta_auth(hapd->drv_priv, hapd->own_addr, addr,
+				      seq, status, ie, len);
+}
+
+
+int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
+		      int reassoc, u16 status, const u8 *ie, size_t len)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_assoc == NULL)
+		return 0;
+	return hapd->driver->sta_assoc(hapd->drv_priv, hapd->own_addr, addr,
+				       reassoc, status, ie, len);
+}
+
+
 int hostapd_sta_add(struct hostapd_data *hapd,
 		    const u8 *addr, u16 aid, u16 capability,
 		    const u8 *supp_rates, size_t supp_rates_len,
 		    u16 listen_interval,
-		    const struct ieee80211_ht_capabilities *ht_capab)
+		    const struct ieee80211_ht_capabilities *ht_capab,
+		    u32 flags, u8 qosinfo)
 {
 	struct hostapd_sta_add_params params;
 
@@ -331,10 +335,22 @@
 	params.supp_rates_len = supp_rates_len;
 	params.listen_interval = listen_interval;
 	params.ht_capabilities = ht_capab;
+	params.flags = hostapd_sta_flags_to_drv(flags);
+	params.qosinfo = qosinfo;
 	return hapd->driver->sta_add(hapd->drv_priv, &params);
 }
 
 
+int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
+		      u8 *tspec_ie, size_t tspec_ielen)
+{
+	if (hapd->driver == NULL || hapd->driver->add_tspec == NULL)
+		return 0;
+	return hapd->driver->add_tspec(hapd->drv_priv, addr, tspec_ie,
+				       tspec_ielen);
+}
+
+
 int hostapd_set_privacy(struct hostapd_data *hapd, int enabled)
 {
 	if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
@@ -460,16 +476,6 @@
 }
 
 
-int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
-			  int *basic_rates, int mode)
-{
-	if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL)
-		return 0;
-	return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates,
-					   basic_rates, mode);
-}
-
-
 int hostapd_set_country(struct hostapd_data *hapd, const char *country)
 {
 	if (hapd->driver == NULL ||
@@ -479,30 +485,6 @@
 }
 
 
-int hostapd_set_cts_protect(struct hostapd_data *hapd, int value)
-{
-	if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL)
-		return 0;
-	return hapd->driver->set_cts_protect(hapd->drv_priv, value);
-}
-
-
-int hostapd_set_preamble(struct hostapd_data *hapd, int value)
-{
-	if (hapd->driver == NULL || hapd->driver->set_preamble == NULL)
-		return 0;
-	return hapd->driver->set_preamble(hapd->drv_priv, value);
-}
-
-
-int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value)
-{
-	if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL)
-		return 0;
-	return hapd->driver->set_short_slot_time(hapd->drv_priv, value);
-}
-
-
 int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
 				int cw_min, int cw_max, int burst_time)
 {
@@ -513,15 +495,6 @@
 }
 
 
-int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
-			   const u8 *mask)
-{
-	if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL)
-		return 1;
-	return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask);
-}
-
-
 struct hostapd_hw_modes *
 hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
 			    u16 *flags)
@@ -542,19 +515,6 @@
 }
 
 
-int hostapd_set_ht_params(struct hostapd_data *hapd,
-			  const u8 *ht_capab, size_t ht_capab_len,
-			  const u8 *ht_oper, size_t ht_oper_len)
-{
-	if (hapd->driver == NULL || hapd->driver->set_ht_params == NULL ||
-	    ht_capab == NULL || ht_oper == NULL)
-		return 0;
-	return hapd->driver->set_ht_params(hapd->drv_priv,
-					   ht_capab, ht_capab_len,
-					   ht_oper, ht_oper_len);
-}
-
-
 int hostapd_drv_none(struct hostapd_data *hapd)
 {
 	return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0;
@@ -604,11 +564,11 @@
 
 
 int hostapd_drv_send_mlme(struct hostapd_data *hapd,
-			  const void *msg, size_t len)
+			  const void *msg, size_t len, int noack)
 {
 	if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
 		return 0;
-	return hapd->driver->send_mlme(hapd->drv_priv, msg, len);
+	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack);
 }
 
 
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index f6076af..835cdde 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -21,13 +21,19 @@
 struct ieee80211_ht_capabilities;
 
 u32 hostapd_sta_flags_to_drv(u32 flags);
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf **beacon,
+			       struct wpabuf **proberesp,
+			       struct wpabuf **assocresp);
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
+			       struct wpabuf *proberesp,
+			       struct wpabuf *assocresp);
 int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
 int hostapd_set_authorized(struct hostapd_data *hapd,
 			   struct sta_info *sta, int authorized);
 int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta);
 int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
 			      int enabled);
-int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection);
 int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
 int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
 int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
@@ -36,7 +42,8 @@
 		    const u8 *addr, u16 aid, u16 capability,
 		    const u8 *supp_rates, size_t supp_rates_len,
 		    u16 listen_interval,
-		    const struct ieee80211_ht_capabilities *ht_capab);
+		    const struct ieee80211_ht_capabilities *ht_capab,
+		    u32 flags, u8 qosinfo);
 int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
 int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
 			     size_t elem_len);
@@ -59,23 +66,13 @@
 int hostapd_set_frag(struct hostapd_data *hapd, int frag);
 int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
 			  int total_flags, int flags_or, int flags_and);
-int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
-			  int *basic_rates, int mode);
 int hostapd_set_country(struct hostapd_data *hapd, const char *country);
-int hostapd_set_cts_protect(struct hostapd_data *hapd, int value);
-int hostapd_set_preamble(struct hostapd_data *hapd, int value);
-int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value);
 int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
 				int cw_min, int cw_max, int burst_time);
-int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
-			   const u8 *mask);
 struct hostapd_hw_modes *
 hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
 			    u16 *flags);
 int hostapd_driver_commit(struct hostapd_data *hapd);
-int hostapd_set_ht_params(struct hostapd_data *hapd,
-			  const u8 *ht_capab, size_t ht_capab_len,
-			  const u8 *ht_oper, size_t ht_oper_len);
 int hostapd_drv_none(struct hostapd_data *hapd);
 int hostapd_driver_scan(struct hostapd_data *hapd,
 			struct wpa_driver_scan_params *params);
@@ -90,11 +87,19 @@
 			const u8 *seq, size_t seq_len,
 			const u8 *key, size_t key_len);
 int hostapd_drv_send_mlme(struct hostapd_data *hapd,
-			  const void *msg, size_t len);
+			  const void *msg, size_t len, int noack);
 int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
 			   const u8 *addr, int reason);
 int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
 			     const u8 *addr, int reason);
+int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
+			 u16 auth_alg);
+int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
+		     u16 seq, u16 status, const u8 *ie, size_t len);
+int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
+		      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);
 
 
 #include "drivers/driver.h"
@@ -163,16 +168,12 @@
 	return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
 }
 
-static inline int hostapd_drv_set_beacon(struct hostapd_data *hapd,
-					 const u8 *head, size_t head_len,
-					 const u8 *tail, size_t tail_len,
-					 int dtim_period, int beacon_int)
+static inline int hostapd_drv_set_ap(struct hostapd_data *hapd,
+				     struct wpa_driver_ap_params *params)
 {
-	if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
+	if (hapd->driver == NULL || hapd->driver->set_ap == NULL)
 		return 0;
-	return hapd->driver->set_beacon(hapd->drv_priv,
-					head, head_len, tail, tail_len,
-					dtim_period, beacon_int);
+	return hapd->driver->set_ap(hapd->drv_priv, params);
 }
 
 static inline int hostapd_drv_set_radius_acl_auth(struct hostapd_data *hapd,
@@ -202,4 +203,13 @@
 	return hapd->driver->set_authmode(hapd->drv_priv, auth_algs);
 }
 
+static inline void hostapd_drv_poll_client(struct hostapd_data *hapd,
+					   const u8 *own_addr, const u8 *addr,
+					   int qos)
+{
+	if (hapd->driver == NULL || hapd->driver->poll_client == NULL)
+		return;
+	hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
+}
+
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 7c87fde..6f56c95 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -60,7 +60,7 @@
 				       struct eap_user *user)
 {
 	const struct hostapd_eap_user *eap_user;
-	int i, count;
+	int i;
 
 	eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
 	if (eap_user == NULL)
@@ -70,10 +70,7 @@
 		return 0;
 
 	os_memset(user, 0, sizeof(*user));
-	count = EAP_USER_MAX_METHODS;
-	if (count > EAP_MAX_METHODS)
-		count = EAP_MAX_METHODS;
-	for (i = 0; i < count; i++) {
+	for (i = 0; i < EAP_MAX_METHODS; i++) {
 		user->methods[i].vendor = eap_user->methods[i].vendor;
 		user->methods[i].method = eap_user->methods[i].method;
 	}
@@ -120,6 +117,9 @@
 	srv.eap_req_id_text = conf->eap_req_id_text;
 	srv.eap_req_id_text_len = conf->eap_req_id_text_len;
 	srv.pwd_group = conf->pwd_group;
+#ifdef CONFIG_RADIUS_TEST
+	srv.dump_msk_file = conf->dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
 
 	hapd->radius_srv = radius_server_init(&srv);
 	if (hapd->radius_srv == NULL) {
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 0091064..4d8b277 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -35,6 +35,8 @@
 #include "beacon.h"
 
 
+#ifdef NEED_AP_MLME
+
 static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
 {
 	u8 erp = 0;
@@ -43,23 +45,11 @@
 	    hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
 		return 0;
 
-	switch (hapd->iconf->cts_protection_type) {
-	case CTS_PROTECTION_FORCE_ENABLED:
-		erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION;
-		break;
-	case CTS_PROTECTION_FORCE_DISABLED:
-		erp = 0;
-		break;
-	case CTS_PROTECTION_AUTOMATIC:
-		if (hapd->iface->olbc)
-			erp |= ERP_INFO_USE_PROTECTION;
-		/* continue */
-	case CTS_PROTECTION_AUTOMATIC_NO_OLBC:
-		if (hapd->iface->num_sta_non_erp > 0) {
-			erp |= ERP_INFO_NON_ERP_PRESENT |
-				ERP_INFO_USE_PROTECTION;
-		}
-		break;
+	if (hapd->iface->olbc)
+		erp |= ERP_INFO_USE_PROTECTION;
+	if (hapd->iface->num_sta_non_erp > 0) {
+		erp |= ERP_INFO_NON_ERP_PRESENT |
+			ERP_INFO_USE_PROTECTION;
 	}
 	if (hapd->iface->num_sta_no_short_preamble > 0 ||
 	    hapd->iconf->preamble == LONG_PREAMBLE)
@@ -182,8 +172,7 @@
 }
 
 
-static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
-			    struct sta_info *sta)
+static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
 {
 	const u8 *ie;
 	size_t ielen;
@@ -197,30 +186,134 @@
 }
 
 
+static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
+				   struct sta_info *sta,
+				   const struct ieee80211_mgmt *req,
+				   int is_p2p, size_t *resp_len)
+{
+	struct ieee80211_mgmt *resp;
+	u8 *pos, *epos;
+	size_t buflen;
+
+#define MAX_PROBERESP_LEN 768
+	buflen = MAX_PROBERESP_LEN;
+#ifdef CONFIG_WPS
+	if (hapd->wps_probe_resp_ie)
+		buflen += wpabuf_len(hapd->wps_probe_resp_ie);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	if (hapd->p2p_probe_resp_ie)
+		buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
+#endif /* CONFIG_P2P */
+	resp = os_zalloc(buflen);
+	if (resp == NULL)
+		return NULL;
+
+	epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
+
+	resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_PROBE_RESP);
+	if (req)
+		os_memcpy(resp->da, req->sa, ETH_ALEN);
+	os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+
+	os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+	resp->u.probe_resp.beacon_int =
+		host_to_le16(hapd->iconf->beacon_int);
+
+	/* hardware or low-level driver will setup seq_ctrl and timestamp */
+	resp->u.probe_resp.capab_info =
+		host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
+
+	pos = resp->u.probe_resp.variable;
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = hapd->conf->ssid.ssid_len;
+	os_memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len);
+	pos += hapd->conf->ssid.ssid_len;
+
+	/* Supported rates */
+	pos = hostapd_eid_supp_rates(hapd, pos);
+
+	/* DS Params */
+	pos = hostapd_eid_ds_params(hapd, pos);
+
+	pos = hostapd_eid_country(hapd, pos, epos - pos);
+
+	/* ERP Information element */
+	pos = hostapd_eid_erp_info(hapd, pos);
+
+	/* Extended supported rates */
+	pos = hostapd_eid_ext_supp_rates(hapd, pos);
+
+	/* RSN, MDIE, WPA */
+	pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+
+#ifdef CONFIG_IEEE80211N
+	pos = hostapd_eid_ht_capabilities(hapd, pos);
+	pos = hostapd_eid_ht_operation(hapd, pos);
+#endif /* CONFIG_IEEE80211N */
+
+	pos = hostapd_eid_ext_capab(hapd, pos);
+
+	pos = hostapd_eid_time_adv(hapd, pos);
+	pos = hostapd_eid_time_zone(hapd, pos);
+
+	pos = hostapd_eid_interworking(hapd, pos);
+	pos = hostapd_eid_adv_proto(hapd, pos);
+	pos = hostapd_eid_roaming_consortium(hapd, pos);
+
+	/* Wi-Fi Alliance WMM */
+	pos = hostapd_eid_wmm(hapd, pos);
+
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
+		os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
+			  wpabuf_len(hapd->wps_probe_resp_ie));
+		pos += wpabuf_len(hapd->wps_probe_resp_ie);
+	}
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	if ((hapd->conf->p2p & P2P_ENABLED) && is_p2p &&
+	    hapd->p2p_probe_resp_ie) {
+		os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie),
+			  wpabuf_len(hapd->p2p_probe_resp_ie));
+		pos += wpabuf_len(hapd->p2p_probe_resp_ie);
+	}
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_P2P_MANAGER
+	if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
+	    P2P_MANAGE)
+		pos = hostapd_eid_p2p_manage(hapd, pos);
+#endif /* CONFIG_P2P_MANAGER */
+
+	*resp_len = pos - (u8 *) resp;
+	return (u8 *) resp;
+}
+
+
 void handle_probe_req(struct hostapd_data *hapd,
 		      const struct ieee80211_mgmt *mgmt, size_t len)
 {
-	struct ieee80211_mgmt *resp;
+	u8 *resp;
 	struct ieee802_11_elems elems;
-	char *ssid;
-	u8 *pos, *epos;
 	const u8 *ie;
-	size_t ssid_len, ie_len;
+	size_t ie_len;
 	struct sta_info *sta = NULL;
-	size_t buflen;
-	size_t i;
+	size_t i, resp_len;
+	int noack;
 
 	ie = mgmt->u.probe_req.variable;
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
 		return;
 	ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
 
-#ifndef ANDROID_BRCM_P2P_PATCH
 	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
 		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
-					    mgmt->sa, ie, ie_len) > 0)
+					    mgmt->sa, mgmt->da, mgmt->bssid,
+					    ie, ie_len) > 0)
 			return;
-#endif
+
 	if (!hapd->iconf->send_probe_response)
 		return;
 
@@ -230,9 +323,6 @@
 		return;
 	}
 
-	ssid = NULL;
-	ssid_len = 0;
-
 	if ((!elems.ssid || !elems.supp_rates)) {
 		wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
 			   "without SSID or supported rates element",
@@ -277,13 +367,9 @@
 	    (elems.ssid_len == hapd->conf->ssid.ssid_len &&
 	     os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) ==
 	     0)) {
-		ssid = hapd->conf->ssid.ssid;
-		ssid_len = hapd->conf->ssid.ssid_len;
 		if (sta)
 			sta->ssid_probe = &hapd->conf->ssid;
-	}
-
-	if (!ssid) {
+	} else {
 		if (!(mgmt->da[0] & 0x01)) {
 			char ssid_txt[33];
 			ieee802_11_print_ssid(ssid_txt, elems.ssid,
@@ -296,92 +382,51 @@
 		return;
 	}
 
+#ifdef CONFIG_INTERWORKING
+	if (elems.interworking && elems.interworking_len >= 1) {
+		u8 ant = elems.interworking[0] & 0x0f;
+		if (ant != INTERWORKING_ANT_WILDCARD &&
+		    ant != hapd->conf->access_network_type) {
+			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+				   " for mismatching ANT %u ignored",
+				   MAC2STR(mgmt->sa), ant);
+			return;
+		}
+	}
+
+	if (elems.interworking &&
+	    (elems.interworking_len == 7 || elems.interworking_len == 9)) {
+		const u8 *hessid;
+		if (elems.interworking_len == 7)
+			hessid = elems.interworking + 1;
+		else
+			hessid = elems.interworking + 1 + 2;
+		if (!is_broadcast_ether_addr(hessid) &&
+		    os_memcmp(hessid, hapd->conf->hessid, ETH_ALEN) != 0) {
+			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+				   " for mismatching HESSID " MACSTR
+				   " ignored",
+				   MAC2STR(mgmt->sa), MAC2STR(hessid));
+			return;
+		}
+	}
+#endif /* CONFIG_INTERWORKING */
+
 	/* TODO: verify that supp_rates contains at least one matching rate
 	 * with AP configuration */
-#define MAX_PROBERESP_LEN 768
-	buflen = MAX_PROBERESP_LEN;
-#ifdef CONFIG_WPS
-	if (hapd->wps_probe_resp_ie)
-		buflen += wpabuf_len(hapd->wps_probe_resp_ie);
-#endif /* CONFIG_WPS */
-#ifdef CONFIG_P2P
-	if (hapd->p2p_probe_resp_ie)
-		buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
-#endif /* CONFIG_P2P */
-	resp = os_zalloc(buflen);
+
+	resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
+				      &resp_len);
 	if (resp == NULL)
 		return;
-	epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
 
-	resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_PROBE_RESP);
-	os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
-	os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+	/*
+	 * If this is a broadcast probe request, apply no ack policy to avoid
+	 * excessive retries.
+	 */
+	noack = !!(elems.ssid_len == 0 && is_broadcast_ether_addr(mgmt->da));
 
-	os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
-	resp->u.probe_resp.beacon_int =
-		host_to_le16(hapd->iconf->beacon_int);
-
-	/* hardware or low-level driver will setup seq_ctrl and timestamp */
-	resp->u.probe_resp.capab_info =
-		host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
-
-	pos = resp->u.probe_resp.variable;
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = ssid_len;
-	os_memcpy(pos, ssid, ssid_len);
-	pos += ssid_len;
-
-	/* Supported rates */
-	pos = hostapd_eid_supp_rates(hapd, pos);
-
-	/* DS Params */
-	pos = hostapd_eid_ds_params(hapd, pos);
-
-	pos = hostapd_eid_country(hapd, pos, epos - pos);
-
-	/* ERP Information element */
-	pos = hostapd_eid_erp_info(hapd, pos);
-
-	/* Extended supported rates */
-	pos = hostapd_eid_ext_supp_rates(hapd, pos);
-
-	/* RSN, MDIE, WPA */
-	pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
-
-#ifdef CONFIG_IEEE80211N
-	pos = hostapd_eid_ht_capabilities(hapd, pos);
-	pos = hostapd_eid_ht_operation(hapd, pos);
-#endif /* CONFIG_IEEE80211N */
-
-	pos = hostapd_eid_ext_capab(hapd, pos);
-
-	/* Wi-Fi Alliance WMM */
-	pos = hostapd_eid_wmm(hapd, pos);
-
-#ifdef CONFIG_WPS
-	if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
-		os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
-			  wpabuf_len(hapd->wps_probe_resp_ie));
-		pos += wpabuf_len(hapd->wps_probe_resp_ie);
-	}
-#endif /* CONFIG_WPS */
-
-#ifdef CONFIG_P2P
-	if ((hapd->conf->p2p & P2P_ENABLED) && elems.p2p &&
-	    hapd->p2p_probe_resp_ie) {
-		os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie),
-			  wpabuf_len(hapd->p2p_probe_resp_ie));
-		pos += wpabuf_len(hapd->p2p_probe_resp_ie);
-	}
-#endif /* CONFIG_P2P */
-#ifdef CONFIG_P2P_MANAGER
-	if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
-	    P2P_MANAGE)
-		pos = hostapd_eid_p2p_manage(hapd, pos);
-#endif /* CONFIG_P2P_MANAGER */
-
-	if (hostapd_drv_send_mlme(hapd, resp, pos - (u8 *) resp) < 0)
+	if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
 		perror("handle_probe_req: send");
 
 	os_free(resp);
@@ -392,17 +437,61 @@
 }
 
 
-void ieee802_11_set_beacon(struct hostapd_data *hapd)
+static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
+					size_t *resp_len)
 {
-	struct ieee80211_mgmt *head;
-	u8 *pos, *tail, *tailpos;
-	u16 capab_info;
-	size_t head_len, tail_len;
+	/* check probe response offloading caps and print warnings */
+	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD))
+		return NULL;
+
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->wps_probe_resp_ie &&
+	    (!(hapd->iface->probe_resp_offloads &
+	       (WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS |
+		WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2))))
+		wpa_printf(MSG_WARNING, "Device is trying to offload WPS "
+			   "Probe Response while not supporting this");
+#endif /* CONFIG_WPS */
 
 #ifdef CONFIG_P2P
-	if ((hapd->conf->p2p & (P2P_ENABLED | P2P_GROUP_OWNER)) == P2P_ENABLED)
-		goto no_beacon;
-#endif /* CONFIG_P2P */
+	if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_probe_resp_ie &&
+	    !(hapd->iface->probe_resp_offloads &
+	      WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P))
+		wpa_printf(MSG_WARNING, "Device is trying to offload P2P "
+			   "Probe Response while not supporting this");
+#endif  /* CONFIG_P2P */
+
+	if (hapd->conf->interworking &&
+	    !(hapd->iface->probe_resp_offloads &
+	      WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING))
+		wpa_printf(MSG_WARNING, "Device is trying to offload "
+			   "Interworking Probe Response while not supporting "
+			   "this");
+
+	/* Generate a Probe Response template for the non-P2P case */
+	return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len);
+}
+
+#endif /* NEED_AP_MLME */
+
+
+void ieee802_11_set_beacon(struct hostapd_data *hapd)
+{
+	struct ieee80211_mgmt *head = NULL;
+	u8 *tail = NULL;
+	size_t head_len = 0, tail_len = 0;
+	u8 *resp = NULL;
+	size_t resp_len = 0;
+	struct wpa_driver_ap_params params;
+	struct wpabuf *beacon, *proberesp, *assocresp;
+#ifdef NEED_AP_MLME
+	u16 capab_info;
+	u8 *pos, *tailpos;
+#endif /* NEED_AP_MLME */
+
+	hapd->beacon_set_done = 1;
+
+#ifdef NEED_AP_MLME
 
 #define BEACON_HEAD_BUF_SIZE 256
 #define BEACON_TAIL_BUF_SIZE 512
@@ -474,7 +563,7 @@
 
 	/* RSN, MDIE, WPA */
 	tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
-				  tailpos, NULL);
+				  tailpos);
 
 #ifdef CONFIG_IEEE80211N
 	tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
@@ -483,6 +572,16 @@
 
 	tailpos = hostapd_eid_ext_capab(hapd, tailpos);
 
+	/*
+	 * TODO: Time Advertisement element should only be included in some
+	 * DTIM Beacon frames.
+	 */
+	tailpos = hostapd_eid_time_adv(hapd, tailpos);
+
+	tailpos = hostapd_eid_interworking(hapd, tailpos);
+	tailpos = hostapd_eid_adv_proto(hapd, tailpos);
+	tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
+
 	/* Wi-Fi Alliance WMM */
 	tailpos = hostapd_eid_wmm(hapd, tailpos);
 
@@ -509,20 +608,75 @@
 
 	tail_len = tailpos > tail ? tailpos - tail : 0;
 
-	if (hostapd_drv_set_beacon(hapd, (u8 *) head, head_len,
-				   tail, tail_len, hapd->conf->dtim_period,
-				   hapd->iconf->beacon_int))
-		wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM "
-			   "period");
+	resp = hostapd_probe_resp_offloads(hapd, &resp_len);
+#endif /* NEED_AP_MLME */
+
+	os_memset(&params, 0, sizeof(params));
+	params.head = (u8 *) head;
+	params.head_len = head_len;
+	params.tail = tail;
+	params.tail_len = tail_len;
+	params.proberesp = resp;
+	params.proberesp_len = resp_len;
+	params.dtim_period = hapd->conf->dtim_period;
+	params.beacon_int = hapd->iconf->beacon_int;
+	params.basic_rates = hapd->iconf->basic_rates;
+	params.ssid = (u8 *) hapd->conf->ssid.ssid;
+	params.ssid_len = hapd->conf->ssid.ssid_len;
+	params.pairwise_ciphers = hapd->conf->rsn_pairwise ?
+		hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
+	params.group_cipher = hapd->conf->wpa_group;
+	params.key_mgmt_suites = hapd->conf->wpa_key_mgmt;
+	params.auth_algs = hapd->conf->auth_algs;
+	params.wpa_version = hapd->conf->wpa;
+	params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+		(hapd->conf->ieee802_1x &&
+		 (hapd->conf->default_wep_key_len ||
+		  hapd->conf->individual_wep_key_len));
+	switch (hapd->conf->ignore_broadcast_ssid) {
+	case 0:
+		params.hide_ssid = NO_SSID_HIDING;
+		break;
+	case 1:
+		params.hide_ssid = HIDDEN_SSID_ZERO_LEN;
+		break;
+	case 2:
+		params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
+		break;
+	}
+	hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp);
+	params.beacon_ies = beacon;
+	params.proberesp_ies = proberesp;
+	params.assocresp_ies = assocresp;
+	params.isolate = hapd->conf->isolate;
+#ifdef NEED_AP_MLME
+	params.cts_protect = !!(ieee802_11_erp_info(hapd) &
+				ERP_INFO_USE_PROTECTION);
+	params.preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
+		hapd->iconf->preamble == SHORT_PREAMBLE;
+	if (hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+		params.short_slot_time =
+			hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1;
+	else
+		params.short_slot_time = -1;
+	if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
+		params.ht_opmode = -1;
+	else
+		params.ht_opmode = hapd->iface->ht_op_mode;
+#endif /* NEED_AP_MLME */
+	params.interworking = hapd->conf->interworking;
+	if (hapd->conf->interworking &&
+	    !is_zero_ether_addr(hapd->conf->hessid))
+		params.hessid = hapd->conf->hessid;
+	params.access_network_type = hapd->conf->access_network_type;
+	if (hostapd_drv_set_ap(hapd, &params))
+		wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
+	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
 
 	os_free(tail);
 	os_free(head);
-
-#ifdef CONFIG_P2P
-no_beacon:
-#endif /* CONFIG_P2P */
-	hostapd_set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) &
-					ERP_INFO_USE_PROTECTION));
+	os_free(resp);
 }
 
 
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index c1510e1..a944f5f 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -20,17 +20,7 @@
 
 void handle_probe_req(struct hostapd_data *hapd,
 		      const struct ieee80211_mgmt *mgmt, size_t len);
-#ifdef NEED_AP_MLME
 void ieee802_11_set_beacon(struct hostapd_data *hapd);
 void ieee802_11_set_beacons(struct hostapd_iface *iface);
-#else /* NEED_AP_MLME */
-static inline void ieee802_11_set_beacon(struct hostapd_data *hapd)
-{
-}
-
-static inline void ieee802_11_set_beacons(struct hostapd_iface *iface)
-{
-}
-#endif /* NEED_AP_MLME */
 
 #endif /* BEACON_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 10e3af9..b7febdc 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -19,7 +19,6 @@
 #include "drivers/driver.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
-#include "common/wpa_ctrl.h"
 #include "crypto/random.h"
 #include "p2p/p2p.h"
 #include "wps/wps.h"
@@ -28,25 +27,22 @@
 #include "sta_info.h"
 #include "accounting.h"
 #include "tkip_countermeasures.h"
-#include "iapp.h"
 #include "ieee802_1x.h"
 #include "wpa_auth.h"
-#include "wmm.h"
 #include "wps_hostapd.h"
 #include "ap_drv_ops.h"
 #include "ap_config.h"
 
 
 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
-			const u8 *ie, size_t ielen, int reassoc)
+			const u8 *req_ies, size_t req_ies_len, int reassoc)
 {
 	struct sta_info *sta;
 	int new_assoc, res;
 	struct ieee802_11_elems elems;
-#ifdef CONFIG_P2P
-	const u8 *all_ies = ie;
-	size_t all_ies_len = ielen;
-#endif /* CONFIG_P2P */
+	const u8 *ie;
+	size_t ielen;
+	u16 reason = WLAN_REASON_UNSPECIFIED;
 
 	if (addr == NULL) {
 		/*
@@ -65,7 +61,7 @@
 	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO, "associated");
 
-	ieee802_11_parse_elems(ie, ielen, &elems, 0);
+	ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
 	if (elems.wps_ie) {
 		ie = elems.wps_ie - 2;
 		ielen = elems.wps_ie_len + 2;
@@ -93,18 +89,19 @@
 		if (sta == NULL)
 			return -1;
 	}
-	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
 
 #ifdef CONFIG_P2P
 	if (elems.p2p) {
 		wpabuf_free(sta->p2p_ie);
-		sta->p2p_ie = ieee802_11_vendor_ie_concat(all_ies, all_ies_len,
+		sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
 							  P2P_IE_VENDOR_TYPE);
 	}
 #endif /* CONFIG_P2P */
 
 	if (hapd->conf->wpa) {
 		if (ie == NULL || ielen == 0) {
+#ifdef CONFIG_WPS
 			if (hapd->conf->wps_state) {
 				wpa_printf(MSG_DEBUG, "STA did not include "
 					   "WPA/RSN IE in (Re)Association "
@@ -112,15 +109,29 @@
 				sta->flags |= WLAN_STA_MAYBE_WPS;
 				goto skip_wpa_check;
 			}
+#endif /* CONFIG_WPS */
 
 			wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
 			return -1;
 		}
+#ifdef CONFIG_WPS
 		if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
 		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
+			struct wpabuf *wps;
 			sta->flags |= WLAN_STA_WPS;
+			wps = ieee802_11_vendor_ie_concat(ie, ielen,
+							  WPS_IE_VENDOR_TYPE);
+			if (wps) {
+				if (wps_is_20(wps)) {
+					wpa_printf(MSG_DEBUG, "WPS: STA "
+						   "supports WPS 2.0");
+					sta->flags |= WLAN_STA_WPS2;
+				}
+				wpabuf_free(wps);
+			}
 			goto skip_wpa_check;
 		}
+#endif /* CONFIG_WPS */
 
 		if (sta->wpa_sm == NULL)
 			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
@@ -133,52 +144,55 @@
 		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
 					  ie, ielen, NULL, 0);
 		if (res != WPA_IE_OK) {
-			int resp;
 			wpa_printf(MSG_DEBUG, "WPA/RSN information element "
 				   "rejected? (res %u)", res);
 			wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
 			if (res == WPA_INVALID_GROUP)
-				resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
 			else if (res == WPA_INVALID_PAIRWISE)
-				resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
+				reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
 			else if (res == WPA_INVALID_AKMP)
-				resp = WLAN_REASON_AKMP_NOT_VALID;
+				reason = WLAN_REASON_AKMP_NOT_VALID;
 #ifdef CONFIG_IEEE80211W
 			else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
-				resp = WLAN_REASON_INVALID_IE;
+				reason = WLAN_REASON_INVALID_IE;
 			else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
-				resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
 #endif /* CONFIG_IEEE80211W */
 			else
-				resp = WLAN_REASON_INVALID_IE;
-			hostapd_drv_sta_disassoc(hapd, sta->addr, resp);
-			ap_free_sta(hapd, sta);
-			return -1;
+				reason = WLAN_REASON_INVALID_IE;
+			goto fail;
 		}
 	} else if (hapd->conf->wps_state) {
-#ifdef CONFIG_WPS_STRICT
-		if (ie) {
-			struct wpabuf *wps;
-			wps = ieee802_11_vendor_ie_concat(ie, ielen,
+#ifdef CONFIG_WPS
+		struct wpabuf *wps;
+		if (req_ies)
+			wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
 							  WPS_IE_VENDOR_TYPE);
-			if (wps && wps_validate_assoc_req(wps) < 0) {
-				hostapd_drv_sta_disassoc(
-					hapd, sta->addr,
-					WLAN_REASON_INVALID_IE);
-				ap_free_sta(hapd, sta);
-				wpabuf_free(wps);
-				return -1;
-			}
+		else
+			wps = NULL;
+#ifdef CONFIG_WPS_STRICT
+		if (wps && wps_validate_assoc_req(wps) < 0) {
+			reason = WLAN_REASON_INVALID_IE;
 			wpabuf_free(wps);
+			goto fail;
 		}
 #endif /* CONFIG_WPS_STRICT */
-		if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 &&
-		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
+		if (wps) {
 			sta->flags |= WLAN_STA_WPS;
+			if (wps_is_20(wps)) {
+				wpa_printf(MSG_DEBUG, "WPS: STA supports "
+					   "WPS 2.0");
+				sta->flags |= WLAN_STA_WPS2;
+			}
 		} else
 			sta->flags |= WLAN_STA_MAYBE_WPS;
+		wpabuf_free(wps);
+#endif /* CONFIG_WPS */
 	}
+#ifdef CONFIG_WPS
 skip_wpa_check:
+#endif /* CONFIG_WPS */
 
 	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
 	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
@@ -189,11 +203,18 @@
 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
 
 #ifdef CONFIG_P2P
-	p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
-			      all_ies, all_ies_len);
+	if (req_ies) {
+		p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
+				      req_ies, req_ies_len);
+	}
 #endif /* CONFIG_P2P */
 
 	return 0;
+
+fail:
+	hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
+	ap_free_sta(hapd, sta);
+	return -1;
 }
 
 
@@ -224,14 +245,8 @@
 		return;
 	}
 
+	ap_sta_set_authorized(hapd, sta, 0);
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-		MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if(hapd->msg_ctx_parent)
-		wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-			MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
 	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -255,8 +270,8 @@
 }
 
 
-int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
-			 const u8 *ie, size_t ie_len)
+int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
+			 const u8 *bssid, const u8 *ie, size_t ie_len)
 {
 	size_t i;
 	int ret = 0;
@@ -267,7 +282,7 @@
 	random_add_randomness(sa, ETH_ALEN);
 	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
 		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
-					    sa, ie, ie_len) > 0) {
+					    sa, da, bssid, ie, ie_len) > 0) {
 			ret = 1;
 			break;
 		}
@@ -280,46 +295,6 @@
 
 #ifdef NEED_AP_MLME
 
-static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
-{
-	u16 fc, type, stype;
-
-	/*
-	 * PS-Poll frames are 16 bytes. All other frames are
-	 * 24 bytes or longer.
-	 */
-	if (len < 16)
-		return NULL;
-
-	fc = le_to_host16(hdr->frame_control);
-	type = WLAN_FC_GET_TYPE(fc);
-	stype = WLAN_FC_GET_STYPE(fc);
-
-	switch (type) {
-	case WLAN_FC_TYPE_DATA:
-		if (len < 24)
-			return NULL;
-		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
-		case WLAN_FC_FROMDS | WLAN_FC_TODS:
-		case WLAN_FC_TODS:
-			return hdr->addr1;
-		case WLAN_FC_FROMDS:
-			return hdr->addr2;
-		default:
-			return NULL;
-		}
-	case WLAN_FC_TYPE_CTRL:
-		if (stype != WLAN_FC_STYPE_PSPOLL)
-			return NULL;
-		return hdr->addr1;
-	case WLAN_FC_TYPE_MGMT:
-		return hdr->addr3;
-	default:
-		return NULL;
-	}
-}
-
-
 #define HAPD_BROADCAST ((struct hostapd_data *) -1)
 
 static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
@@ -343,17 +318,14 @@
 
 
 static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
-					const u8 *frame, size_t len)
+					const u8 *bssid, const u8 *addr,
+					int wds)
 {
-	const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
-	u16 fc = le_to_host16(hdr->frame_control);
-	hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
+	hapd = get_hapd_bssid(hapd->iface, bssid);
 	if (hapd == NULL || hapd == HAPD_BROADCAST)
 		return;
 
-	ieee802_11_rx_from_unknown(hapd, hdr->addr2,
-				   (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
-				   (WLAN_FC_TODS | WLAN_FC_FROMDS));
+	ieee802_11_rx_from_unknown(hapd, addr, wds);
 }
 
 
@@ -497,6 +469,23 @@
 			  union wpa_event_data *data)
 {
 	struct hostapd_data *hapd = ctx;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	int level = MSG_DEBUG;
+
+	if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame &&
+	    data->rx_mgmt.frame_len >= 24) {
+		const struct ieee80211_hdr *hdr;
+		u16 fc;
+		hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
+		fc = le_to_host16(hdr->frame_control);
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+			level = MSG_EXCESSIVE;
+	}
+
+	wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
+		event_to_string(event), event);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
 
 	switch (event) {
 	case EVENT_MICHAEL_MIC_FAILURE:
@@ -532,9 +521,19 @@
 			break;
 		}
 		break;
+	case EVENT_EAPOL_TX_STATUS:
+		hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
+					data->eapol_tx_status.data,
+					data->eapol_tx_status.data_len,
+					data->eapol_tx_status.ack);
+		break;
+	case EVENT_DRIVER_CLIENT_POLL_OK:
+		hostapd_client_poll_ok(hapd, data->client_poll.addr);
+		break;
 	case EVENT_RX_FROM_UNKNOWN:
-		hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame,
-					    data->rx_from_unknown.len);
+		hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid,
+					    data->rx_from_unknown.addr,
+					    data->rx_from_unknown.wds);
 		break;
 	case EVENT_RX_MGMT:
 		hostapd_mgmt_rx(hapd, &data->rx_mgmt);
@@ -545,6 +544,8 @@
 		    data->rx_probe_req.ie == NULL)
 			break;
 		hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
+				     data->rx_probe_req.da,
+				     data->rx_probe_req.bssid,
 				     data->rx_probe_req.ie,
 				     data->rx_probe_req.ie_len);
 		break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index f00a544..0c5ee2e 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -61,9 +61,11 @@
 	else
 		hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
 
-	if (hapd->conf->wpa && hapd->wpa_auth == NULL)
+	if (hapd->conf->wpa && hapd->wpa_auth == NULL) {
 		hostapd_setup_wpa(hapd);
-	else if (hapd->conf->wpa) {
+		if (hapd->wpa_auth)
+			wpa_init_keys(hapd->wpa_auth);
+	} else if (hapd->conf->wpa) {
 		const u8 *wpa_ie;
 		size_t wpa_ie_len;
 		hostapd_reconfig_wpa(hapd);
@@ -259,6 +261,8 @@
 	wpabuf_free(hapd->p2p_probe_resp_ie);
 	hapd->p2p_probe_resp_ie = NULL;
 #endif /* CONFIG_P2P */
+
+	wpabuf_free(hapd->time_adv);
 }
 
 
@@ -287,6 +291,8 @@
 	iface->hw_features = NULL;
 	os_free(iface->current_rates);
 	iface->current_rates = NULL;
+	os_free(iface->basic_rates);
+	iface->basic_rates = NULL;
 	ap_list_deinit(iface);
 	hostapd_config_free(iface->conf);
 	iface->conf = NULL;
@@ -341,12 +347,13 @@
 	if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
 		return 0;
 
-	wpa_printf(MSG_DEBUG, "Flushing old station entries");
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries");
 	if (hostapd_flush(hapd)) {
-		wpa_printf(MSG_WARNING, "Could not connect to kernel driver.");
+		wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to "
+			"kernel driver");
 		ret = -1;
 	}
-	wpa_printf(MSG_DEBUG, "Deauthenticate all stations");
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
 	os_memset(addr, 0xff, ETH_ALEN);
 	hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
 	hostapd_free_stas(hapd);
@@ -367,7 +374,6 @@
 	u8 mask[ETH_ALEN] = { 0 };
 	struct hostapd_data *hapd = iface->bss[0];
 	unsigned int i = iface->conf->num_bss, bits = 0, j;
-	int res;
 	int auto_addr = 0;
 
 	if (hostapd_drv_none(hapd))
@@ -431,17 +437,6 @@
 	wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
 		   (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits);
 
-	res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask);
-	if (res == 0)
-		return 0;
-
-	if (res < 0) {
-		wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask "
-			   MACSTR " for start address " MACSTR ".",
-			   MAC2STR(mask), MAC2STR(hapd->own_addr));
-		return -1;
-	}
-
 	if (!auto_addr)
 		return 0;
 
@@ -639,6 +634,9 @@
 
 	ieee802_11_set_beacon(hapd);
 
+	if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
+		return -1;
+
 	if (hapd->driver && hapd->driver->set_operstate)
 		hapd->driver->set_operstate(hapd->drv_priv, 1);
 
@@ -746,7 +744,7 @@
 	}
 
 	if (iface->current_mode) {
-		if (hostapd_prepare_rates(hapd, iface->current_mode)) {
+		if (hostapd_prepare_rates(iface, iface->current_mode)) {
 			wpa_printf(MSG_ERROR, "Failed to prepare rates "
 				   "table.");
 			hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 3764be4..c6f6205 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -31,7 +31,8 @@
 union wps_event_data;
 
 struct hostapd_probereq_cb {
-	int (*cb)(void *ctx, const u8 *sa, const u8 *ie, size_t ie_len);
+	int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
+		  const u8 *ie, size_t ie_len);
 	void *ctx;
 };
 
@@ -81,10 +82,7 @@
 				 struct sta_info *sta, int reassoc);
 
 	void *msg_ctx; /* ctx for wpa_msg() calls */
-#ifdef ANDROID_BRCM_P2P_PATCH
-	/* Sending the event to parent is required as SSL listens on parent ctrl iface */
-	void *msg_ctx_parent; /* ctx for wpa_msg() calls */
-#endif /*ANDROID_BRCM_P2P_PATCH*/
+	void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */
 
 	struct radius_client_data *radius;
 	u32 acct_session_id_hi, acct_session_id_lo;
@@ -111,6 +109,10 @@
 
 	int parameter_set_count;
 
+	/* Time Advertisement */
+	u8 time_update_counter;
+	struct wpabuf *time_adv;
+
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
 	struct full_dynamic_vlan *full_dynamic_vlan;
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
@@ -118,6 +120,7 @@
 	struct l2_packet_data *l2;
 	struct wps_context *wps;
 
+	int beacon_set_done;
 	struct wpabuf *wps_beacon_ie;
 	struct wpabuf *wps_probe_resp_ie;
 #ifdef CONFIG_WPS
@@ -146,7 +149,7 @@
 	void *wps_event_cb_ctx;
 
 	void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
-				  int authorized);
+				  int authorized, const u8 *p2p_dev_addr);
 	void *sta_authorized_cb_ctx;
 
 	void (*setup_complete_cb)(void *ctx);
@@ -189,6 +192,13 @@
 	struct ap_info *ap_iter_list;
 
 	unsigned int drv_flags;
+
+	/*
+	 * A bitmap of supported protocols for probe response offload. See
+	 * struct wpa_driver_capa in driver.h
+	 */
+	unsigned int probe_resp_offloads;
+
 	struct hostapd_hw_modes *hw_features;
 	int num_hw_features;
 	struct hostapd_hw_modes *current_mode;
@@ -196,6 +206,7 @@
 	 * current_mode->channels */
 	int num_rates;
 	struct hostapd_rate_data *current_rates;
+	int *basic_rates;
 	int freq;
 
 	u16 hw_flags;
@@ -251,6 +262,7 @@
 /* utils.c */
 int hostapd_register_probereq_cb(struct hostapd_data *hapd,
 				 int (*cb)(void *ctx, const u8 *sa,
+					   const u8 *da, const u8 *bssid,
 					   const u8 *ie, size_t ie_len),
 				 void *ctx);
 void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
@@ -260,7 +272,7 @@
 			const u8 *ie, size_t ielen, int reassoc);
 void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
 void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
-int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
-			 const u8 *ie, size_t ie_len);
+int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
+			 const u8 *bssid, const u8 *ie, size_t ie_len);
 
 #endif /* HOSTAPD_H */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 86f6811..8c6fef2 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -2,7 +2,7 @@
  * hostapd / Hardware feature query and different modes
  * Copyright 2002-2003, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -101,7 +101,7 @@
 }
 
 
-int hostapd_prepare_rates(struct hostapd_data *hapd,
+int hostapd_prepare_rates(struct hostapd_iface *iface,
 			  struct hostapd_hw_modes *mode)
 {
 	int i, num_basic_rates = 0;
@@ -110,8 +110,8 @@
 	int basic_rates_g[] = { 10, 20, 55, 110, -1 };
 	int *basic_rates;
 
-	if (hapd->iconf->basic_rates)
-		basic_rates = hapd->iconf->basic_rates;
+	if (iface->conf->basic_rates)
+		basic_rates = iface->conf->basic_rates;
 	else switch (mode->mode) {
 	case HOSTAPD_MODE_IEEE80211A:
 		basic_rates = basic_rates_a;
@@ -126,18 +126,20 @@
 		return -1;
 	}
 
-	if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates,
-				  basic_rates, mode->mode)) {
-		wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel "
-			   "module");
-	}
+	i = 0;
+	while (basic_rates[i] >= 0)
+		i++;
+	os_free(iface->basic_rates);
+	iface->basic_rates = os_malloc(i * sizeof(int));
+	if (iface->basic_rates)
+		os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int));
 
-	os_free(hapd->iface->current_rates);
-	hapd->iface->num_rates = 0;
+	os_free(iface->current_rates);
+	iface->num_rates = 0;
 
-	hapd->iface->current_rates =
+	iface->current_rates =
 		os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data));
-	if (!hapd->iface->current_rates) {
+	if (!iface->current_rates) {
 		wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
 			   "table.");
 		return -1;
@@ -146,27 +148,27 @@
 	for (i = 0; i < mode->num_rates; i++) {
 		struct hostapd_rate_data *rate;
 
-		if (hapd->iconf->supported_rates &&
-		    !hostapd_rate_found(hapd->iconf->supported_rates,
+		if (iface->conf->supported_rates &&
+		    !hostapd_rate_found(iface->conf->supported_rates,
 					mode->rates[i]))
 			continue;
 
-		rate = &hapd->iface->current_rates[hapd->iface->num_rates];
+		rate = &iface->current_rates[iface->num_rates];
 		rate->rate = mode->rates[i];
 		if (hostapd_rate_found(basic_rates, rate->rate)) {
 			rate->flags |= HOSTAPD_RATE_BASIC;
 			num_basic_rates++;
 		}
 		wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
-			   hapd->iface->num_rates, rate->rate, rate->flags);
-		hapd->iface->num_rates++;
+			   iface->num_rates, rate->rate, rate->flags);
+		iface->num_rates++;
 	}
 
-	if ((hapd->iface->num_rates == 0 || num_basic_rates == 0) &&
-	    (!hapd->iconf->ieee80211n || !hapd->iconf->require_ht)) {
+	if ((iface->num_rates == 0 || num_basic_rates == 0) &&
+	    (!iface->conf->ieee80211n || !iface->conf->require_ht)) {
 		wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
 			   "rate sets (%d,%d).",
-			   hapd->iface->num_rates, num_basic_rates);
+			   iface->num_rates, num_basic_rates);
 		return -1;
 	}
 
@@ -407,20 +409,6 @@
 }
 
 
-static void wpa_scan_results_free(struct wpa_scan_results *res)
-{
-	size_t i;
-
-	if (res == NULL)
-		return;
-
-	for (i = 0; i < res->num; i++)
-		os_free(res->res[i]);
-	os_free(res->res);
-	os_free(res);
-}
-
-
 static void ieee80211n_check_scan(struct hostapd_iface *iface)
 {
 	struct wpa_scan_results *scan_res;
@@ -630,7 +618,8 @@
 		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_WARNING,
 			       "Hardware does not support configured mode "
-			       "(%d)", (int) iface->conf->hw_mode);
+			       "(%d) (hw_mode in hostapd.conf)",
+			       (int) iface->conf->hw_mode);
 		return -2;
 	}
 
@@ -642,8 +631,15 @@
 			if (chan->flag & HOSTAPD_CHAN_DISABLED) {
 				wpa_printf(MSG_ERROR,
 					   "channel [%i] (%i) is disabled for "
-					   "use in AP mode, flags: 0x%x",
-					   j, chan->chan, chan->flag);
+					   "use in AP mode, flags: 0x%x%s%s%s",
+					   j, chan->chan, chan->flag,
+					   chan->flag & HOSTAPD_CHAN_NO_IBSS ?
+					   " NO-IBSS" : "",
+					   chan->flag &
+					   HOSTAPD_CHAN_PASSIVE_SCAN ?
+					   " PASSIVE-SCAN" : "",
+					   chan->flag & HOSTAPD_CHAN_RADAR ?
+					   " RADAR" : "");
 			} else {
 				ok = 1;
 				break;
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index b84bca6..abadcd1 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -2,6 +2,7 @@
  * hostapd / Hardware feature query and different modes
  * Copyright 2002-2003, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -25,7 +26,7 @@
 int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
 int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
 int hostapd_check_ht_capab(struct hostapd_iface *iface);
-int hostapd_prepare_rates(struct hostapd_data *hapd,
+int hostapd_prepare_rates(struct hostapd_iface *iface,
 			  struct hostapd_hw_modes *mode);
 #else /* NEED_AP_MLME */
 static inline void
@@ -59,7 +60,7 @@
 	return 0;
 }
 
-static inline int hostapd_prepare_rates(struct hostapd_data *hapd,
+static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
 					struct hostapd_hw_modes *mode)
 {
 	return 0;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index e0a3a36..a1a7270 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -163,59 +163,6 @@
 }
 
 
-u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
-{
-	u8 *pos = eid;
-
-	if ((hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)) ==
-	    0)
-		return eid;
-
-	*pos++ = WLAN_EID_EXT_CAPAB;
-	*pos++ = 5;
-	*pos++ = 0x00;
-	*pos++ = 0x00;
-	*pos++ = 0x00;
-	*pos++ = 0x00;
-	*pos = 0x00;
-	if (hapd->conf->tdls & TDLS_PROHIBIT)
-		*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
-	if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
-		*pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
-	pos++;
-
-	return pos;
-}
-
-
-#ifdef CONFIG_IEEE80211W
-static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
-					    struct sta_info *sta, u8 *eid)
-{
-	u8 *pos = eid;
-	u32 timeout, tu;
-	struct os_time now, passed;
-
-	*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
-	*pos++ = 5;
-	*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
-	os_get_time(&now);
-	os_time_sub(&now, &sta->sa_query_start, &passed);
-	tu = (passed.sec * 1000000 + passed.usec) / 1024;
-	if (hapd->conf->assoc_sa_query_max_timeout > tu)
-		timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
-	else
-		timeout = 0;
-	if (timeout < hapd->conf->assoc_sa_query_max_timeout)
-		timeout++; /* add some extra time for local timers */
-	WPA_PUT_LE32(pos, timeout);
-	pos += 4;
-
-	return pos;
-}
-#endif /* CONFIG_IEEE80211W */
-
-
 void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len)
 {
 	int i;
@@ -322,7 +269,7 @@
 		   " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
 		   MAC2STR(dst), auth_alg, auth_transaction,
 		   resp, (unsigned long) ies_len);
-	if (hostapd_drv_send_mlme(hapd, reply, rlen) < 0)
+	if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
 		perror("send_auth_reply: send");
 
 	os_free(buf);
@@ -366,6 +313,8 @@
 	const u8 *challenge = NULL;
 	u32 session_timeout, acct_interim_interval;
 	int vlan_id = 0;
+	u8 psk[PMK_LEN];
+	int has_psk = 0;
 	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
 	size_t resp_ies_len = 0;
 
@@ -400,9 +349,7 @@
 	if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
 	       auth_alg == WLAN_AUTH_OPEN) ||
 #ifdef CONFIG_IEEE80211R
-	      (hapd->conf->wpa &&
-	       (hapd->conf->wpa_key_mgmt &
-		(WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) &&
+	      (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
 	       auth_alg == WLAN_AUTH_FT) ||
 #endif /* CONFIG_IEEE80211R */
 	      ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
@@ -430,7 +377,9 @@
 
 	res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
 				      &session_timeout,
-				      &acct_interim_interval, &vlan_id);
+				      &acct_interim_interval, &vlan_id,
+				      psk, &has_psk);
+
 	if (res == HOSTAPD_ACL_REJECT) {
 		printf("Station " MACSTR " not allowed to authenticate.\n",
 		       MAC2STR(mgmt->sa));
@@ -468,6 +417,16 @@
 			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
 	}
 
+	if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+		os_free(sta->psk);
+		sta->psk = os_malloc(PMK_LEN);
+		if (sta->psk)
+			os_memcpy(sta->psk, psk, PMK_LEN);
+	} else {
+		os_free(sta->psk);
+		sta->psk = NULL;
+	}
+
 	sta->flags &= ~WLAN_STA_PREAUTH;
 	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
 
@@ -592,15 +551,22 @@
 		     const u8 *wmm_ie, size_t wmm_ie_len)
 {
 	sta->flags &= ~WLAN_STA_WMM;
+	sta->qosinfo = 0;
 	if (wmm_ie && hapd->conf->wmm_enabled) {
-		if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len))
+		struct wmm_information_element *wmm;
+
+		if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_WPA,
 				       HOSTAPD_LEVEL_DEBUG,
 				       "invalid WMM element in association "
 				       "request");
-		else
-			sta->flags |= WLAN_STA_WMM;
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		}
+
+		sta->flags |= WLAN_STA_WMM;
+		wmm = (struct wmm_information_element *) wmm_ie;
+		sta->qosinfo = wmm->qos_info;
 	}
 	return WLAN_STATUS_SUCCESS;
 }
@@ -701,7 +667,7 @@
 	}
 
 #ifdef CONFIG_WPS
-	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
 	if (hapd->conf->wps_state && elems.wps_ie) {
 		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
 			   "Request - assume WPS is used");
@@ -709,6 +675,10 @@
 		wpabuf_free(sta->wps_ie);
 		sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
 							  WPS_IE_VENDOR_TYPE);
+		if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
+			wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
+			sta->flags |= WLAN_STA_WPS2;
+		}
 		wpa_ie = NULL;
 		wpa_ie_len = 0;
 		if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
@@ -854,7 +824,7 @@
 	send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
 	reply.u.deauth.reason_code = host_to_le16(reason_code);
 
-	if (hostapd_drv_send_mlme(hapd, &reply, send_len) < 0)
+	if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0)
 		wpa_printf(MSG_INFO, "Failed to send deauth: %s",
 			   strerror(errno));
 }
@@ -917,7 +887,8 @@
 		p = hostapd_eid_wmm(hapd, p);
 
 #ifdef CONFIG_WPS
-	if (sta->flags & WLAN_STA_WPS) {
+	if ((sta->flags & WLAN_STA_WPS) ||
+	    ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa)) {
 		struct wpabuf *wps = wps_build_assoc_resp_ie();
 		if (wps) {
 			os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
@@ -959,7 +930,7 @@
 
 	send_len += p - reply->u.assoc_resp.variable;
 
-	if (hostapd_drv_send_mlme(hapd, reply, send_len) < 0)
+	if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0)
 		wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
 			   strerror(errno));
 }
@@ -1160,15 +1131,8 @@
 		return;
 	}
 
+	ap_sta_set_authorized(hapd, sta, 0);
 	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
-	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-		MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if(hapd->msg_ctx_parent)
-		wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-			MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
-
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO, "disassociated");
@@ -1199,32 +1163,26 @@
 	struct sta_info *sta;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
-		wpa_msg(hapd, MSG_DEBUG, "handle_deauth - too short payload "
-			"(len=%lu)", (unsigned long) len);
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short "
+			"payload (len=%lu)", (unsigned long) len);
 		return;
 	}
 
-	wpa_msg(hapd, MSG_DEBUG, "deauthentication: STA=" MACSTR
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR
 		" reason_code=%d",
 		MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
 
 	sta = ap_get_sta(hapd, mgmt->sa);
 	if (sta == NULL) {
-		wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " trying to "
-			"deauthenticate, but it is not authenticated",
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
+			"to deauthenticate, but it is not authenticated",
 			MAC2STR(mgmt->sa));
 		return;
 	}
 
+	ap_sta_set_authorized(hapd, sta, 0);
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
 			WLAN_STA_ASSOC_REQ_OK);
-	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-		MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if(hapd->msg_ctx_parent)
-		wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-			MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_DEBUG, "deauthenticated");
@@ -1259,81 +1217,11 @@
 
 #ifdef CONFIG_IEEE80211W
 
-/* MLME-SAQuery.request */
-void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
-				  const u8 *addr, const u8 *trans_id)
-{
-	struct ieee80211_mgmt mgmt;
-	u8 *end;
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
-		   MACSTR, MAC2STR(addr));
-	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
-
-	os_memset(&mgmt, 0, sizeof(mgmt));
-	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					  WLAN_FC_STYPE_ACTION);
-	os_memcpy(mgmt.da, addr, ETH_ALEN);
-	os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-	mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
-	mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
-	os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
-		  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)
-		perror("ieee802_11_send_sa_query_req: send");
-}
-
-
-static void hostapd_sa_query_request(struct hostapd_data *hapd,
-				     const struct ieee80211_mgmt *mgmt)
-{
-	struct sta_info *sta;
-	struct ieee80211_mgmt resp;
-	u8 *end;
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
-		   MACSTR, MAC2STR(mgmt->sa));
-	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-		    mgmt->u.action.u.sa_query_resp.trans_id,
-		    WLAN_SA_QUERY_TR_ID_LEN);
-
-	sta = ap_get_sta(hapd, mgmt->sa);
-	if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
-			   "from unassociated STA " MACSTR, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
-		   MACSTR, MAC2STR(mgmt->sa));
-
-	os_memset(&resp, 0, sizeof(resp));
-	resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					  WLAN_FC_STYPE_ACTION);
-	os_memcpy(resp.da, mgmt->sa, ETH_ALEN);
-	os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
-	resp.u.action.category = WLAN_ACTION_SA_QUERY;
-	resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
-	os_memcpy(resp.u.action.u.sa_query_req.trans_id,
-		  mgmt->u.action.u.sa_query_req.trans_id,
-		  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)
-		perror("hostapd_sa_query_request: send");
-}
-
-
 static void hostapd_sa_query_action(struct hostapd_data *hapd,
 				    const struct ieee80211_mgmt *mgmt,
 				    size_t len)
 {
-	struct sta_info *sta;
 	const u8 *end;
-	int i;
 
 	end = mgmt->u.action.u.sa_query_resp.trans_id +
 		WLAN_SA_QUERY_TR_ID_LEN;
@@ -1343,50 +1231,9 @@
 		return;
 	}
 
-	if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) {
-		hostapd_sa_query_request(hapd, mgmt);
-		return;
-	}
-
-	if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
-			   "Action %d", mgmt->u.action.u.sa_query_resp.action);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
-		   MACSTR, MAC2STR(mgmt->sa));
-	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-		    mgmt->u.action.u.sa_query_resp.trans_id,
-		    WLAN_SA_QUERY_TR_ID_LEN);
-
-	/* MLME-SAQuery.confirm */
-
-	sta = ap_get_sta(hapd, mgmt->sa);
-	if (sta == NULL || sta->sa_query_trans_id == NULL) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
-			   "pending SA Query request found");
-		return;
-	}
-
-	for (i = 0; i < sta->sa_query_count; i++) {
-		if (os_memcmp(sta->sa_query_trans_id +
-			      i * WLAN_SA_QUERY_TR_ID_LEN,
-			      mgmt->u.action.u.sa_query_resp.trans_id,
-			      WLAN_SA_QUERY_TR_ID_LEN) == 0)
-			break;
-	}
-
-	if (i >= sta->sa_query_count) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
-			   "transaction identifier found");
-		return;
-	}
-
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "Reply to pending SA Query received");
-	ap_sta_stop_sa_query(hapd, sta);
+	ieee802_11_sa_query_action(hapd, mgmt->sa,
+				   mgmt->u.action.u.sa_query_resp.action,
+				   mgmt->u.action.u.sa_query_resp.trans_id);
 }
 
 
@@ -1401,7 +1248,10 @@
 static void handle_action(struct hostapd_data *hapd,
 			  const struct ieee80211_mgmt *mgmt, size_t len)
 {
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R)
 	struct sta_info *sta;
+	sta = ap_get_sta(hapd, mgmt->sa);
+#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */
 
 	if (len < IEEE80211_HDRLEN + 1) {
 		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -1411,7 +1261,6 @@
 		return;
 	}
 
-	sta = ap_get_sta(hapd, mgmt->sa);
 #ifdef CONFIG_IEEE80211W
 	if (sta && (sta->flags & WLAN_STA_MFP) &&
 	    !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
@@ -1493,7 +1342,7 @@
 		os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
 		resp->u.action.category |= 0x80;
 
-		hostapd_drv_send_mlme(hapd, resp, len);
+		hostapd_drv_send_mlme(hapd, resp, len, 0);
 		os_free(resp);
 	}
 }
@@ -1536,6 +1385,11 @@
 		mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
 
 	if (!broadcast &&
+#ifdef CONFIG_P2P
+	    /* Invitation responses can be sent with the peer MAC as BSSID */
+	    !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+	      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));
@@ -1574,7 +1428,7 @@
 		handle_disassoc(hapd, mgmt, len);
 		break;
 	case WLAN_FC_STYPE_DEAUTH:
-		wpa_msg(hapd, MSG_DEBUG, "mgmt::deauth");
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
 		handle_deauth(hapd, mgmt, len);
 		break;
 	case WLAN_FC_STYPE_ACTION:
@@ -1688,14 +1542,6 @@
 		 * step.
 		 */
 		ap_sta_set_authorized(hapd, sta, 1);
-		wpa_msg(hapd->msg_ctx, MSG_INFO,
-			AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
-		/* Sending the event to parent is required as SSL listens on parent ctrl iface */
-		if(hapd->msg_ctx_parent)
-			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
-				AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
 	}
 
 	if (reassoc)
@@ -1722,10 +1568,16 @@
 	if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
 			    sta->supported_rates, sta->supported_rates_len,
 			    sta->listen_interval,
-			    sta->flags & WLAN_STA_HT ? &ht_cap : NULL)) {
+			    sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
+			    sta->flags, sta->qosinfo)) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_NOTICE,
 			       "Could not add STA to kernel driver");
+
+		ap_sta_disconnect(hapd, sta, sta->addr,
+				  WLAN_REASON_DISASSOC_AP_BUSY);
+
+		goto fail;
 	}
 
 	if (sta->flags & WLAN_STA_WDS)
@@ -1764,6 +1616,54 @@
 }
 
 
+static void handle_deauth_cb(struct hostapd_data *hapd,
+			     const struct ieee80211_mgmt *mgmt,
+			     size_t len, int ok)
+{
+	struct sta_info *sta;
+	if (mgmt->da[0] & 0x01)
+		return;
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
+			   " not found", MAC2STR(mgmt->da));
+		return;
+	}
+	if (ok)
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
+			   MAC2STR(sta->addr));
+	else
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+			   "deauth", MAC2STR(sta->addr));
+
+	ap_sta_deauth_cb(hapd, sta);
+}
+
+
+static void handle_disassoc_cb(struct hostapd_data *hapd,
+			       const struct ieee80211_mgmt *mgmt,
+			       size_t len, int ok)
+{
+	struct sta_info *sta;
+	if (mgmt->da[0] & 0x01)
+		return;
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
+			   " not found", MAC2STR(mgmt->da));
+		return;
+	}
+	if (ok)
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
+			   MAC2STR(sta->addr));
+	else
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+			   "disassoc", MAC2STR(sta->addr));
+
+	ap_sta_disassoc_cb(hapd, sta);
+}
+
+
 /**
  * ieee802_11_mgmt_cb - Process management frame TX status callback
  * @hapd: hostapd BSS data structure (the BSS from which the management frame
@@ -1796,7 +1696,12 @@
 		wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb");
 		break;
 	case WLAN_FC_STYPE_DEAUTH:
-		/* ignore */
+		wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
+		handle_deauth_cb(hapd, mgmt, len, ok);
+		break;
+	case WLAN_FC_STYPE_DISASSOC:
+		wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
+		handle_disassoc_cb(hapd, mgmt, len, ok);
 		break;
 	case WLAN_FC_STYPE_ACTION:
 		wpa_printf(MSG_DEBUG, "mgmt::action cb");
@@ -1853,6 +1758,55 @@
 }
 
 
+void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+			     const u8 *data, size_t len, int ack)
+{
+	struct sta_info *sta;
+	struct hostapd_iface *iface = hapd->iface;
+
+	sta = ap_get_sta(hapd, dst);
+	if (sta == NULL && iface->num_bss > 1) {
+		size_t j;
+		for (j = 0; j < iface->num_bss; j++) {
+			hapd = iface->bss[j];
+			sta = ap_get_sta(hapd, dst);
+			if (sta)
+				break;
+		}
+	}
+	if (sta == NULL)
+		return;
+
+	ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
+}
+
+
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta;
+	struct hostapd_iface *iface = hapd->iface;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL && iface->num_bss > 1) {
+		size_t j;
+		for (j = 0; j < iface->num_bss; j++) {
+			hapd = iface->bss[j];
+			sta = ap_get_sta(hapd, addr);
+			if (sta)
+				break;
+		}
+	}
+	if (sta == NULL)
+		return;
+	if (!(sta->flags & WLAN_STA_PENDING_POLL))
+		return;
+
+	wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
+		   "activity poll", MAC2STR(sta->addr));
+	sta->flags &= ~WLAN_STA_PENDING_POLL;
+}
+
+
 void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
 				int wds)
 {
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 157198c..43042a5 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -62,7 +62,21 @@
 void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
 void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
 		       const u8 *buf, size_t len, int ack);
+void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+			     const u8 *data, size_t len, int ack);
 void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
 				int wds);
+u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
+				     struct sta_info *sta, u8 *eid);
+void ieee802_11_sa_query_action(struct hostapd_data *hapd,
+				const u8 *sa, const u8 action_type,
+				const u8 *trans_id);
+u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
+int hostapd_update_time_adv(struct hostapd_data *hapd);
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
 
 #endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index b933263..f3f313d 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -21,6 +21,7 @@
 
 #include "utils/common.h"
 #include "utils/eloop.h"
+#include "crypto/sha1.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "hostapd.h"
@@ -40,6 +41,8 @@
 	u32 session_timeout;
 	u32 acct_interim_interval;
 	int vlan_id;
+	int has_psk;
+	u8 psk[PMK_LEN];
 };
 
 
@@ -68,7 +71,8 @@
 
 static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
 				 u32 *session_timeout,
-				 u32 *acct_interim_interval, int *vlan_id)
+				 u32 *acct_interim_interval, int *vlan_id,
+				 u8 *psk, int *has_psk)
 {
 	struct hostapd_cached_radius_acl *entry;
 	struct os_time now;
@@ -89,6 +93,10 @@
 					entry->acct_interim_interval;
 			if (vlan_id)
 				*vlan_id = entry->vlan_id;
+			if (psk)
+				os_memcpy(psk, entry->psk, PMK_LEN);
+			if (has_psk)
+				*has_psk = entry->has_psk;
 			return entry->accepted;
 		}
 
@@ -210,11 +218,14 @@
  * @session_timeout: Buffer for returning session timeout (from RADIUS)
  * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
  * @vlan_id: Buffer for returning VLAN ID
+ * @psk: Buffer for returning WPA PSK
+ * @has_psk: Buffer for indicating whether psk was filled
  * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
  */
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 			    const u8 *msg, size_t len, u32 *session_timeout,
-			    u32 *acct_interim_interval, int *vlan_id)
+			    u32 *acct_interim_interval, int *vlan_id,
+			    u8 *psk, int *has_psk)
 {
 	if (session_timeout)
 		*session_timeout = 0;
@@ -222,6 +233,10 @@
 		*acct_interim_interval = 0;
 	if (vlan_id)
 		*vlan_id = 0;
+	if (has_psk)
+		*has_psk = 0;
+	if (psk)
+		os_memset(psk, 0, PMK_LEN);
 
 	if (hostapd_maclist_found(hapd->conf->accept_mac,
 				  hapd->conf->num_accept_mac, addr, vlan_id))
@@ -241,11 +256,12 @@
 		return HOSTAPD_ACL_REJECT;
 #else /* CONFIG_NO_RADIUS */
 		struct hostapd_acl_query_data *query;
+		struct os_time t;
 
 		/* Check whether ACL cache has an entry for this station */
 		int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
 						acct_interim_interval,
-						vlan_id);
+						vlan_id, psk, has_psk);
 		if (res == HOSTAPD_ACL_ACCEPT ||
 		    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
 			return res;
@@ -271,7 +287,8 @@
 			wpa_printf(MSG_ERROR, "malloc for query data failed");
 			return HOSTAPD_ACL_REJECT;
 		}
-		time(&query->timestamp);
+		os_get_time(&t);
+		query->timestamp = t.sec;
 		os_memcpy(query->addr, addr, ETH_ALEN);
 		if (hostapd_radius_acl_query(hapd, addr, query)) {
 			wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
@@ -397,6 +414,7 @@
 	struct hostapd_acl_query_data *query, *prev;
 	struct hostapd_cached_radius_acl *cache;
 	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+	struct os_time t;
 
 	query = hapd->acl_queries;
 	prev = NULL;
@@ -431,9 +449,13 @@
 		wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
 		goto done;
 	}
-	time(&cache->timestamp);
+	os_get_time(&t);
+	cache->timestamp = t.sec;
 	os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
 	if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
+		int passphraselen;
+		char *passphrase;
+
 		if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
 					      &cache->session_timeout) == 0)
 			cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
@@ -452,6 +474,32 @@
 		}
 
 		cache->vlan_id = radius_msg_get_vlanid(msg);
+
+		passphrase = radius_msg_get_tunnel_password(
+			msg, &passphraselen,
+			hapd->conf->radius->auth_server->shared_secret,
+			hapd->conf->radius->auth_server->shared_secret_len,
+			req);
+		cache->has_psk = passphrase != NULL;
+		if (passphrase != NULL) {
+			/* passphrase does not contain the NULL termination.
+			 * Add it here as pbkdf2_sha1 requires it. */
+			char *strpassphrase = os_zalloc(passphraselen + 1);
+			if (strpassphrase) {
+				os_memcpy(strpassphrase, passphrase,
+					  passphraselen);
+				pbkdf2_sha1(strpassphrase,
+					    hapd->conf->ssid.ssid,
+					    hapd->conf->ssid.ssid_len, 4096,
+					    cache->psk, PMK_LEN);
+				os_free(strpassphrase);
+			}
+			os_free(passphrase);
+		}
+
+		if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
+		    cache->psk == NULL)
+			cache->accepted = HOSTAPD_ACL_REJECT;
 	} else
 		cache->accepted = HOSTAPD_ACL_REJECT;
 	cache->next = hapd->acl_cache;
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index b2971e5..a90571f 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -24,7 +24,8 @@
 
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 			    const u8 *msg, size_t len, u32 *session_timeout,
-			    u32 *acct_interim_interval, int *vlan_id);
+			    u32 *acct_interim_interval, int *vlan_id,
+			    u8 *psk, int *has_psk);
 int hostapd_acl_init(struct hostapd_data *hapd);
 void hostapd_acl_deinit(struct hostapd_data *hapd);
 
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
new file mode 100644
index 0000000..8503fce
--- /dev/null
+++ b/src/ap/ieee802_11_shared.c
@@ -0,0 +1,405 @@
+/*
+ * hostapd / IEEE 802.11 Management
+ * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "ieee802_11.h"
+
+
+#ifdef CONFIG_IEEE80211W
+
+u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
+				     struct sta_info *sta, u8 *eid)
+{
+	u8 *pos = eid;
+	u32 timeout, tu;
+	struct os_time now, passed;
+
+	*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+	*pos++ = 5;
+	*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
+	os_get_time(&now);
+	os_time_sub(&now, &sta->sa_query_start, &passed);
+	tu = (passed.sec * 1000000 + passed.usec) / 1024;
+	if (hapd->conf->assoc_sa_query_max_timeout > tu)
+		timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
+	else
+		timeout = 0;
+	if (timeout < hapd->conf->assoc_sa_query_max_timeout)
+		timeout++; /* add some extra time for local timers */
+	WPA_PUT_LE32(pos, timeout);
+	pos += 4;
+
+	return pos;
+}
+
+
+/* MLME-SAQuery.request */
+void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
+				  const u8 *addr, const u8 *trans_id)
+{
+	struct ieee80211_mgmt mgmt;
+	u8 *end;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
+		   MACSTR, MAC2STR(addr));
+	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	os_memset(&mgmt, 0, sizeof(mgmt));
+	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_ACTION);
+	os_memcpy(mgmt.da, addr, ETH_ALEN);
+	os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+	mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
+	mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
+	os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
+		  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");
+}
+
+
+static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
+					  const u8 *sa, const u8 *trans_id)
+{
+	struct sta_info *sta;
+	struct ieee80211_mgmt resp;
+	u8 *end;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
+		   MACSTR, MAC2STR(sa));
+	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	sta = ap_get_sta(hapd, sa);
+	if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
+			   "from unassociated STA " MACSTR, MAC2STR(sa));
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
+		   MACSTR, MAC2STR(sa));
+
+	os_memset(&resp, 0, sizeof(resp));
+	resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_ACTION);
+	os_memcpy(resp.da, sa, ETH_ALEN);
+	os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
+	resp.u.action.category = WLAN_ACTION_SA_QUERY;
+	resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
+	os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id,
+		  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");
+}
+
+
+void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
+				const u8 action_type, const u8 *trans_id)
+{
+	struct sta_info *sta;
+	int i;
+
+	if (action_type == WLAN_SA_QUERY_REQUEST) {
+		ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
+		return;
+	}
+
+	if (action_type != WLAN_SA_QUERY_RESPONSE) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
+			   "Action %d", action_type);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
+		   MACSTR, MAC2STR(sa));
+	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	/* MLME-SAQuery.confirm */
+
+	sta = ap_get_sta(hapd, sa);
+	if (sta == NULL || sta->sa_query_trans_id == NULL) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
+			   "pending SA Query request found");
+		return;
+	}
+
+	for (i = 0; i < sta->sa_query_count; i++) {
+		if (os_memcmp(sta->sa_query_trans_id +
+			      i * WLAN_SA_QUERY_TR_ID_LEN,
+			      trans_id, WLAN_SA_QUERY_TR_ID_LEN) == 0)
+			break;
+	}
+
+	if (i >= sta->sa_query_count) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
+			   "transaction identifier found");
+		return;
+	}
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "Reply to pending SA Query received");
+	ap_sta_stop_sa_query(hapd, sta);
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+
+u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	u8 len = 0;
+
+	if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
+		len = 5;
+	if (len < 4 && hapd->conf->interworking)
+		len = 4;
+	if (len == 0)
+		return eid;
+
+	*pos++ = WLAN_EID_EXT_CAPAB;
+	*pos++ = len;
+	*pos++ = 0x00;
+	*pos++ = 0x00;
+	*pos++ = 0x00;
+
+	*pos = 0x00;
+	if (hapd->conf->time_advertisement == 2)
+		*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
+	if (hapd->conf->interworking)
+		*pos |= 0x80; /* Bit 31 - Interworking */
+	pos++;
+
+	if (len < 5)
+		return pos;
+	*pos = 0x00;
+	if (hapd->conf->tdls & TDLS_PROHIBIT)
+		*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
+	if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
+		*pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
+	pos++;
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+	u8 *len;
+
+	if (!hapd->conf->interworking)
+		return eid;
+
+	*pos++ = WLAN_EID_INTERWORKING;
+	len = pos++;
+
+	*pos = hapd->conf->access_network_type;
+	if (hapd->conf->internet)
+		*pos |= INTERWORKING_ANO_INTERNET;
+	if (hapd->conf->asra)
+		*pos |= INTERWORKING_ANO_ASRA;
+	if (hapd->conf->esr)
+		*pos |= INTERWORKING_ANO_ESR;
+	if (hapd->conf->uesa)
+		*pos |= INTERWORKING_ANO_UESA;
+	pos++;
+
+	if (hapd->conf->venue_info_set) {
+		*pos++ = hapd->conf->venue_group;
+		*pos++ = hapd->conf->venue_type;
+	}
+
+	if (!is_zero_ether_addr(hapd->conf->hessid)) {
+		os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
+		pos += ETH_ALEN;
+	}
+
+	*len = pos - len - 1;
+#endif /* CONFIG_INTERWORKING */
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+
+	/* TODO: Separate configuration for ANQP? */
+	if (!hapd->conf->interworking)
+		return eid;
+
+	*pos++ = WLAN_EID_ADV_PROTO;
+	*pos++ = 2;
+	*pos++ = 0x7F; /* Query Response Length Limit | PAME-BI */
+	*pos++ = ACCESS_NETWORK_QUERY_PROTOCOL;
+#endif /* CONFIG_INTERWORKING */
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+	u8 *len;
+	unsigned int i, count;
+
+	if (!hapd->conf->interworking ||
+	    hapd->conf->roaming_consortium == NULL ||
+	    hapd->conf->roaming_consortium_count == 0)
+		return eid;
+
+	*pos++ = WLAN_EID_ROAMING_CONSORTIUM;
+	len = pos++;
+
+	/* Number of ANQP OIs (in addition to the max 3 listed here) */
+	if (hapd->conf->roaming_consortium_count > 3 + 255)
+		*pos++ = 255;
+	else if (hapd->conf->roaming_consortium_count > 3)
+		*pos++ = hapd->conf->roaming_consortium_count - 3;
+	else
+		*pos++ = 0;
+
+	/* OU #1 and #2 Lengths */
+	*pos = hapd->conf->roaming_consortium[0].len;
+	if (hapd->conf->roaming_consortium_count > 1)
+		*pos |= hapd->conf->roaming_consortium[1].len << 4;
+	pos++;
+
+	if (hapd->conf->roaming_consortium_count > 3)
+		count = 3;
+	else
+		count = hapd->conf->roaming_consortium_count;
+
+	for (i = 0; i < count; i++) {
+		os_memcpy(pos, hapd->conf->roaming_consortium[i].oi,
+			  hapd->conf->roaming_consortium[i].len);
+		pos += hapd->conf->roaming_consortium[i].len;
+	}
+
+	*len = pos - len - 1;
+#endif /* CONFIG_INTERWORKING */
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid)
+{
+	if (hapd->conf->time_advertisement != 2)
+		return eid;
+
+	if (hapd->time_adv == NULL &&
+	    hostapd_update_time_adv(hapd) < 0)
+		return eid;
+
+	if (hapd->time_adv == NULL)
+		return eid;
+
+	os_memcpy(eid, wpabuf_head(hapd->time_adv),
+		  wpabuf_len(hapd->time_adv));
+	eid += wpabuf_len(hapd->time_adv);
+
+	return eid;
+}
+
+
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid)
+{
+	size_t len;
+
+	if (hapd->conf->time_advertisement != 2)
+		return eid;
+
+	len = os_strlen(hapd->conf->time_zone);
+
+	*eid++ = WLAN_EID_TIME_ZONE;
+	*eid++ = len;
+	os_memcpy(eid, hapd->conf->time_zone, len);
+	eid += len;
+
+	return eid;
+}
+
+
+int hostapd_update_time_adv(struct hostapd_data *hapd)
+{
+	const int elen = 2 + 1 + 10 + 5 + 1;
+	struct os_time t;
+	struct os_tm tm;
+	u8 *pos;
+
+	if (hapd->conf->time_advertisement != 2)
+		return 0;
+
+	if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0)
+		return -1;
+
+	if (!hapd->time_adv) {
+		hapd->time_adv = wpabuf_alloc(elen);
+		if (hapd->time_adv == NULL)
+			return -1;
+		pos = wpabuf_put(hapd->time_adv, elen);
+	} else
+		pos = wpabuf_mhead_u8(hapd->time_adv);
+
+	*pos++ = WLAN_EID_TIME_ADVERTISEMENT;
+	*pos++ = 1 + 10 + 5 + 1;
+
+	*pos++ = 2; /* UTC time at which the TSF timer is 0 */
+
+	/* Time Value at TSF 0 */
+	/* FIX: need to calculate this based on the current TSF value */
+	WPA_PUT_LE16(pos, tm.year); /* Year */
+	pos += 2;
+	*pos++ = tm.month; /* Month */
+	*pos++ = tm.day; /* Day of month */
+	*pos++ = tm.hour; /* Hours */
+	*pos++ = tm.min; /* Minutes */
+	*pos++ = tm.sec; /* Seconds */
+	WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */
+	pos += 2;
+	*pos++ = 0; /* Reserved */
+
+	/* Time Error */
+	/* TODO: fill in an estimate on the error */
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+
+	*pos++ = hapd->time_update_counter++;
+
+	return 0;
+}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 49eba69..153b271 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -20,13 +20,13 @@
 #include "crypto/crypto.h"
 #include "crypto/random.h"
 #include "common/ieee802_11_defs.h"
-#include "common/wpa_ctrl.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "eap_server/eap.h"
 #include "eap_common/eap_wsc_common.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "eapol_auth/eapol_auth_sm_i.h"
+#include "p2p/p2p.h"
 #include "hostapd.h"
 #include "accounting.h"
 #include "sta_info.h"
@@ -36,9 +36,6 @@
 #include "ap_config.h"
 #include "ap_drv_ops.h"
 #include "ieee802_1x.h"
-#ifdef ANDROID_BRCM_P2P_PATCH
-#include "p2p/p2p_i.h"
-#endif
 
 
 static void ieee802_1x_finished(struct hostapd_data *hapd,
@@ -87,53 +84,16 @@
 				   struct sta_info *sta, int authorized)
 {
 	int res;
-#ifdef ANDROID_BRCM_P2P_PATCH
-	u8 *dev_addr = NULL;
-#endif
 
 	if (sta->flags & WLAN_STA_PREAUTH)
 		return;
 
 	if (authorized) {
-		if (!ap_sta_is_authorized(sta)) {
-#if defined(ANDROID_BRCM_P2P_PATCH) && defined(CONFIG_P2P)
-			if((dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr)))
-				wpa_msg(hapd->msg_ctx, MSG_INFO,
-					AP_STA_CONNECTED MACSTR " dev_addr="MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
-			else
-#endif /*ANDROID_BRCM_P2P_PATCH*/
-				wpa_msg(hapd->msg_ctx, MSG_INFO,
-					AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-
-#ifdef ANDROID_BRCM_P2P_PATCH
-			/* Sending the event to parent is required as SSL listens on parent ctrl iface */
-			if(hapd->msg_ctx_parent) {
-				if(dev_addr)
-					wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
-						AP_STA_CONNECTED MACSTR " dev_addr="MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
-				else
-					wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
-						AP_STA_CONNECTED MACSTR , MAC2STR(sta->addr));
-			}
-#endif /* ANDROID_BRCM_P2P_PATCH */
-		}
-
 		ap_sta_set_authorized(hapd, sta, 1);
 		res = hostapd_set_authorized(hapd, sta, 1);
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_DEBUG, "authorizing port");
 	} else {
-		if (ap_sta_is_authorized(sta) && (sta->flags & WLAN_STA_ASSOC)) {
-			wpa_msg(hapd->msg_ctx, MSG_INFO,
-				AP_STA_DISCONNECTED MACSTR,
-				MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
-			if(hapd->msg_ctx_parent)
-				wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
-					AP_STA_DISCONNECTED MACSTR,
-					MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
-		}
 		ap_sta_set_authorized(hapd, sta, 0);
 		res = hostapd_set_authorized(hapd, sta, 0);
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
@@ -722,7 +682,8 @@
 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
 		   (unsigned long) len, MAC2STR(sa));
 	sta = ap_get_sta(hapd, sa);
-	if (!sta || !(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH))) {
+	if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
+		     !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
 		wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
 			   "associated/Pre-authenticating STA");
 		return;
@@ -785,14 +746,24 @@
 			return;
 
 #ifdef CONFIG_WPS
-		if (!hapd->conf->ieee802_1x &&
-		    ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) ==
-		     WLAN_STA_MAYBE_WPS)) {
-			/*
-			 * Delay EAPOL frame transmission until a possible WPS
-			 * STA initiates the handshake with EAPOL-Start.
-			 */
-			sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+		if (!hapd->conf->ieee802_1x) {
+			u32 wflags = sta->flags & (WLAN_STA_WPS |
+						   WLAN_STA_WPS2 |
+						   WLAN_STA_MAYBE_WPS);
+			if (wflags == WLAN_STA_MAYBE_WPS ||
+			    wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) {
+				/*
+				 * Delay EAPOL frame transmission until a
+				 * possible WPS STA initiates the handshake
+				 * with EAPOL-Start. Only allow the wait to be
+				 * skipped if the STA is known to support WPS
+				 * 2.0.
+				 */
+				wpa_printf(MSG_DEBUG, "WPS: Do not start "
+					   "EAPOL until EAPOL-Start is "
+					   "received");
+				sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+			}
 		}
 #endif /* CONFIG_WPS */
 
@@ -921,11 +892,14 @@
 
 #ifdef CONFIG_WPS
 	sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
-	if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) {
+	if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) {
 		/*
-		 * Delay EAPOL frame transmission until a possible WPS
-		 * initiates the handshake with EAPOL-Start.
+		 * Delay EAPOL frame transmission until a possible WPS STA
+		 * initiates the handshake with EAPOL-Start. Only allow the
+		 * wait to be skipped if the STA is known to support WPS 2.0.
 		 */
+		wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until "
+			   "EAPOL-Start is received");
 		sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
 	}
 #endif /* CONFIG_WPS */
@@ -1443,6 +1417,9 @@
 		 * request and we cannot continue EAP processing (EAP-Failure
 		 * could only be sent if the EAP peer actually replied).
 		 */
+		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
+			MAC2STR(sta->addr));
+
 		sm->eap_if->portEnabled = FALSE;
 		ap_sta_disconnect(hapd, sta, sta->addr,
 				  WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -1595,7 +1572,7 @@
 {
 	struct hostapd_data *hapd = ctx;
 	const struct hostapd_eap_user *eap_user;
-	int i, count;
+	int i;
 
 	eap_user = hostapd_get_eap_user(hapd->conf, identity,
 					identity_len, phase2);
@@ -1604,10 +1581,7 @@
 
 	os_memset(user, 0, sizeof(*user));
 	user->phase2 = phase2;
-	count = EAP_USER_MAX_METHODS;
-	if (count > EAP_MAX_METHODS)
-		count = EAP_MAX_METHODS;
-	for (i = 0; i < count; i++) {
+	for (i = 0; i < EAP_MAX_METHODS; i++) {
 		user->methods[i].vendor = eap_user->methods[i].vendor;
 		user->methods[i].method = eap_user->methods[i].method;
 	}
@@ -1619,6 +1593,7 @@
 		os_memcpy(user->password, eap_user->password,
 			  eap_user->password_len);
 		user->password_len = eap_user->password_len;
+		user->password_hash = eap_user->password_hash;
 	}
 	user->force_version = eap_user->force_version;
 	user->ttls_auth = eap_user->ttls_auth;
@@ -1795,15 +1770,13 @@
 			 const u8 *buf, size_t len, int ack)
 {
 	struct ieee80211_hdr *hdr;
-	struct ieee802_1x_hdr *xhdr;
-	struct ieee802_1x_eapol_key *key;
 	u8 *pos;
 	const unsigned char rfc1042_hdr[ETH_ALEN] =
 		{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
 
 	if (sta == NULL)
 		return -1;
-	if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr))
+	if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
 		return 0;
 
 	hdr = (struct ieee80211_hdr *) buf;
@@ -1815,16 +1788,30 @@
 		return 0;
 	pos += 2;
 
-	xhdr = (struct ieee802_1x_hdr *) pos;
-	pos += sizeof(*xhdr);
+	return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos,
+					  ack);
+}
 
+
+int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			       const u8 *buf, int len, int ack)
+{
+	const struct ieee802_1x_hdr *xhdr =
+		(const struct ieee802_1x_hdr *) buf;
+	const u8 *pos = buf + sizeof(*xhdr);
+	struct ieee802_1x_eapol_key *key;
+
+	if (len < (int) sizeof(*xhdr))
+		return 0;
 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
 		   "type=%d length=%d - ack=%d",
 		   MAC2STR(sta->addr), xhdr->version, xhdr->type,
 		   be_to_host16(xhdr->length), ack);
 
-	if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY &&
-	    pos + sizeof(struct wpa_eapol_key) <= buf + len) {
+	if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
+		return 0;
+
+	if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
 		const struct wpa_eapol_key *wpa;
 		wpa = (const struct wpa_eapol_key *) pos;
 		if (wpa->type == EAPOL_KEY_TYPE_RSN ||
@@ -1835,11 +1822,10 @@
 
 	/* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
 	 * or Authenticator state machines, but EAPOL-Key packets are not
-	 * retransmitted in case of failure. Try to re-sent failed EAPOL-Key
+	 * retransmitted in case of failure. Try to re-send failed EAPOL-Key
 	 * packets couple of times because otherwise STA keys become
 	 * unsynchronized with AP. */
-	if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && !ack &&
-	    pos + sizeof(*key) <= buf + len) {
+	if (!ack && pos + sizeof(*key) <= buf + len) {
 		key = (struct ieee802_1x_eapol_key *) pos;
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
@@ -1943,6 +1929,7 @@
 {
 	int len = 0, ret;
 	struct eapol_state_machine *sm = sta->eapol_sm;
+	struct os_time t;
 
 	if (sm == NULL)
 		return 0;
@@ -2057,6 +2044,7 @@
 	len += ret;
 
 	/* dot1xAuthSessionStatsTable */
+	os_get_time(&t);
 	ret = os_snprintf(buf + len, buflen - len,
 			  /* TODO: dot1xAuthSessionOctetsRx */
 			  /* TODO: dot1xAuthSessionOctetsTx */
@@ -2071,8 +2059,7 @@
 			  (wpa_key_mgmt_wpa_ieee8021x(
 				   wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
 			  1 : 2,
-			  (unsigned int) (time(NULL) -
-					  sta->acct_session_start),
+			  (unsigned int) (t.sec - sta->acct_session_start),
 			  sm->identity);
 	if (ret < 0 || (size_t) ret >= buflen - len)
 		return len;
@@ -2099,22 +2086,25 @@
 			       "Added PMKSA cache entry (IEEE 802.1X)");
 	}
 
-#ifdef CONFIG_WPS
-	if (!success && (sta->flags & WLAN_STA_WPS)) {
+	if (!success) {
 		/*
 		 * Many devices require deauthentication after WPS provisioning
 		 * and some may not be be able to do that themselves, so
-		 * disconnect the client here.
+		 * disconnect the client here. In addition, this may also
+		 * benefit IEEE 802.1X/EAPOL authentication cases, too since
+		 * the EAPOL PAE state machine would remain in HELD state for
+		 * considerable amount of time and some EAP methods, like
+		 * EAP-FAST with anonymous provisioning, may require another
+		 * EAPOL authentication to be started to complete connection.
 		 */
-		wpa_printf(MSG_DEBUG, "WPS: Force disconnection after "
-			   "EAP-Failure");
+		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
+			"disconnection after EAP-Failure");
 		/* Add a small sleep to increase likelihood of previously
 		 * requested EAP-Failure TX getting out before this should the
 		 * driver reorder operations.
 		 */
 		os_sleep(0, 10000);
 		ap_sta_disconnect(hapd, sta, sta->addr,
-				  WLAN_REASON_PREV_AUTH_NOT_VALID);
+				  WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
 	}
-#endif /* CONFIG_WPS */
 }
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index 1a4d2eb..267e22a 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -68,6 +68,8 @@
 void ieee802_1x_deinit(struct hostapd_data *hapd);
 int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
 			 const u8 *buf, size_t len, int ack);
+int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			       const u8 *data, int len, int ack);
 u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
 u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
 				 int idx);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index e829447..972a723 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / Station table
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "drivers/driver.h"
@@ -38,9 +39,12 @@
 static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
 				       struct sta_info *sta);
 static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
+static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
+static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
 #ifdef CONFIG_IEEE80211W
 static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
 #endif /* CONFIG_IEEE80211W */
+static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
 
 int ap_for_each_sta(struct hostapd_data *hapd,
 		    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
@@ -198,6 +202,8 @@
 
 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
 	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
 
 	ieee802_1x_free_station(sta);
 	wpa_auth_sta_deinit(sta->wpa_sm);
@@ -222,6 +228,7 @@
 	wpabuf_free(sta->p2p_ie);
 
 	os_free(sta->ht_capabilities);
+	os_free(sta->psk);
 
 	os_free(sta);
 }
@@ -275,31 +282,37 @@
 		int inactive_sec;
 		inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
 		if (inactive_sec == -1) {
-			wpa_msg(hapd, MSG_DEBUG, "Check inactivity: Could not "
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"Check inactivity: Could not "
 				"get station info rom kernel driver for "
 				MACSTR, MAC2STR(sta->addr));
 		} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
 			   sta->flags & WLAN_STA_ASSOC) {
 			/* station activity detected; reset timeout state */
-			wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been "
-				"active %is ago",
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"Station " MACSTR " has been active %is ago",
 				MAC2STR(sta->addr), inactive_sec);
 			sta->timeout_next = STA_NULLFUNC;
 			next_time = hapd->conf->ap_max_inactivity -
 				inactive_sec;
 		} else {
-			wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been "
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"Station " MACSTR " has been "
 				"inactive too long: %d sec, max allowed: %d",
 				MAC2STR(sta->addr), inactive_sec,
 				hapd->conf->ap_max_inactivity);
+
+			if (hapd->conf->skip_inactivity_poll)
+				sta->timeout_next = STA_DISASSOC;
 		}
 	}
 
 	if ((sta->flags & WLAN_STA_ASSOC) &&
 	    sta->timeout_next == STA_DISASSOC &&
-	    !(sta->flags & WLAN_STA_PENDING_POLL)) {
-		wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has ACKed data "
-			"poll", MAC2STR(sta->addr));
+	    !(sta->flags & WLAN_STA_PENDING_POLL) &&
+	    !hapd->conf->skip_inactivity_poll) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
+			" has ACKed data poll", MAC2STR(sta->addr));
 		/* data nullfunc frame poll did not produce TX errors; assume
 		 * station ACKed it */
 		sta->timeout_next = STA_NULLFUNC;
@@ -314,46 +327,17 @@
 
 	if (sta->timeout_next == STA_NULLFUNC &&
 	    (sta->flags & WLAN_STA_ASSOC)) {
-#ifndef CONFIG_NATIVE_WINDOWS
-		/* send data frame to poll STA and check whether this frame
-		 * is ACKed */
-		struct ieee80211_hdr hdr;
-
-		wpa_printf(MSG_DEBUG, "  Polling STA with data frame");
+		wpa_printf(MSG_DEBUG, "  Polling STA");
 		sta->flags |= WLAN_STA_PENDING_POLL;
-
-		os_memset(&hdr, 0, sizeof(hdr));
-		if (hapd->driver &&
-		    os_strcmp(hapd->driver->name, "hostap") == 0) {
-			/*
-			 * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
-			 * but it is apparently not retried so TX Exc events
-			 * are not received for it.
-			 */
-			hdr.frame_control =
-				IEEE80211_FC(WLAN_FC_TYPE_DATA,
-					     WLAN_FC_STYPE_DATA);
-		} else {
-			hdr.frame_control =
-				IEEE80211_FC(WLAN_FC_TYPE_DATA,
-					     WLAN_FC_STYPE_NULLFUNC);
-		}
-
-		hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
-		os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN);
-		os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
-			  ETH_ALEN);
-		os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN);
-
-		if (hostapd_drv_send_mlme(hapd, &hdr, sizeof(hdr)) < 0)
-			perror("ap_handle_timer: send");
-#endif /* CONFIG_NATIVE_WINDOWS */
+		hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr,
+					sta->flags & WLAN_STA_WMM);
 	} else if (sta->timeout_next != STA_REMOVE) {
 		int deauth = sta->timeout_next == STA_DEAUTH;
 
-		wpa_printf(MSG_DEBUG, "Sending %s info to STA " MACSTR,
-			   deauth ? "deauthentication" : "disassociation",
-			   MAC2STR(sta->addr));
+		wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+			"Timeout, sending %s info to STA " MACSTR,
+			deauth ? "deauthentication" : "disassociation",
+			MAC2STR(sta->addr));
 
 		if (deauth) {
 			hostapd_drv_sta_deauth(
@@ -373,6 +357,7 @@
 				       hapd, sta);
 		break;
 	case STA_DISASSOC:
+		ap_sta_set_authorized(hapd, sta, 0);
 		sta->flags &= ~WLAN_STA_ASSOC;
 		ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
 		if (!sta->acct_terminate_cause)
@@ -393,7 +378,7 @@
 	case STA_REMOVE:
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
-			       "inactivity");
+			       "inactivity (timer DEAUTH/REMOVE)");
 		if (!sta->acct_terminate_cause)
 			sta->acct_terminate_cause =
 				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
@@ -525,13 +510,23 @@
 }
 
 
+static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+
+	ap_sta_remove(hapd, sta);
+	mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
+}
+
+
 void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
 			 u16 reason)
 {
 	wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
 		   hapd->conf->iface, MAC2STR(sta->addr));
 	sta->flags &= ~WLAN_STA_ASSOC;
-	ap_sta_remove(hapd, sta);
+	ap_sta_set_authorized(hapd, sta, 0);
 	sta->timeout_next = STA_DEAUTH;
 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
 	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
@@ -539,7 +534,22 @@
 	accounting_sta_stop(hapd, sta);
 	ieee802_1x_free_station(sta);
 
-	mlme_disassociate_indication(hapd, sta, reason);
+	sta->disassoc_reason = reason;
+	sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
+	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+	eloop_register_timeout(hapd->iface->drv_flags &
+			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+			       ap_sta_disassoc_cb_timeout, hapd, sta);
+}
+
+
+static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+
+	ap_sta_remove(hapd, sta);
+	mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
 }
 
 
@@ -549,7 +559,7 @@
 	wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
 		   hapd->conf->iface, MAC2STR(sta->addr));
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-	ap_sta_remove(hapd, sta);
+	ap_sta_set_authorized(hapd, sta, 0);
 	sta->timeout_next = STA_REMOVE;
 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
 	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
@@ -557,7 +567,12 @@
 	accounting_sta_stop(hapd, sta);
 	ieee802_1x_free_station(sta);
 
-	mlme_deauthenticate_indication(hapd, sta, reason);
+	sta->deauth_reason = reason;
+	sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	eloop_register_timeout(hapd->iface->drv_flags &
+			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+			       ap_sta_deauth_cb_timeout, hapd, sta);
 }
 
 
@@ -762,17 +777,58 @@
 void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
 			   int authorized)
 {
+	const u8 *dev_addr = NULL;
 	if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
 		return;
 
-	if (authorized)
+#ifdef CONFIG_P2P
+	dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
+#endif /* CONFIG_P2P */
+
+	if (authorized) {
+		if (dev_addr)
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
+				MACSTR " p2p_dev_addr=" MACSTR,
+				MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
+				MACSTR, MAC2STR(sta->addr));
+		if (hapd->msg_ctx_parent &&
+		    hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_CONNECTED MACSTR " p2p_dev_addr="
+				MACSTR,
+				MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else if (hapd->msg_ctx_parent &&
+			 hapd->msg_ctx_parent != hapd->msg_ctx)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
+
 		sta->flags |= WLAN_STA_AUTHORIZED;
-	else
+	} else {
+		if (dev_addr)
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
+				MACSTR " p2p_dev_addr=" MACSTR,
+				MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
+				MACSTR, MAC2STR(sta->addr));
+		if (hapd->msg_ctx_parent &&
+		    hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_DISCONNECTED MACSTR " p2p_dev_addr="
+				MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else if (hapd->msg_ctx_parent &&
+			 hapd->msg_ctx_parent != hapd->msg_ctx)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_DISCONNECTED MACSTR,
+				MAC2STR(sta->addr));
 		sta->flags &= ~WLAN_STA_AUTHORIZED;
+	}
 
 	if (hapd->sta_authorized_cb)
 		hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
-					sta->addr, authorized);
+					sta->addr, authorized, dev_addr);
 }
 
 
@@ -791,6 +847,38 @@
 	ap_sta_set_authorized(hapd, sta, 0);
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-	eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
+	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
+			       ap_handle_timer, hapd, sta);
 	sta->timeout_next = STA_REMOVE;
+
+	sta->deauth_reason = reason;
+	sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	eloop_register_timeout(hapd->iface->drv_flags &
+			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+			       ap_sta_deauth_cb_timeout, hapd, sta);
+}
+
+
+void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) {
+		wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame");
+		return;
+	}
+	sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB;
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	ap_sta_deauth_cb_timeout(hapd, sta);
+}
+
+
+void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) {
+		wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame");
+		return;
+	}
+	sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB;
+	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+	ap_sta_disassoc_cb_timeout(hapd, sta);
 }
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 9ec4fe3..daa96bf 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -1,6 +1,6 @@
 /*
  * hostapd / Station table
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -32,6 +32,9 @@
 #define WLAN_STA_MAYBE_WPS BIT(13)
 #define WLAN_STA_WDS BIT(14)
 #define WLAN_STA_ASSOC_REQ_OK BIT(15)
+#define WLAN_STA_WPS2 BIT(16)
+#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
+#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
 #define WLAN_STA_NONERP BIT(31)
 
 /* Maximum number of supported rates (from both Supported Rates and Extended
@@ -49,6 +52,7 @@
 	u16 listen_interval; /* or beacon_int for APs */
 	u8 supported_rates[WLAN_SUPP_RATES_MAX];
 	int supported_rates_len;
+	u8 qosinfo; /* Valid when WLAN_STA_WMM is set */
 
 	unsigned int nonerp_set:1;
 	unsigned int no_short_slot_time_set:1;
@@ -65,6 +69,9 @@
 		STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
 	} timeout_next;
 
+	u16 deauth_reason;
+	u16 disassoc_reason;
+
 	/* IEEE 802.1X related data */
 	struct eapol_state_machine *eapol_sm;
 
@@ -92,6 +99,7 @@
 	struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
 
 	int vlan_id;
+	u8 *psk; /* PSK from RADIUS authentication server */
 
 	struct ieee80211_ht_capabilities *ht_capabilities;
 
@@ -114,7 +122,7 @@
  * passed since last received frame from the station, a nullfunc data frame is
  * sent to the station. If this frame is not acknowledged and no other frames
  * have been received, the station will be disassociated after
- * AP_DISASSOC_DELAY seconds. Similarily, the station will be deauthenticated
+ * AP_DISASSOC_DELAY seconds. Similarly, the station will be deauthenticated
  * after AP_DEAUTH_DELAY seconds has passed after disassociation. */
 #define AP_MAX_INACTIVITY (5 * 60)
 #define AP_DISASSOC_DELAY (1)
@@ -162,4 +170,7 @@
 	return sta->flags & WLAN_STA_AUTHORIZED;
 }
 
+void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
+
 #endif /* STA_INFO_H */
diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c
index 1925217..fac7f4b 100644
--- a/src/ap/tkip_countermeasures.c
+++ b/src/ap/tkip_countermeasures.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / TKIP countermeasures
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -60,9 +60,15 @@
 }
 
 
+void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd)
+{
+	eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
+}
+
+
 void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
 {
-	time_t now;
+	struct os_time now;
 
 	if (addr && local) {
 		struct sta_info *sta = ap_get_sta(hapd, addr);
@@ -82,13 +88,13 @@
 		}
 	}
 
-	time(&now);
-	if (now > hapd->michael_mic_failure + 60) {
+	os_get_time(&now);
+	if (now.sec > hapd->michael_mic_failure + 60) {
 		hapd->michael_mic_failures = 1;
 	} else {
 		hapd->michael_mic_failures++;
 		if (hapd->michael_mic_failures > 1)
 			ieee80211_tkip_countermeasures_start(hapd);
 	}
-	hapd->michael_mic_failure = now;
+	hapd->michael_mic_failure = now.sec;
 }
diff --git a/src/ap/tkip_countermeasures.h b/src/ap/tkip_countermeasures.h
index 5a1afce..a8ffd16 100644
--- a/src/ap/tkip_countermeasures.h
+++ b/src/ap/tkip_countermeasures.h
@@ -1,6 +1,6 @@
 /*
  * hostapd / TKIP countermeasures
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -16,5 +16,6 @@
 #define TKIP_COUNTERMEASURES_H
 
 void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
+void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd);
 
 #endif /* TKIP_COUNTERMEASURES_H */
diff --git a/src/ap/utils.c b/src/ap/utils.c
index 0ff48ae..09bc32f 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -22,6 +22,7 @@
 
 int hostapd_register_probereq_cb(struct hostapd_data *hapd,
 				 int (*cb)(void *ctx, const u8 *sa,
+					   const u8 *da, const u8 *bssid,
 					   const u8 *ie, size_t ie_len),
 				 void *ctx)
 {
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index a6d9b89..d21c82f 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -72,7 +72,8 @@
 	wmm->version = WMM_VERSION;
 	wmm->qos_info = hapd->parameter_set_count & 0xf;
 
-	if (hapd->conf->wmm_uapsd)
+	if (hapd->conf->wmm_uapsd &&
+	    (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
 		wmm->qos_info |= 0x80;
 
 	wmm->reserved = 0;
@@ -97,9 +98,11 @@
 }
 
 
-/* This function is called when a station sends an association request with
- * WMM info element. The function returns zero on success or non-zero on any
- * error in WMM element. eid does not include Element ID and Length octets. */
+/*
+ * This function is called when a station sends an association request with
+ * WMM info element. The function returns 1 on success or 0 on any error in WMM
+ * element. eid does not include Element ID and Length octets.
+ */
 int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
 {
 	struct wmm_information_element *wmm;
@@ -109,7 +112,7 @@
 	if (len < sizeof(struct wmm_information_element)) {
 		wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)",
 			   (unsigned long) len);
-		return -1;
+		return 0;
 	}
 
 	wmm = (struct wmm_information_element *) eid;
@@ -120,10 +123,10 @@
 	if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT ||
 	    wmm->version != WMM_VERSION) {
 		wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version");
-		return -1;
+		return 0;
 	}
 
-	return 0;
+	return 1;
 }
 
 
@@ -153,7 +156,7 @@
 	os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
 	len = ((u8 *) (t + 1)) - buf;
 
-	if (hostapd_drv_send_mlme(hapd, m, len) < 0)
+	if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
 		perror("wmm_send_action: send");
 }
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 0836887..adc69e2 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1,6 +1,6 @@
 /*
- * hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * IEEE 802.11 RSN / WPA Authenticator
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -52,6 +52,7 @@
 static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
 static const u32 eapol_key_timeout_first = 100; /* ms */
 static const u32 eapol_key_timeout_subseq = 1000; /* ms */
+static const u32 eapol_key_timeout_first_group = 500; /* ms */
 
 /* TODO: make these configurable */
 static const int dot11RSNAConfigPMKLifetime = 43200;
@@ -194,6 +195,7 @@
 {
 	if (wpa_auth->cb.disconnect == NULL)
 		return;
+	wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR, MAC2STR(addr));
 	wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr,
 				WLAN_REASON_PREV_AUTH_NOT_VALID);
 }
@@ -332,7 +334,7 @@
 
 
 static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
-					 int vlan_id)
+					 int vlan_id, int delay_init)
 {
 	struct wpa_group *group;
 
@@ -349,10 +351,6 @@
 		wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
 			   "for secure operations - update keys later when "
 			   "the first station connects");
-#ifdef ANDROID_BRCM_P2P_PATCH
-		os_free(group);
-		return NULL;
-#endif
 	}
 
 	/*
@@ -369,9 +367,15 @@
 	}
 
 	group->GInit = TRUE;
-	wpa_group_sm_step(wpa_auth, group);
-	group->GInit = FALSE;
-	wpa_group_sm_step(wpa_auth, group);
+	if (delay_init) {
+		wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start "
+			   "until Beacon frames have been configured");
+		/* Initialization is completed in wpa_init_keys(). */
+	} else {
+		wpa_group_sm_step(wpa_auth, group);
+		group->GInit = FALSE;
+		wpa_group_sm_step(wpa_auth, group);
+	}
 
 	return group;
 }
@@ -403,7 +407,7 @@
 		return NULL;
 	}
 
-	wpa_auth->group = wpa_group_init(wpa_auth, 0);
+	wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
 	if (wpa_auth->group == NULL) {
 		os_free(wpa_auth->wpa_ie);
 		os_free(wpa_auth);
@@ -444,6 +448,19 @@
 }
 
 
+int wpa_init_keys(struct wpa_authenticator *wpa_auth)
+{
+	struct wpa_group *group = wpa_auth->group;
+
+	wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial "
+		   "keys");
+	wpa_group_sm_step(wpa_auth, group);
+	group->GInit = FALSE;
+	wpa_group_sm_step(wpa_auth, group);
+	return 0;
+}
+
+
 /**
  * wpa_deinit - Deinitialize WPA authenticator
  * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
@@ -695,6 +712,37 @@
 #endif /* CONFIG_IEEE80211R */
 
 
+static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
+				     struct wpa_state_machine *sm, int group)
+{
+	/* Supplicant reported a Michael MIC error */
+	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+			 "received EAPOL-Key Error Request "
+			 "(STA detected Michael MIC failure (group=%d))",
+			 group);
+
+	if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"ignore Michael MIC failure report since "
+				"group cipher is not TKIP");
+	} else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"ignore Michael MIC failure report since "
+				"pairwise cipher is not TKIP");
+	} else {
+		wpa_auth_mic_failure_report(wpa_auth, sm->addr);
+		sm->dot11RSNAStatsTKIPRemoteMICFailures++;
+		wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
+	}
+
+	/*
+	 * Error report is not a request for a new key handshake, but since
+	 * Authenticator may do it, let's change the keys now anyway.
+	 */
+	wpa_request_new_ptk(sm);
+}
+
+
 void wpa_receive(struct wpa_authenticator *wpa_auth,
 		 struct wpa_state_machine *sm,
 		 u8 *data, size_t data_len)
@@ -720,6 +768,9 @@
 	key = (struct wpa_eapol_key *) (hdr + 1);
 	key_info = WPA_GET_BE16(key->key_info);
 	key_data_length = WPA_GET_BE16(key->key_data_length);
+	wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
+		   " key_info=0x%x type=%u key_data_length=%u",
+		   MAC2STR(sm->addr), key_info, key->type, key_data_length);
 	if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
 		wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
 			   "key_data overflow (%d > %lu)",
@@ -819,7 +870,7 @@
 	if (!(key_info & WPA_KEY_INFO_REQUEST) &&
 	    !wpa_replay_counter_valid(sm, key->replay_counter)) {
 		int i;
-		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
 				 "received EAPOL-Key %s with unexpected "
 				 "replay counter", msgtxt);
 		for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
@@ -1000,17 +1051,9 @@
 #endif /* CONFIG_PEERKEY */
 			return;
 		} else if (key_info & WPA_KEY_INFO_ERROR) {
-			/* Supplicant reported a Michael MIC error */
-			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-					"received EAPOL-Key Error Request "
-					"(STA detected Michael MIC failure)");
-			wpa_auth_mic_failure_report(wpa_auth, sm->addr);
-			sm->dot11RSNAStatsTKIPRemoteMICFailures++;
-			wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
-			/* Error report is not a request for a new key
-			 * handshake, but since Authenticator may do it, let's
-			 * change the keys now anyway. */
-			wpa_request_new_ptk(sm);
+			wpa_receive_error_report(
+				wpa_auth, sm,
+				!(key_info & WPA_KEY_INFO_KEY_TYPE));
 		} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
 					"received EAPOL-Key Request for new "
@@ -1028,9 +1071,6 @@
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
 					"received EAPOL-Key Request for GTK "
 					"rekeying");
-			/* FIX: why was this triggering PTK rekeying for the
-			 * STA that requested Group Key rekeying?? */
-			/* wpa_request_new_ptk(sta->wpa_sm); */
 			eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
 			wpa_rekey_gtk(wpa_auth, NULL);
 		}
@@ -1057,6 +1097,7 @@
 	os_memcpy(sm->last_rx_eapol_key, data, data_len);
 	sm->last_rx_eapol_key_len = data_len;
 
+	sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE);
 	sm->EAPOLKeyReceived = TRUE;
 	sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
 	sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
@@ -1293,7 +1334,8 @@
 
 	ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
 	if (ctr == 1 && wpa_auth->conf.tx_status)
-		timeout_ms = eapol_key_timeout_first;
+		timeout_ms = pairwise ? eapol_key_timeout_first :
+			eapol_key_timeout_first_group;
 	else
 		timeout_ms = eapol_key_timeout_subseq;
 	if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
@@ -1844,6 +1886,20 @@
 		gtk_len = 0;
 		keyidx = 0;
 		_rsc = NULL;
+		if (sm->rx_eapol_key_secure) {
+			/*
+			 * It looks like Windows 7 supplicant tries to use
+			 * Secure bit in msg 2/4 after having reported Michael
+			 * MIC failure and it then rejects the 4-way handshake
+			 * if msg 3/4 does not set Secure bit. Work around this
+			 * by setting the Secure bit here even in the case of
+			 * WPA if the supplicant used it first.
+			 */
+			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+					"STA used Secure bit in WPA msg 2/4 - "
+					"set Secure for 3/4 as workaround");
+			secure = 1;
+		}
 	}
 
 	kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
@@ -2469,6 +2525,7 @@
 		group->GN_igtk = tmp;
 #endif /* CONFIG_IEEE80211W */
 		wpa_gtk_update(wpa_auth, group);
+		wpa_group_config_group_keys(wpa_auth, group);
 	}
 }
 
@@ -2771,7 +2828,7 @@
 
 	wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
 		   vlan_id);
-	group = wpa_group_init(wpa_auth, vlan_id);
+	group = wpa_group_init(wpa_auth, vlan_id, 0);
 	if (group == NULL)
 		return NULL;
 
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index e533a14..ce2751e 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -208,6 +208,7 @@
 struct wpa_authenticator * wpa_init(const u8 *addr,
 				    struct wpa_auth_config *conf,
 				    struct wpa_auth_callbacks *cb);
+int wpa_init_keys(struct wpa_authenticator *wpa_auth);
 void wpa_deinit(struct wpa_authenticator *wpa_auth);
 int wpa_reconfig(struct wpa_authenticator *wpa_auth,
 		 struct wpa_auth_config *conf);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 65f5f4c..2d1bbe4 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -24,33 +24,10 @@
 #include "wmm.h"
 #include "wpa_auth.h"
 #include "wpa_auth_i.h"
-#include "wpa_auth_ie.h"
 
 
 #ifdef CONFIG_IEEE80211R
 
-struct wpa_ft_ies {
-	const u8 *mdie;
-	size_t mdie_len;
-	const u8 *ftie;
-	size_t ftie_len;
-	const u8 *r1kh_id;
-	const u8 *gtk;
-	size_t gtk_len;
-	const u8 *r0kh_id;
-	size_t r0kh_id_len;
-	const u8 *rsn;
-	size_t rsn_len;
-	const u8 *rsn_pmkid;
-	const u8 *ric;
-	size_t ric_len;
-};
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-			    struct wpa_ft_ies *parse);
-
-
 static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
 			   const u8 *data, size_t data_len)
 {
@@ -728,143 +705,6 @@
 }
 
 
-static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
-			     struct wpa_ft_ies *parse)
-{
-	const u8 *end, *pos;
-
-	parse->ftie = ie;
-	parse->ftie_len = ie_len;
-
-	pos = ie + sizeof(struct rsn_ftie);
-	end = ie + ie_len;
-
-	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-		switch (pos[0]) {
-		case FTIE_SUBELEM_R1KH_ID:
-			if (pos[1] != FT_R1KH_ID_LEN) {
-				wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
-					   "length in FTIE: %d", pos[1]);
-				return -1;
-			}
-			parse->r1kh_id = pos + 2;
-			break;
-		case FTIE_SUBELEM_GTK:
-			parse->gtk = pos + 2;
-			parse->gtk_len = pos[1];
-			break;
-		case FTIE_SUBELEM_R0KH_ID:
-			if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
-				wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
-					   "length in FTIE: %d", pos[1]);
-				return -1;
-			}
-			parse->r0kh_id = pos + 2;
-			parse->r0kh_id_len = pos[1];
-			break;
-		}
-
-		pos += 2 + pos[1];
-	}
-
-	return 0;
-}
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-			    struct wpa_ft_ies *parse)
-{
-	const u8 *end, *pos;
-	struct wpa_ie_data data;
-	int ret;
-	const struct rsn_ftie *ftie;
-	int prot_ie_count = 0;
-
-	os_memset(parse, 0, sizeof(*parse));
-	if (ies == NULL)
-		return 0;
-
-	pos = ies;
-	end = ies + ies_len;
-	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-		switch (pos[0]) {
-		case WLAN_EID_RSN:
-			parse->rsn = pos + 2;
-			parse->rsn_len = pos[1];
-			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
-						   parse->rsn_len + 2,
-						   &data);
-			if (ret < 0) {
-				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
-					   "RSN IE: %d", ret);
-				return -1;
-			}
-			if (data.num_pmkid == 1 && data.pmkid)
-				parse->rsn_pmkid = data.pmkid;
-			break;
-		case WLAN_EID_MOBILITY_DOMAIN:
-			parse->mdie = pos + 2;
-			parse->mdie_len = pos[1];
-			break;
-		case WLAN_EID_FAST_BSS_TRANSITION:
-			if (pos[1] < sizeof(*ftie))
-				return -1;
-			ftie = (const struct rsn_ftie *) (pos + 2);
-			prot_ie_count = ftie->mic_control[1];
-			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
-				return -1;
-			break;
-		case WLAN_EID_RIC_DATA:
-			if (parse->ric == NULL)
-				parse->ric = pos;
-		}
-
-		pos += 2 + pos[1];
-	}
-
-	if (prot_ie_count == 0)
-		return 0; /* no MIC */
-
-	/*
-	 * Check that the protected IE count matches with IEs included in the
-	 * frame.
-	 */
-	if (parse->rsn)
-		prot_ie_count--;
-	if (parse->mdie)
-		prot_ie_count--;
-	if (parse->ftie)
-		prot_ie_count--;
-	if (prot_ie_count < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
-			   "the protected IE count");
-		return -1;
-	}
-
-	if (prot_ie_count == 0 && parse->ric) {
-		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
-			   "included in protected IE count");
-		return -1;
-	}
-
-	/* Determine the end of the RIC IE(s) */
-	pos = parse->ric;
-	while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
-	       prot_ie_count) {
-		prot_ie_count--;
-		pos += 2 + pos[1];
-	}
-	parse->ric_len = pos - parse->ric;
-	if (prot_ie_count) {
-		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
-			   "frame", (int) prot_ie_count);
-		return -1;
-	}
-
-	return 0;
-}
-
-
 static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
 				   int vlan_id,
 				   enum wpa_alg alg, const u8 *addr, int idx,
@@ -1207,7 +1047,7 @@
 
 	count = 3;
 	if (parse.ric)
-		count++;
+		count += ieee802_11_ie_count(parse.ric, parse.ric_len);
 	if (ftie->mic_control[1] != count) {
 		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
 			   "Control: received %u expected %u",
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 0e3cb31..56bab23 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -29,11 +29,13 @@
 #include "ap_drv_ops.h"
 #include "ap_config.h"
 #include "wpa_auth.h"
+#include "wpa_auth_glue.h"
 
 
 static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
 				  struct wpa_auth_config *wconf)
 {
+	os_memset(wconf, 0, sizeof(*wconf));
 	wconf->wpa = conf->wpa;
 	wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
 	wconf->wpa_pairwise = conf->wpa_pairwise;
@@ -184,6 +186,9 @@
 					   const u8 *prev_psk)
 {
 	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	if (sta && sta->psk)
+		return sta->psk;
 	return hostapd_get_psk(hapd->conf, addr, prev_psk);
 }
 
@@ -384,7 +389,7 @@
 	ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf,
 			     sizeof(*buf) + data_len);
 	os_free(buf);
-	return -1;
+	return ret;
 }
 
 
@@ -414,7 +419,7 @@
 	os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
 	os_memcpy(&m->u, data, data_len);
 
-	res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen);
+	res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0);
 	os_free(m);
 	return res;
 }
@@ -547,6 +552,7 @@
 
 void hostapd_deinit_wpa(struct hostapd_data *hapd)
 {
+	ieee80211_tkip_countermeasures_deinit(hapd);
 	rsn_preauth_iface_deinit(hapd);
 	if (hapd->wpa_auth) {
 		wpa_deinit(hapd->wpa_auth);
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 67a5c3b..d82192a 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -86,6 +86,7 @@
 	unsigned int pending_deinit:1;
 	unsigned int started:1;
 	unsigned int mgmt_frame_prot:1;
+	unsigned int rx_eapol_key_secure:1;
 #ifdef CONFIG_IEEE80211R
 	unsigned int ft_completed:1;
 	unsigned int pmk_r1_name_valid:1;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 9d4aa67..4db04bb 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -253,19 +253,10 @@
 		capab |= WPA_CAPABILITY_PREAUTH;
 	if (conf->peerkey)
 		capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
-#ifdef ANDROID_BRCM_P2P_PATCH 
-    /* WAR: we should make an get_wpa_rsnie_cap() to get the cap of peer supp 
-	 * Temporally we force tp set replay counter tp 0x3 
-	 * as if wmm is enable in all of supp device
-     */
-    capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); 
-#else
 	if (conf->wmm_enabled) {
 		/* 4 PTKSA replay counters when using WMM */
 		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
 	}
-#endif /* ANDROID_BRCM_P2P_PATCH */
-
 #ifdef CONFIG_IEEE80211W
 	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
 		capab |= WPA_CAPABILITY_MFPC;
@@ -350,8 +341,7 @@
 		pos += res;
 	}
 #ifdef CONFIG_IEEE80211R
-	if (wpa_auth->conf.wpa_key_mgmt &
-	    (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) {
+	if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
 		res = wpa_write_mdie(&wpa_auth->conf, pos,
 				     buf + sizeof(buf) - pos);
 		if (res < 0)
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 640e8cd..817012e 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -41,7 +41,8 @@
 static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
 #endif /* CONFIG_WPS_UPNP */
 
-static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
+static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
+				    const u8 *bssid,
 				    const u8 *ie, size_t ie_len);
 static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
 
@@ -140,7 +141,8 @@
 	hapd->wps_beacon_ie = beacon_ie;
 	wpabuf_free(hapd->wps_probe_resp_ie);
 	hapd->wps_probe_resp_ie = probe_resp_ie;
-	ieee802_11_set_beacon(hapd);
+	if (hapd->beacon_set_done)
+		ieee802_11_set_beacon(hapd);
 	return hostapd_set_ap_wps_ie(hapd);
 }
 
@@ -184,11 +186,26 @@
 }
 
 
+struct wps_stop_reg_data {
+	struct hostapd_data *current_hapd;
+	const u8 *uuid_e;
+};
+
+static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx)
+{
+	struct wps_stop_reg_data *data = ctx;
+	if (hapd != data->current_hapd && hapd->wps != NULL)
+		wps_registrar_complete(hapd->wps->registrar, data->uuid_e);
+	return 0;
+}
+
+
 static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
 				       const u8 *uuid_e)
 {
 	struct hostapd_data *hapd = ctx;
 	char uuid[40];
+	struct wps_stop_reg_data data;
 	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
 		return;
 	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s",
@@ -196,6 +213,9 @@
 	if (hapd->wps_reg_success_cb)
 		hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx,
 					 mac_addr, uuid_e);
+	data.current_hapd = hapd;
+	data.uuid_e = uuid_e;
+	hostapd_wps_for_each(hapd, wps_stop_registrar, &data);
 }
 
 
@@ -240,6 +260,20 @@
 }
 
 
+static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr,
+			      size_t attr_len)
+{
+	size_t blen = attr_len * 2 + 1;
+	char *buf = os_malloc(blen);
+	if (buf) {
+		wpa_snprintf_hex(buf, blen, attr, attr_len);
+		wpa_msg(hapd->msg_ctx, MSG_INFO,
+			WPS_EVENT_NEW_AP_SETTINGS "%s", buf);
+		os_free(buf);
+	}
+}
+
+
 static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
 {
 	const struct wps_credential *cred = ctx;
@@ -269,15 +303,15 @@
 
 	if ((hapd->conf->wps_cred_processing == 1 ||
 	     hapd->conf->wps_cred_processing == 2) && cred->cred_attr) {
-		size_t blen = cred->cred_attr_len * 2 + 1;
-		char *_buf = os_malloc(blen);
-		if (_buf) {
-			wpa_snprintf_hex(_buf, blen,
-					 cred->cred_attr, cred->cred_attr_len);
-			wpa_msg(hapd->msg_ctx, MSG_INFO, "%s%s",
-				WPS_EVENT_NEW_AP_SETTINGS, _buf);
-			os_free(_buf);
-		}
+		hapd_new_ap_event(hapd, cred->cred_attr, cred->cred_attr_len);
+	} else if (hapd->conf->wps_cred_processing == 1 ||
+		   hapd->conf->wps_cred_processing == 2) {
+		struct wpabuf *attr;
+		attr = wpabuf_alloc(200);
+		if (attr && wps_build_credential_wrap(attr, cred) == 0)
+			hapd_new_ap_event(hapd, wpabuf_head_u8(attr),
+					  wpabuf_len(attr));
+		wpabuf_free(attr);
 	} else
 		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
 
@@ -565,18 +599,22 @@
 
 	switch (event) {
 	case WPS_EV_M2D:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_M2D);
 		break;
 	case WPS_EV_FAIL:
 		hostapd_wps_event_fail(hapd, &data->fail);
 		break;
 	case WPS_EV_SUCCESS:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS);
 		break;
 	case WPS_EV_PWD_AUTH_FAIL:
 		hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
 		break;
 	case WPS_EV_PBC_OVERLAP:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP);
 		break;
 	case WPS_EV_PBC_TIMEOUT:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT);
 		break;
 	case WPS_EV_ER_AP_ADD:
 		break;
@@ -762,8 +800,14 @@
 	}
 
 	wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
-	wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
-		WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+
+	if (conf->wps_rf_bands) {
+		wps->dev.rf_bands = conf->wps_rf_bands;
+	} else {
+		wps->dev.rf_bands =
+			hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
+			WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+	}
 
 	if (conf->wpa & WPA_PROTO_RSN) {
 		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
@@ -1076,7 +1120,8 @@
 #endif /* CONFIG_WPS_OOB */
 
 
-static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
+static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
+				    const u8 *bssid,
 				    const u8 *ie, size_t ie_len)
 {
 	struct hostapd_data *hapd = ctx;
@@ -1175,7 +1220,7 @@
 	}
 #endif /* CONFIG_WPS_STRICT */
 
-	if (!sta) {
+	if (!sta || !(sta->flags & WLAN_STA_WPS)) {
 		wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
 		return 0;
 	}
@@ -1240,6 +1285,7 @@
 	struct hostapd_data *hapd = eloop_data;
 	wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
 	hostapd_wps_ap_pin_disable(hapd);
+	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED);
 }
 
 
@@ -1304,7 +1350,7 @@
 	struct wps_ap_pin_data data;
 
 	pin = wps_generate_pin();
-	os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%u", pin);
+	os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin);
 	data.timeout = timeout;
 	hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
 	return hapd->conf->ap_pin;
diff --git a/src/common/defs.h b/src/common/defs.h
index 8abec07..6082053 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -76,6 +76,11 @@
 		wpa_key_mgmt_wpa_psk(akm);
 }
 
+static inline int wpa_key_mgmt_wpa_any(int akm)
+{
+	return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE);
+}
+
 
 #define WPA_PROTO_WPA BIT(0)
 #define WPA_PROTO_RSN BIT(1)
@@ -267,4 +272,21 @@
 	NUM_HOSTAPD_MODES
 };
 
+/**
+ * enum wpa_ctrl_req_type - Control interface request types
+ */
+enum wpa_ctrl_req_type {
+	WPA_CTRL_REQ_UNKNOWN,
+	WPA_CTRL_REQ_EAP_IDENTITY,
+	WPA_CTRL_REQ_EAP_PASSWORD,
+	WPA_CTRL_REQ_EAP_NEW_PASSWORD,
+	WPA_CTRL_REQ_EAP_PIN,
+	WPA_CTRL_REQ_EAP_OTP,
+	WPA_CTRL_REQ_EAP_PASSPHRASE,
+	NUM_WPA_CTRL_REQS
+};
+
+/* Maximum number of EAP methods to store for EAP server user information */
+#define EAP_MAX_METHODS 8
+
 #endif /* DEFS_H */
diff --git a/src/common/gas.c b/src/common/gas.c
new file mode 100644
index 0000000..babdaa3
--- /dev/null
+++ b/src/common/gas.c
@@ -0,0 +1,279 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "ieee802_11_defs.h"
+#include "gas.h"
+
+
+static struct wpabuf *
+gas_build_req(u8 action, u8 dialog_token, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(100 + size);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+	wpabuf_put_u8(buf, action);
+	wpabuf_put_u8(buf, dialog_token);
+
+	return buf;
+}
+
+
+static struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
+{
+	return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
+			     size);
+}
+
+
+struct wpabuf * gas_build_comeback_req(u8 dialog_token)
+{
+	return gas_build_req(WLAN_PA_GAS_COMEBACK_REQ, dialog_token, 0);
+}
+
+
+static struct wpabuf *
+gas_build_resp(u8 action, u8 dialog_token, u16 status_code, u8 frag_id,
+	       u8 more, u16 comeback_delay, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(100 + size);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+	wpabuf_put_u8(buf, action);
+	wpabuf_put_u8(buf, dialog_token);
+	wpabuf_put_le16(buf, status_code);
+	if (action == WLAN_PA_GAS_COMEBACK_RESP)
+		wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
+	wpabuf_put_le16(buf, comeback_delay);
+
+	return buf;
+}
+
+
+struct wpabuf *
+gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
+		       size_t size)
+{
+	return gas_build_resp(WLAN_PA_GAS_INITIAL_RESP, dialog_token,
+			      status_code, 0, 0, comeback_delay, size);
+}
+
+
+static struct wpabuf *
+gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
+			u16 comeback_delay, size_t size)
+{
+	return gas_build_resp(WLAN_PA_GAS_COMEBACK_RESP, dialog_token,
+			      status_code, frag_id, more, comeback_delay,
+			      size);
+}
+
+
+/**
+ * gas_add_adv_proto_anqp - Add an Advertisement Protocol element
+ * @buf: Buffer to which the element is added
+ * @query_resp_len_limit: Query Response Length Limit in units of 256 octets
+ * @pame_bi: Pre-Association Message Exchange BSSID Independent (0/1)
+ *
+ *
+ * @query_resp_len_limit is 0 for request and 1-0x7f for response. 0x7f means
+ * that the maximum limit is determined by the maximum allowable number of
+ * fragments in the GAS Query Response Fragment ID.
+ */
+static void gas_add_adv_proto_anqp(struct wpabuf *buf, u8 query_resp_len_limit,
+				   u8 pame_bi)
+{
+	/* Advertisement Protocol IE */
+	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+	wpabuf_put_u8(buf, 2); /* Length */
+	wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
+		      (pame_bi ? 0x80 : 0));
+	/* Advertisement Protocol */
+	wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
+}
+
+
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = gas_build_initial_req(dialog_token, 4 + size);
+	if (buf == NULL)
+		return NULL;
+
+	gas_add_adv_proto_anqp(buf, 0, 0);
+
+	wpabuf_put(buf, 2); /* Query Request Length to be filled */
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+					    u16 comeback_delay, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay,
+				     4 + size);
+	if (buf == NULL)
+		return NULL;
+
+	gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+	wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+						u16 status_code,
+						u16 comeback_delay,
+						struct wpabuf *payload)
+{
+	struct wpabuf *buf;
+
+	buf = gas_anqp_build_initial_resp(dialog_token, status_code,
+					  comeback_delay,
+					  payload ? wpabuf_len(payload) : 0);
+	if (buf == NULL)
+		return NULL;
+
+	if (payload)
+		wpabuf_put_buf(buf, payload);
+
+	gas_anqp_set_len(buf);
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+					     u8 frag_id, u8 more,
+					     u16 comeback_delay, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = gas_build_comeback_resp(dialog_token, status_code,
+				      frag_id, more, comeback_delay, 4 + size);
+	if (buf == NULL)
+		return NULL;
+
+	gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+	wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+						 u16 status_code,
+						 u8 frag_id, u8 more,
+						 u16 comeback_delay,
+						 struct wpabuf *payload)
+{
+	struct wpabuf *buf;
+
+	buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
+					   more, comeback_delay,
+					   payload ? wpabuf_len(payload) : 0);
+	if (buf == NULL)
+		return NULL;
+
+	if (payload)
+		wpabuf_put_buf(buf, payload);
+
+	gas_anqp_set_len(buf);
+
+	return buf;
+}
+
+
+/**
+ * gas_anqp_set_len - Set Query Request/Response Length
+ * @buf: GAS message
+ *
+ * This function is used to update the Query Request/Response Length field once
+ * the payload has been filled.
+ */
+void gas_anqp_set_len(struct wpabuf *buf)
+{
+	u8 action;
+	size_t offset;
+	u8 *len;
+
+	if (buf == NULL || wpabuf_len(buf) < 2)
+		return;
+
+	action = *(wpabuf_head_u8(buf) + 1);
+	switch (action) {
+	case WLAN_PA_GAS_INITIAL_REQ:
+		offset = 3 + 4;
+		break;
+	case WLAN_PA_GAS_INITIAL_RESP:
+		offset = 7 + 4;
+		break;
+	case WLAN_PA_GAS_COMEBACK_RESP:
+		offset = 8 + 4;
+		break;
+	default:
+		return;
+	}
+
+	if (wpabuf_len(buf) < offset + 2)
+		return;
+
+	len = wpabuf_mhead_u8(buf) + offset;
+	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+}
+
+
+/**
+ * gas_anqp_add_element - Add ANQP element header
+ * @buf: GAS message
+ * @info_id: ANQP Info ID
+ * Returns: Pointer to the Length field for gas_anqp_set_element_len()
+ */
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id)
+{
+	wpabuf_put_le16(buf, info_id);
+	return wpabuf_put(buf, 2); /* Length to be filled */
+}
+
+
+/**
+ * gas_anqp_set_element_len - Update ANQP element Length field
+ * @buf: GAS message
+ * @len_pos: Length field position from gas_anqp_add_element()
+ *
+ * This function is called after the ANQP element payload has been added to the
+ * buffer.
+ */
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos)
+{
+	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+}
diff --git a/src/common/gas.h b/src/common/gas.h
new file mode 100644
index 0000000..2f8d2cb
--- /dev/null
+++ b/src/common/gas.h
@@ -0,0 +1,42 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef GAS_H
+#define GAS_H
+
+struct wpabuf * gas_build_comeback_req(u8 dialog_token);
+struct wpabuf * gas_build_initial_resp(u8 dialog_token, u16 status_code,
+				       u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+					    u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+						u16 status_code,
+						u16 comeback_delay,
+						struct wpabuf *payload);
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+					     u8 frag_id, u8 more,
+					     u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+						 u16 status_code,
+						 u8 frag_id, u8 more,
+						 u16 comeback_delay,
+						 struct wpabuf *payload);
+void gas_anqp_set_len(struct wpabuf *buf);
+
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id);
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos);
+
+#endif /* GAS_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index ee41b3a..43cb2c6 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -259,6 +259,10 @@
 				break;
 			elems->link_id = pos;
 			break;
+		case WLAN_EID_INTERWORKING:
+			elems->interworking = pos;
+			elems->interworking_len = elen;
+			break;
 		default:
 			unknown++;
 			if (!show_errors)
@@ -345,3 +349,43 @@
 
 	return buf;
 }
+
+
+const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
+{
+	u16 fc, type, stype;
+
+	/*
+	 * PS-Poll frames are 16 bytes. All other frames are
+	 * 24 bytes or longer.
+	 */
+	if (len < 16)
+		return NULL;
+
+	fc = le_to_host16(hdr->frame_control);
+	type = WLAN_FC_GET_TYPE(fc);
+	stype = WLAN_FC_GET_STYPE(fc);
+
+	switch (type) {
+	case WLAN_FC_TYPE_DATA:
+		if (len < 24)
+			return NULL;
+		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
+		case WLAN_FC_FROMDS | WLAN_FC_TODS:
+		case WLAN_FC_TODS:
+			return hdr->addr1;
+		case WLAN_FC_FROMDS:
+			return hdr->addr2;
+		default:
+			return NULL;
+		}
+	case WLAN_FC_TYPE_CTRL:
+		if (stype != WLAN_FC_STYPE_PSPOLL)
+			return NULL;
+		return hdr->addr1;
+	case WLAN_FC_TYPE_MGMT:
+		return hdr->addr3;
+	default:
+		return NULL;
+	}
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 0c90fa4..60f0974 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -42,6 +42,7 @@
 	const u8 *vendor_ht_cap;
 	const u8 *p2p;
 	const u8 *link_id;
+	const u8 *interworking;
 
 	u8 ssid_len;
 	u8 supp_rates_len;
@@ -67,6 +68,7 @@
 	u8 ht_operation_len;
 	u8 vendor_ht_cap_len;
 	u8 p2p_len;
+	u8 interworking_len;
 };
 
 typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -77,5 +79,7 @@
 int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
 					    u32 oui_type);
+struct ieee80211_hdr;
+const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len);
 
 #endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 86868c0..66801fd 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -153,7 +153,17 @@
 #define WLAN_STATUS_INVALID_PMKID 53
 #define WLAN_STATUS_INVALID_MDIE 54
 #define WLAN_STATUS_INVALID_FTIE 55
+#define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59
+#define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60
+#define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61
+#define WLAN_STATUS_STA_TIMED_OUT_WAITING_FOR_GAS_RESP 62
+#define WLAN_STATUS_GAS_RESP_LARGER_THAN_LIMIT 63
+#define WLAN_STATUS_REQ_REFUSED_HOME 64
+#define WLAN_STATUS_ADV_SRV_UNREACHABLE 65
+#define WLAN_STATUS_REQ_REFUSED_SSPN 67
+#define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
 #define WLAN_STATUS_INVALID_RSNIE 72
+#define WLAN_STATUS_TRANSMISSION_FAILURE 79
 
 /* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
 #define WLAN_REASON_UNSPECIFIED 1
@@ -219,12 +229,16 @@
 #define WLAN_EID_RIC_DATA 57
 #define WLAN_EID_HT_OPERATION 61
 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
+#define WLAN_EID_TIME_ADVERTISEMENT 69
 #define WLAN_EID_20_40_BSS_COEXISTENCE 72
 #define WLAN_EID_20_40_BSS_INTOLERANT 73
 #define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
 #define WLAN_EID_MMIE 76
+#define WLAN_EID_TIME_ZONE 98
 #define WLAN_EID_LINK_ID 101
+#define WLAN_EID_INTERWORKING 107
 #define WLAN_EID_ADV_PROTO 108
+#define WLAN_EID_ROAMING_CONSORTIUM 111
 #define WLAN_EID_EXT_CAPAB 127
 #define WLAN_EID_VENDOR_SPECIFIC 221
 
@@ -239,6 +253,8 @@
 #define WLAN_ACTION_FT 6
 #define WLAN_ACTION_HT 7
 #define WLAN_ACTION_SA_QUERY 8
+#define WLAN_ACTION_WNM 10
+#define WLAN_ACTION_UNPROTECTED_WNM 11
 #define WLAN_ACTION_TDLS 12
 #define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
 #define WLAN_ACTION_VENDOR_SPECIFIC 127
@@ -249,6 +265,7 @@
 #define WLAN_PA_GAS_INITIAL_RESP 11
 #define WLAN_PA_GAS_COMEBACK_REQ 12
 #define WLAN_PA_GAS_COMEBACK_RESP 13
+#define WLAN_TDLS_DISCOVERY_RESPONSE 14
 
 /* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
 #define WLAN_SA_QUERY_REQUEST 0
@@ -274,33 +291,81 @@
 #define WLAN_TIMEOUT_KEY_LIFETIME 2
 #define WLAN_TIMEOUT_ASSOC_COMEBACK 3
 
-/* Advertisement Protocol ID definitions (IEEE 802.11u) */
+/* Interworking element (IEEE 802.11u) - Access Network Options */
+#define INTERWORKING_ANO_ACCESS_NETWORK_MASK 0x0f
+#define INTERWORKING_ANO_INTERNET 0x10
+#define INTERWORKING_ANO_ASRA 0x20
+#define INTERWORKING_ANO_ESR 0x40
+#define INTERWORKING_ANO_UESA 0x80
+
+#define INTERWORKING_ANT_PRIVATE 0
+#define INTERWORKING_ANT_PRIVATE_WITH_GUEST 1
+#define INTERWORKING_ANT_CHARGEABLE_PUBLIC 2
+#define INTERWORKING_ANT_FREE_PUBLIC 3
+#define INTERWORKING_ANT_PERSONAL_DEVICE 4
+#define INTERWORKING_ANT_EMERGENCY_SERVICES 5
+#define INTERWORKING_ANT_TEST 6
+#define INTERWORKING_ANT_WILDCARD 15
+
+/* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */
 enum adv_proto_id {
-	NATIVE_QUERY_PROTOCOL = 0,
+	ACCESS_NETWORK_QUERY_PROTOCOL = 0,
 	MIH_INFO_SERVICE = 1,
 	MIH_CMD_AND_EVENT_DISCOVERY = 2,
 	EMERGENCY_ALERT_SYSTEM = 3,
-	LOCATION_TO_SERVICE = 4,
 	ADV_PROTO_VENDOR_SPECIFIC = 221
 };
 
-/* Native Query Protocol info ID definitions (IEEE 802.11u) */
-enum nqp_info_id {
-	NQP_CAPABILITY_LIST = 256,
-	NQP_VENUE_NAME = 257,
-	NQP_EMERGENCY_CALL_NUMBER = 258,
-	NQP_NETWORK_AUTH_TYPE = 259,
-	NQP_ROAMING_CONSORTIUM = 260,
-	NQP_IP_ADDR_TYPE_AVAILABILITY = 261,
-	NQP_NAI_REALM = 262,
-	NQP_3GPP_CELLULAR_NETWORK = 263,
-	NQP_AP_GEOSPATIAL_LOCATION = 264,
-	NQP_AP_CIVIC_LOCATION = 265,
-	NQP_DOMAIN_NAME = 266,
-	NQP_EMERGENCY_ALERT_URI = 267,
-	NQP_VENDOR_SPECIFIC = 56797
+/* Access Network Query Protocol info ID definitions (IEEE Std 802.11u-2011) */
+enum anqp_info_id {
+	ANQP_QUERY_LIST = 256,
+	ANQP_CAPABILITY_LIST = 257,
+	ANQP_VENUE_NAME = 258,
+	ANQP_EMERGENCY_CALL_NUMBER = 259,
+	ANQP_NETWORK_AUTH_TYPE = 260,
+	ANQP_ROAMING_CONSORTIUM = 261,
+	ANQP_IP_ADDR_TYPE_AVAILABILITY = 262,
+	ANQP_NAI_REALM = 263,
+	ANQP_3GPP_CELLULAR_NETWORK = 264,
+	ANQP_AP_GEOSPATIAL_LOCATION = 265,
+	ANQP_AP_CIVIC_LOCATION = 266,
+	ANQP_AP_LOCATION_PUBLIC_URI = 267,
+	ANQP_DOMAIN_NAME = 268,
+	ANQP_EMERGENCY_ALERT_URI = 269,
+	ANQP_EMERGENCY_NAI = 271,
+	ANQP_VENDOR_SPECIFIC = 56797
 };
 
+/* NAI Realm list - EAP Method subfield - Authentication Parameter ID */
+enum nai_realm_eap_auth_param {
+	NAI_REALM_EAP_AUTH_EXPANDED_EAP_METHOD = 1,
+	NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH = 2,
+	NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD = 3,
+	NAI_REALM_EAP_AUTH_EXPANDED_INNER_EAP_METHOD = 4,
+	NAI_REALM_EAP_AUTH_CRED_TYPE = 5,
+	NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE = 6,
+	NAI_REALM_EAP_AUTH_VENDOR_SPECIFIC = 221
+};
+
+enum nai_realm_eap_auth_inner_non_eap {
+	NAI_REALM_INNER_NON_EAP_PAP = 1,
+	NAI_REALM_INNER_NON_EAP_CHAP = 2,
+	NAI_REALM_INNER_NON_EAP_MSCHAP = 3,
+	NAI_REALM_INNER_NON_EAP_MSCHAPV2 = 4
+};
+
+enum nai_realm_eap_cred_type {
+	NAI_REALM_CRED_TYPE_SIM = 1,
+	NAI_REALM_CRED_TYPE_USIM = 2,
+	NAI_REALM_CRED_TYPE_NFC_SECURE_ELEMENT = 3,
+	NAI_REALM_CRED_TYPE_HARDWARE_TOKEN = 4,
+	NAI_REALM_CRED_TYPE_SOFTOKEN = 5,
+	NAI_REALM_CRED_TYPE_CERTIFICATE = 6,
+	NAI_REALM_CRED_TYPE_USERNAME_PASSWORD = 7,
+	NAI_REALM_CRED_TYPE_NONE = 8,
+	NAI_REALM_CRED_TYPE_ANONYMOUS = 9,
+	NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
+};
 
 #ifdef _MSC_VER
 #pragma pack(push, 1)
@@ -436,6 +501,18 @@
 					/* Vendor-specific content */
 					u8 variable[0];
 				} STRUCT_PACKED vs_public_action;
+				struct {
+					u8 action; /* 7 */
+					u8 dialog_token;
+					u8 req_mode;
+					le16 disassoc_timer;
+					u8 validity_interval;
+					/* BSS Termination Duration (optional),
+					 * Session Information URL (optional),
+					 * BSS Transition Candidate List
+					 * Entries */
+					u8 variable[0];
+				} STRUCT_PACKED bss_tm_req;
 			} u;
 		} STRUCT_PACKED action;
 	} u;
@@ -541,7 +618,7 @@
 #define OP_MODE_MIXED                   3
 
 #define HT_INFO_OPERATION_MODE_OP_MODE_MASK	\
-		((le16) (0x0001 | 0x0002))
+		(0x0001 | 0x0002)
 #define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET		0
 #define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT	((u8) BIT(2))
 #define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT	((u8) BIT(3))
@@ -600,6 +677,10 @@
 
 } STRUCT_PACKED;
 
+#define WMM_QOSINFO_STA_AC_MASK 0x0f
+#define WMM_QOSINFO_STA_SP_MASK 0x03
+#define WMM_QOSINFO_STA_SP_SHIFT 5
+
 #define WMM_AC_AIFSN_MASK 0x0f
 #define WMM_AC_AIFNS_SHIFT 0
 #define WMM_AC_ACM 0x10
@@ -628,7 +709,7 @@
 	u8 oui_type; /* 2 */
 	u8 oui_subtype; /* 1 */
 	u8 version; /* 1 for WMM version 1.0 */
-	u8 qos_info; /* AP/STA specif QoS info */
+	u8 qos_info; /* AP/STA specific QoS info */
 	u8 reserved; /* 0 */
 	struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
 
@@ -797,4 +878,44 @@
 #define WLAN_AKM_SUITE_8021X		0x000FAC01
 #define WLAN_AKM_SUITE_PSK		0x000FAC02
 
+
+/* IEEE 802.11v - WNM Action field values */
+enum wnm_action {
+	WNM_EVENT_REQ = 0,
+	WNM_EVENT_REPORT = 1,
+	WNM_DIAGNOSTIC_REQ = 2,
+	WNM_DIAGNOSTIC_REPORT = 3,
+	WNM_LOCATION_CFG_REQ = 4,
+	WNM_LOCATION_CFG_RESP = 5,
+	WNM_BSS_TRANS_MGMT_QUERY = 6,
+	WNM_BSS_TRANS_MGMT_REQ = 7,
+	WNM_BSS_TRANS_MGMT_RESP = 8,
+	WNM_FMS_REQ = 9,
+	WNM_FMS_RESP = 10,
+	WNM_COLLOCATED_INTERFERENCE_REQ = 11,
+	WNM_COLLOCATED_INTERFERENCE_REPORT = 12,
+	WNM_TFS_REQ = 13,
+	WNM_TFS_RESP = 14,
+	WNM_TFS_NOTIFY = 15,
+	WNM_SLEEP_MODE_REQ = 16,
+	WNM_SLEEP_MODE_RESP = 17,
+	WNM_TIM_BROADCAST_REQ = 18,
+	WNM_TIM_BROADCAST_RESP = 19,
+	WNM_QOS_TRAFFIC_CAPAB_UPDATE = 20,
+	WNM_CHANNEL_USAGE_REQ = 21,
+	WNM_CHANNEL_USAGE_RESP = 22,
+	WNM_DMS_REQ = 23,
+	WNM_DMS_RESP = 24,
+	WNM_TIMING_MEASUREMENT_REQ = 25,
+	WNM_NOTIFICATION_REQ = 26,
+	WNM_NOTIFICATION_RESP = 27
+};
+
+/* IEEE 802.11v - BSS Transition Management Request - Request Mode */
+#define WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED BIT(0)
+#define WNM_BSS_TM_REQ_ABRIDGED BIT(1)
+#define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2)
+#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
+#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
+
 #endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/version.h b/src/common/version.h
index ba2d2c0..7afba48 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -5,6 +5,6 @@
 #define VERSION_STR_POSTFIX ""
 #endif /* VERSION_STR_POSTFIX */
 
-#define VERSION_STR "0.8.x" VERSION_STR_POSTFIX
+#define VERSION_STR "2.0-devel" VERSION_STR_POSTFIX
 
 #endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index eb2745e..24a61e4 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -188,6 +188,154 @@
 
 	return 0;
 }
+
+
+static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
+			     struct wpa_ft_ies *parse)
+{
+	const u8 *end, *pos;
+
+	parse->ftie = ie;
+	parse->ftie_len = ie_len;
+
+	pos = ie + sizeof(struct rsn_ftie);
+	end = ie + ie_len;
+
+	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+		switch (pos[0]) {
+		case FTIE_SUBELEM_R1KH_ID:
+			if (pos[1] != FT_R1KH_ID_LEN) {
+				wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
+					   "length in FTIE: %d", pos[1]);
+				return -1;
+			}
+			parse->r1kh_id = pos + 2;
+			break;
+		case FTIE_SUBELEM_GTK:
+			parse->gtk = pos + 2;
+			parse->gtk_len = pos[1];
+			break;
+		case FTIE_SUBELEM_R0KH_ID:
+			if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
+				wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
+					   "length in FTIE: %d", pos[1]);
+				return -1;
+			}
+			parse->r0kh_id = pos + 2;
+			parse->r0kh_id_len = pos[1];
+			break;
+#ifdef CONFIG_IEEE80211W
+		case FTIE_SUBELEM_IGTK:
+			parse->igtk = pos + 2;
+			parse->igtk_len = pos[1];
+			break;
+#endif /* CONFIG_IEEE80211W */
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	return 0;
+}
+
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
+		     struct wpa_ft_ies *parse)
+{
+	const u8 *end, *pos;
+	struct wpa_ie_data data;
+	int ret;
+	const struct rsn_ftie *ftie;
+	int prot_ie_count = 0;
+
+	os_memset(parse, 0, sizeof(*parse));
+	if (ies == NULL)
+		return 0;
+
+	pos = ies;
+	end = ies + ies_len;
+	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+		switch (pos[0]) {
+		case WLAN_EID_RSN:
+			parse->rsn = pos + 2;
+			parse->rsn_len = pos[1];
+			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
+						   parse->rsn_len + 2,
+						   &data);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
+					   "RSN IE: %d", ret);
+				return -1;
+			}
+			if (data.num_pmkid == 1 && data.pmkid)
+				parse->rsn_pmkid = data.pmkid;
+			break;
+		case WLAN_EID_MOBILITY_DOMAIN:
+			parse->mdie = pos + 2;
+			parse->mdie_len = pos[1];
+			break;
+		case WLAN_EID_FAST_BSS_TRANSITION:
+			if (pos[1] < sizeof(*ftie))
+				return -1;
+			ftie = (const struct rsn_ftie *) (pos + 2);
+			prot_ie_count = ftie->mic_control[1];
+			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
+				return -1;
+			break;
+		case WLAN_EID_TIMEOUT_INTERVAL:
+			parse->tie = pos + 2;
+			parse->tie_len = pos[1];
+			break;
+		case WLAN_EID_RIC_DATA:
+			if (parse->ric == NULL)
+				parse->ric = pos;
+			break;
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	if (prot_ie_count == 0)
+		return 0; /* no MIC */
+
+	/*
+	 * Check that the protected IE count matches with IEs included in the
+	 * frame.
+	 */
+	if (parse->rsn)
+		prot_ie_count--;
+	if (parse->mdie)
+		prot_ie_count--;
+	if (parse->ftie)
+		prot_ie_count--;
+	if (prot_ie_count < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
+			   "the protected IE count");
+		return -1;
+	}
+
+	if (prot_ie_count == 0 && parse->ric) {
+		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
+			   "included in protected IE count");
+		return -1;
+	}
+
+	/* Determine the end of the RIC IE(s) */
+	pos = parse->ric;
+	while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
+	       prot_ie_count) {
+		prot_ie_count--;
+		pos += 2 + pos[1];
+	}
+	parse->ric_len = pos - parse->ric;
+	if (prot_ie_count) {
+		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
+			   "frame", (int) prot_ie_count);
+		return -1;
+	}
+
+	return 0;
+}
 #endif /* CONFIG_IEEE80211R */
 
 
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index fe79cee..69437a7 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -358,4 +358,27 @@
 		       const u8 *ie2, size_t ie2len);
 int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid);
 
+struct wpa_ft_ies {
+	const u8 *mdie;
+	size_t mdie_len;
+	const u8 *ftie;
+	size_t ftie_len;
+	const u8 *r1kh_id;
+	const u8 *gtk;
+	size_t gtk_len;
+	const u8 *r0kh_id;
+	size_t r0kh_id_len;
+	const u8 *rsn;
+	size_t rsn_len;
+	const u8 *rsn_pmkid;
+	const u8 *tie;
+	size_t tie_len;
+	const u8 *igtk;
+	size_t igtk_len;
+	const u8 *ric;
+	size_t ric_len;
+};
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
+
 #endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index 88d3a02..3b25f77 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -21,6 +21,7 @@
 #endif /* CONFIG_CTRL_IFACE_UNIX */
 
 #ifdef ANDROID
+#include <dirent.h>
 #include <cutils/sockets.h>
 #include "private/android_filesystem_config.h"
 #endif /* ANDROID */
@@ -175,6 +176,56 @@
 	os_free(ctrl);
 }
 
+
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void)
+{
+	DIR *dir;
+	struct dirent entry;
+	struct dirent *result;
+	size_t dirnamelen;
+	int prefixlen = os_strlen(CONFIG_CTRL_IFACE_CLIENT_PREFIX);
+	size_t maxcopy;
+	char pathname[PATH_MAX];
+	char *namep;
+
+	if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
+		return;
+
+	dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
+					  CONFIG_CTRL_IFACE_CLIENT_DIR);
+	if (dirnamelen >= sizeof(pathname)) {
+		closedir(dir);
+		return;
+	}
+	namep = pathname + dirnamelen;
+	maxcopy = PATH_MAX - dirnamelen;
+	while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
+		if (os_strncmp(entry.d_name, CONFIG_CTRL_IFACE_CLIENT_PREFIX,
+			       prefixlen) == 0) {
+			if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
+				unlink(pathname);
+		}
+	}
+	closedir(dir);
+}
+#endif /* ANDROID */
+
+#else /* CONFIG_CTRL_IFACE_UNIX */
+
+#ifdef ANDROID
+void wpa_ctrl_cleanup(void)
+{
+}
+#endif /* ANDROID */
+
 #endif /* CONFIG_CTRL_IFACE_UNIX */
 
 
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
old mode 100644
new mode 100755
index 35e5e3d..d13ba02
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -100,10 +100,8 @@
 /** P2P device found */
 #define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
 
-#ifdef ANDROID_BRCM_P2P_PATCH
 /** P2P device lost */
 #define P2P_EVENT_DEVICE_LOST "P2P-DEVICE-LOST "
-#endif
 
 /** A P2P device requested GO negotiation, but we were not ready to start the
  * negotiation */
@@ -130,6 +128,10 @@
 #define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP "
 #define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
 #define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
+#define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
+
+#define INTERWORKING_AP "INTERWORKING-AP "
+#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
 
 /* hostapd control interface - fixed message prefixes */
 #define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
@@ -267,6 +269,17 @@
  */
 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
 
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void);
+#endif /* ANDROID */
+
 #ifdef CONFIG_CTRL_IFACE_UDP
 #define WPA_CTRL_IFACE_PORT 9877
 #define WPA_GLOBAL_CTRL_IFACE_PORT 9878
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index 69aa16a..b221dd4 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -12,6 +12,7 @@
 CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
 CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
 #CFLAGS += -DALL_DH_GROUPS
+CFLAGS += -DCONFIG_SHA256
 
 LIB_OBJS= \
 	aes-cbc.o \
@@ -40,6 +41,7 @@
 	sha1-tlsprf.o \
 	sha1-tprf.o \
 	sha256.o \
+	sha256-tlsprf.o \
 	sha256-internal.o
 
 LIB_OBJS += crypto_internal.o
@@ -48,6 +50,7 @@
 LIB_OBJS += crypto_internal-rsa.o
 LIB_OBJS += tls_internal.o
 LIB_OBJS += fips_prf_internal.o
+LIB_OBJS += random.o
 
 
 libcrypto.a: $(LIB_OBJS)
diff --git a/src/crypto/aes-internal-dec.c b/src/crypto/aes-internal-dec.c
index 2d32c03..a0fc45b 100644
--- a/src/crypto/aes-internal-dec.c
+++ b/src/crypto/aes-internal-dec.c
@@ -32,7 +32,7 @@
  *
  * @return	the number of rounds for the given cipher key size.
  */
-void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
+static void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
 {
 	int Nr = 10, i, j;
 	u32 temp;
diff --git a/src/crypto/aes-internal-enc.c b/src/crypto/aes-internal-enc.c
index 2f19826..8726aa7 100644
--- a/src/crypto/aes-internal-enc.c
+++ b/src/crypto/aes-internal-enc.c
@@ -27,7 +27,7 @@
 #include "crypto.h"
 #include "aes_i.h"
 
-void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
+static void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
 {
 	u32 s0, s1, s2, s3, t0, t1, t2, t3;
 	const int Nr = 10;
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 587b5a9..6dca191 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -155,7 +155,8 @@
 
 enum crypto_hash_alg {
 	CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
-	CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1
+	CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,
+	CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256
 };
 
 struct crypto_hash;
diff --git a/src/crypto/crypto_internal-rsa.c b/src/crypto/crypto_internal-rsa.c
index 205042c..7f0a5cf 100644
--- a/src/crypto/crypto_internal-rsa.c
+++ b/src/crypto/crypto_internal-rsa.c
@@ -17,7 +17,6 @@
 #include "common.h"
 #include "crypto.h"
 #include "tls/rsa.h"
-#include "tls/bignum.h"
 #include "tls/pkcs1.h"
 #include "tls/pkcs8.h"
 
diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c
index 8fdba65..9362fe1 100644
--- a/src/crypto/crypto_internal.c
+++ b/src/crypto/crypto_internal.c
@@ -1,6 +1,6 @@
 /*
  * Crypto wrapper for internal crypto implementation
- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -16,6 +16,7 @@
 
 #include "common.h"
 #include "crypto.h"
+#include "sha256_i.h"
 #include "sha1_i.h"
 #include "md5_i.h"
 
@@ -24,6 +25,9 @@
 	union {
 		struct MD5Context md5;
 		struct SHA1Context sha1;
+#ifdef CONFIG_SHA256
+		struct sha256_state sha256;
+#endif /* CONFIG_SHA256 */
 	} u;
 	u8 key[64];
 	size_t key_len;
@@ -35,7 +39,7 @@
 {
 	struct crypto_hash *ctx;
 	u8 k_pad[64];
-	u8 tk[20];
+	u8 tk[32];
 	size_t i;
 
 	ctx = os_zalloc(sizeof(*ctx));
@@ -51,6 +55,11 @@
 	case CRYPTO_HASH_ALG_SHA1:
 		SHA1Init(&ctx->u.sha1);
 		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_SHA256:
+		sha256_init(&ctx->u.sha256);
+		break;
+#endif /* CONFIG_SHA256 */
 	case CRYPTO_HASH_ALG_HMAC_MD5:
 		if (key_len > sizeof(k_pad)) {
 			MD5Init(&ctx->u.md5);
@@ -63,7 +72,8 @@
 		ctx->key_len = key_len;
 
 		os_memcpy(k_pad, key, key_len);
-		os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+		if (key_len < sizeof(k_pad))
+			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
 		for (i = 0; i < sizeof(k_pad); i++)
 			k_pad[i] ^= 0x36;
 		MD5Init(&ctx->u.md5);
@@ -81,12 +91,34 @@
 		ctx->key_len = key_len;
 
 		os_memcpy(k_pad, key, key_len);
-		os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+		if (key_len < sizeof(k_pad))
+			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
 		for (i = 0; i < sizeof(k_pad); i++)
 			k_pad[i] ^= 0x36;
 		SHA1Init(&ctx->u.sha1);
 		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
 		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		if (key_len > sizeof(k_pad)) {
+			sha256_init(&ctx->u.sha256);
+			sha256_process(&ctx->u.sha256, key, key_len);
+			sha256_done(&ctx->u.sha256, tk);
+			key = tk;
+			key_len = 32;
+		}
+		os_memcpy(ctx->key, key, key_len);
+		ctx->key_len = key_len;
+
+		os_memcpy(k_pad, key, key_len);
+		if (key_len < sizeof(k_pad))
+			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x36;
+		sha256_init(&ctx->u.sha256);
+		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
+		break;
+#endif /* CONFIG_SHA256 */
 	default:
 		os_free(ctx);
 		return NULL;
@@ -110,6 +142,14 @@
 	case CRYPTO_HASH_ALG_HMAC_SHA1:
 		SHA1Update(&ctx->u.sha1, data, len);
 		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_SHA256:
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		sha256_process(&ctx->u.sha256, data, len);
+		break;
+#endif /* CONFIG_SHA256 */
+	default:
+		break;
 	}
 }
 
@@ -146,6 +186,17 @@
 		*len = 20;
 		SHA1Final(mac, &ctx->u.sha1);
 		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_SHA256:
+		if (*len < 32) {
+			*len = 32;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 32;
+		sha256_done(&ctx->u.sha256, mac);
+		break;
+#endif /* CONFIG_SHA256 */
 	case CRYPTO_HASH_ALG_HMAC_MD5:
 		if (*len < 16) {
 			*len = 16;
@@ -186,6 +237,31 @@
 		SHA1Update(&ctx->u.sha1, mac, 20);
 		SHA1Final(mac, &ctx->u.sha1);
 		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		if (*len < 32) {
+			*len = 32;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 32;
+
+		sha256_done(&ctx->u.sha256, mac);
+
+		os_memcpy(k_pad, ctx->key, ctx->key_len);
+		os_memset(k_pad + ctx->key_len, 0,
+			  sizeof(k_pad) - ctx->key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x5c;
+		sha256_init(&ctx->u.sha256);
+		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
+		sha256_process(&ctx->u.sha256, mac, 32);
+		sha256_done(&ctx->u.sha256, mac);
+		break;
+#endif /* CONFIG_SHA256 */
+	default:
+		os_free(ctx);
+		return -1;
 	}
 
 	os_free(ctx);
diff --git a/src/crypto/dh_group5.c b/src/crypto/dh_group5.c
index 8c475bf..2a67d99 100644
--- a/src/crypto/dh_group5.c
+++ b/src/crypto/dh_group5.c
@@ -22,7 +22,7 @@
 void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
 {
 	*publ = dh_init(dh_groups_get(5), priv);
-	if (*publ == 0)
+	if (*publ == NULL)
 		return NULL;
 	return (void *) 1;
 }
diff --git a/src/crypto/fips_prf_internal.c b/src/crypto/fips_prf_internal.c
index a85cb14..1e0c453 100644
--- a/src/crypto/fips_prf_internal.c
+++ b/src/crypto/fips_prf_internal.c
@@ -28,13 +28,14 @@
 	u8 *xpos = x;
 	u32 carry;
 
-	if (seed_len > sizeof(xkey))
+	if (seed_len < sizeof(xkey))
+		os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+	else
 		seed_len = sizeof(xkey);
 
 	/* FIPS 186-2 + change notice 1 */
 
 	os_memcpy(xkey, seed, seed_len);
-	os_memset(xkey + seed_len, 0, 64 - seed_len);
 	t[0] = 0x67452301;
 	t[1] = 0xEFCDAB89;
 	t[2] = 0x98BADCFE;
diff --git a/src/crypto/md5-internal.c b/src/crypto/md5-internal.c
index f8692a9..137ad91 100644
--- a/src/crypto/md5-internal.c
+++ b/src/crypto/md5-internal.c
@@ -188,7 +188,7 @@
     MD5Transform(ctx->buf, (u32 *) ctx->in);
     byteReverse((unsigned char *) ctx->buf, 4);
     os_memcpy(digest, ctx->buf, 16);
-    os_memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
+    os_memset(ctx, 0, sizeof(*ctx));	/* In case it's sensitive */
 }
 
 /* The four core functions - F1 is optimized somewhat */
diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c
index dae15ab..c439ae9 100644
--- a/src/crypto/ms_funcs.c
+++ b/src/crypto/ms_funcs.c
@@ -19,6 +19,60 @@
 #include "ms_funcs.h"
 #include "crypto.h"
 
+/**
+ * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
+ * @utf8_string: UTF-8 string (IN)
+ * @utf8_string_len: Length of utf8_string (IN)
+ * @ucs2_buffer: UCS-2 buffer (OUT)
+ * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
+ * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
+ * Returns: 0 on success, -1 on failure
+ */
+static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
+                        u8 *ucs2_buffer, size_t ucs2_buffer_size,
+                        size_t *ucs2_string_size)
+{
+	size_t i, j;
+
+	for (i = 0, j = 0; i < utf8_string_len; i++) {
+		u8 c = utf8_string[i];
+		if (j >= ucs2_buffer_size) {
+			/* input too long */
+			return -1;
+		}
+		if (c <= 0x7F) {
+			WPA_PUT_LE16(ucs2_buffer + j, c);
+			j += 2;
+		} else if (i == utf8_string_len - 1 ||
+			   j >= ucs2_buffer_size - 1) {
+			/* incomplete surrogate */
+			return -1;
+		} else {
+			u8 c2 = utf8_string[++i];
+			if ((c & 0xE0) == 0xC0) {
+				/* two-byte encoding */
+				WPA_PUT_LE16(ucs2_buffer + j,
+					     ((c & 0x1F) << 6) | (c2 & 0x3F));
+				j += 2;
+			} else if (i == utf8_string_len ||
+				   j >= ucs2_buffer_size - 1) {
+				/* incomplete surrogate */
+				return -1;
+			} else {
+				/* three-byte encoding */
+				u8 c3 = utf8_string[++i];
+				WPA_PUT_LE16(ucs2_buffer + j,
+					     ((c & 0xF) << 12) |
+					     ((c2 & 0x3F) << 6) | (c3 & 0x3F));
+			}
+		}
+	}
+
+	if (ucs2_string_size)
+		*ucs2_string_size = j / 2;
+	return 0;
+}
+
 
 /**
  * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
@@ -53,7 +107,7 @@
 
 /**
  * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @password_hash: 16-octet PasswordHash (OUT)
  * Returns: 0 on success, -1 on failure
@@ -62,18 +116,13 @@
 		      u8 *password_hash)
 {
 	u8 buf[512], *pos;
-	size_t i, len;
+	size_t len, max_len;
 
-	if (password_len > 256)
-		password_len = 256;
+	max_len = sizeof(buf);
+	if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
+		return -1;
 
-	/* Convert password into unicode */
-	for (i = 0; i < password_len; i++) {
-		buf[2 * i] = password[i];
-		buf[2 * i + 1] = 0;
-	}
-
-	len = password_len * 2;
+	len *= 2;
 	pos = buf;
 	return md4_vector(1, (const u8 **) &pos, &len, password_hash);
 }
@@ -117,7 +166,7 @@
  * @peer_challenge: 16-octet PeerChallenge (IN)
  * @username: 0-to-256-char UserName (IN)
  * @username_len: Length of username
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @response: 24-octet Response (OUT)
  * Returns: 0 on success, -1 on failure
@@ -225,7 +274,7 @@
 
 /**
  * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @nt_response: 24-octet NT-Response (IN)
  * @peer_challenge: 16-octet PeerChallenge (IN)
@@ -254,7 +303,7 @@
 /**
  * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
  * @challenge: 8-octet Challenge (IN)
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @response: 24-octet Response (OUT)
  * Returns: 0 on success, -1 on failure
@@ -375,7 +424,7 @@
 
 /**
  * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @password_hash: 16-octet PasswordHash (IN)
  * @pw_block: 516-byte PwBlock (OUT)
@@ -385,18 +434,23 @@
 	const u8 *password, size_t password_len,
 	const u8 *password_hash, u8 *pw_block)
 {
-	size_t i, offset;
+	size_t ucs2_len, offset;
 	u8 *pos;
 
-	if (password_len > 256)
+	os_memset(pw_block, 0, PWBLOCK_LEN);
+
+	if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
 		return -1;
 
-	os_memset(pw_block, 0, PWBLOCK_LEN);
-	offset = (256 - password_len) * 2;
-	if (os_get_random(pw_block, offset) < 0)
+	if (ucs2_len > 256)
 		return -1;
-	for (i = 0; i < password_len; i++)
-		pw_block[offset + i * 2] = password[i];
+
+	offset = (256 - ucs2_len) * 2;
+	if (offset != 0) {
+		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
+		if (os_get_random(pw_block, offset) < 0)
+			return -1;
+	}
 	/*
 	 * PasswordLength is 4 octets, but since the maximum password length is
 	 * 256, only first two (in little endian byte order) can be non-zero.
@@ -410,9 +464,9 @@
 
 /**
  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
- * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
  * @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
  * @old_password_len: Length of old_password
  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
  * Returns: 0 on success, -1 on failure
@@ -450,9 +504,9 @@
 
 /**
  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
- * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
  * @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
  * @old_password_len: Length of old_password
  * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
  * Returns: 0 on success, -1 on failure
diff --git a/src/crypto/random.c b/src/crypto/random.c
index f545917..a54e197 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -354,23 +354,31 @@
 	char buf[RANDOM_ENTROPY_SIZE];
 	FILE *f;
 	u8 opr;
+	int fail = 0;
 
 	if (!random_entropy_file)
 		return;
 
-	random_get_bytes(buf, RANDOM_ENTROPY_SIZE);
+	if (random_get_bytes(buf, RANDOM_ENTROPY_SIZE) < 0)
+		return;
 
 	f = fopen(random_entropy_file, "wb");
 	if (f == NULL) {
-		wpa_printf(MSG_ERROR, "random: Could not write %s",
-			   random_entropy_file);
+		wpa_printf(MSG_ERROR, "random: Could not open entropy file %s "
+			   "for writing", random_entropy_file);
 		return;
 	}
 
 	opr = own_pool_ready > 0xff ? 0xff : own_pool_ready;
-	fwrite(&opr, 1, 1, f);
-	fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f);
+	if (fwrite(&opr, 1, 1, f) != 1 ||
+	    fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f) != 1)
+		fail = 1;
 	fclose(f);
+	if (fail) {
+		wpa_printf(MSG_ERROR, "random: Could not write entropy data "
+			   "to %s", random_entropy_file);
+		return;
+	}
 
 	wpa_printf(MSG_DEBUG, "random: Updated entropy file %s "
 		   "(own_pool_ready=%u)",
diff --git a/src/crypto/sha1-pbkdf2.c b/src/crypto/sha1-pbkdf2.c
index 11323de..9dac977 100644
--- a/src/crypto/sha1-pbkdf2.c
+++ b/src/crypto/sha1-pbkdf2.c
@@ -16,8 +16,6 @@
 
 #include "common.h"
 #include "sha1.h"
-#include "md5.h"
-#include "crypto.h"
 
 static int pbkdf2_sha1_f(const char *passphrase, const char *ssid,
 			 size_t ssid_len, int iterations, unsigned int count,
diff --git a/src/crypto/sha1-tlsprf.c b/src/crypto/sha1-tlsprf.c
index 2c8c029..f98fd65 100644
--- a/src/crypto/sha1-tlsprf.c
+++ b/src/crypto/sha1-tlsprf.c
@@ -17,11 +17,10 @@
 #include "common.h"
 #include "sha1.h"
 #include "md5.h"
-#include "crypto.h"
 
 
 /**
- * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
+ * tls_prf_sha1_md5 - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
  * @secret: Key for PRF
  * @secret_len: Length of the key in bytes
  * @label: A unique label for each purpose of the PRF
@@ -34,8 +33,8 @@
  * This function is used to derive new, cryptographically separate keys from a
  * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
  */
-int tls_prf(const u8 *secret, size_t secret_len, const char *label,
-	    const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
+		     const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
 {
 	size_t L_S1, L_S2, i;
 	const u8 *S1, *S2;
diff --git a/src/crypto/sha1.h b/src/crypto/sha1.h
index c1a6233..f0c1a5f 100644
--- a/src/crypto/sha1.h
+++ b/src/crypto/sha1.h
@@ -25,9 +25,9 @@
 	     const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
 int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
 	       const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len);
-int __must_check tls_prf(const u8 *secret, size_t secret_len,
-			 const char *label, const u8 *seed, size_t seed_len,
-			 u8 *out, size_t outlen);
+int __must_check tls_prf_sha1_md5(const u8 *secret, size_t secret_len,
+				  const char *label, const u8 *seed,
+				  size_t seed_len, u8 *out, size_t outlen);
 int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
 		int iterations, u8 *buf, size_t buflen);
 #endif /* SHA1_H */
diff --git a/src/crypto/sha256-internal.c b/src/crypto/sha256-internal.c
index b061373..ef5751d 100644
--- a/src/crypto/sha256-internal.c
+++ b/src/crypto/sha256-internal.c
@@ -1,6 +1,6 @@
 /*
  * SHA-256 hash implementation and interface functions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -16,19 +16,9 @@
 
 #include "common.h"
 #include "sha256.h"
+#include "sha256_i.h"
 #include "crypto.h"
 
-struct sha256_state {
-	u64 length;
-	u32 state[8], curlen;
-	u8 buf[64];
-};
-
-static void sha256_init(struct sha256_state *md);
-static int sha256_process(struct sha256_state *md, const unsigned char *in,
-			  unsigned long inlen);
-static int sha256_done(struct sha256_state *md, unsigned char *out);
-
 
 /**
  * sha256_vector - SHA256 hash for data vector
@@ -137,7 +127,7 @@
 
 
 /* Initialize the hash state */
-static void sha256_init(struct sha256_state *md)
+void sha256_init(struct sha256_state *md)
 {
 	md->curlen = 0;
 	md->length = 0;
@@ -158,32 +148,31 @@
    @param inlen  The length of the data (octets)
    @return CRYPT_OK if successful
 */
-static int sha256_process(struct sha256_state *md, const unsigned char *in,
-			  unsigned long inlen)
+int sha256_process(struct sha256_state *md, const unsigned char *in,
+		   unsigned long inlen)
 {
 	unsigned long n;
-#define block_size 64
 
-	if (md->curlen > sizeof(md->buf))
+	if (md->curlen >= sizeof(md->buf))
 		return -1;
 
 	while (inlen > 0) {
-		if (md->curlen == 0 && inlen >= block_size) {
+		if (md->curlen == 0 && inlen >= SHA256_BLOCK_SIZE) {
 			if (sha256_compress(md, (unsigned char *) in) < 0)
 				return -1;
-			md->length += block_size * 8;
-			in += block_size;
-			inlen -= block_size;
+			md->length += SHA256_BLOCK_SIZE * 8;
+			in += SHA256_BLOCK_SIZE;
+			inlen -= SHA256_BLOCK_SIZE;
 		} else {
-			n = MIN(inlen, (block_size - md->curlen));
+			n = MIN(inlen, (SHA256_BLOCK_SIZE - md->curlen));
 			os_memcpy(md->buf + md->curlen, in, n);
 			md->curlen += n;
 			in += n;
 			inlen -= n;
-			if (md->curlen == block_size) {
+			if (md->curlen == SHA256_BLOCK_SIZE) {
 				if (sha256_compress(md, md->buf) < 0)
 					return -1;
-				md->length += 8 * block_size;
+				md->length += 8 * SHA256_BLOCK_SIZE;
 				md->curlen = 0;
 			}
 		}
@@ -199,7 +188,7 @@
    @param out [out] The destination of the hash (32 bytes)
    @return CRYPT_OK if successful
 */
-static int sha256_done(struct sha256_state *md, unsigned char *out)
+int sha256_done(struct sha256_state *md, unsigned char *out)
 {
 	int i;
 
@@ -217,14 +206,14 @@
 	 * encoding like normal.
 	 */
 	if (md->curlen > 56) {
-		while (md->curlen < 64) {
+		while (md->curlen < SHA256_BLOCK_SIZE) {
 			md->buf[md->curlen++] = (unsigned char) 0;
 		}
 		sha256_compress(md, md->buf);
 		md->curlen = 0;
 	}
 
-	/* pad upto 56 bytes of zeroes */
+	/* pad up to 56 bytes of zeroes */
 	while (md->curlen < 56) {
 		md->buf[md->curlen++] = (unsigned char) 0;
 	}
diff --git a/src/crypto/sha256-tlsprf.c b/src/crypto/sha256-tlsprf.c
new file mode 100644
index 0000000..6763c96
--- /dev/null
+++ b/src/crypto/sha256-tlsprf.c
@@ -0,0 +1,72 @@
+/*
+ * TLS PRF P_SHA256
+ * Copyright (c) 2011, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+
+
+/**
+ * tls_prf_sha256 - Pseudo-Random Function for TLS v1.2 (P_SHA256, RFC 5246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
+ */
+void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
+		    const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+	size_t clen;
+	u8 A[SHA256_MAC_LEN];
+	u8 P[SHA256_MAC_LEN];
+	size_t pos;
+	const unsigned char *addr[3];
+	size_t len[3];
+
+	addr[0] = A;
+	len[0] = SHA256_MAC_LEN;
+	addr[1] = (unsigned char *) label;
+	len[1] = os_strlen(label);
+	addr[2] = seed;
+	len[2] = seed_len;
+
+	/*
+	 * RFC 5246, Chapter 5
+	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+	 * PRF(secret, label, seed) = P_SHA256(secret, label + seed)
+	 */
+
+	hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A);
+
+	pos = 0;
+	while (pos < outlen) {
+		hmac_sha256_vector(secret, secret_len, 3, addr, len, P);
+		hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A);
+
+		clen = outlen - pos;
+		if (clen > SHA256_MAC_LEN)
+			clen = SHA256_MAC_LEN;
+		os_memcpy(out + pos, P, clen);
+		pos += clen;
+	}
+}
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index dc597f0..b1ce6af 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -1,6 +1,6 @@
 /*
  * SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -23,5 +23,8 @@
 		 size_t data_len, u8 *mac);
 void sha256_prf(const u8 *key, size_t key_len, const char *label,
 	      const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+void tls_prf_sha256(const u8 *secret, size_t secret_len,
+		    const char *label, const u8 *seed, size_t seed_len,
+		    u8 *out, size_t outlen);
 
 #endif /* SHA256_H */
diff --git a/src/crypto/sha256_i.h b/src/crypto/sha256_i.h
new file mode 100644
index 0000000..20ae488
--- /dev/null
+++ b/src/crypto/sha256_i.h
@@ -0,0 +1,31 @@
+/*
+ * SHA-256 internal definitions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef SHA256_I_H
+#define SHA256_I_H
+
+#define SHA256_BLOCK_SIZE 64
+
+struct sha256_state {
+	u64 length;
+	u32 state[8], curlen;
+	u8 buf[SHA256_BLOCK_SIZE];
+};
+
+void sha256_init(struct sha256_state *md);
+int sha256_process(struct sha256_state *md, const unsigned char *in,
+		   unsigned long inlen);
+int sha256_done(struct sha256_state *md, unsigned char *out);
+
+#endif /* SHA256_I_H */
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 0928b5b..d9d88cb 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -24,8 +24,6 @@
 	size_t client_random_len;
 	const u8 *server_random;
 	size_t server_random_len;
-	const u8 *inner_secret; /* TLS/IA inner secret */
-	size_t inner_secret_len;
 };
 
 enum tls_event {
@@ -72,6 +70,7 @@
 	const char *pkcs11_engine_path;
 	const char *pkcs11_module_path;
 	int fips_mode;
+	int cert_in_cb;
 
 	void (*event_cb)(void *ctx, enum tls_event ev,
 			 union tls_event_data *data);
@@ -114,7 +113,6 @@
  * specific for now)
  * @cert_id: the certificate's id when using engine
  * @ca_cert_id: the CA certificate's id when using engine
- * @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
  * @flags: Parameter options (TLS_CONN_*)
  *
  * TLS connection parameters to be configured with tls_connection_set_params()
@@ -142,7 +140,6 @@
 	const char *dh_file;
 	const u8 *dh_blob;
 	size_t dh_blob_len;
-	int tls_ia;
 
 	/* OpenSSL specific variables */
 	int engine;
@@ -282,20 +279,6 @@
 					   int verify_peer);
 
 /**
- * tls_connection_set_ia - Set TLS/IA parameters
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @tls_ia: 1 = enable TLS/IA
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to configure TLS/IA in server mode where
- * tls_connection_set_params() is not used.
- */
-int __must_check tls_connection_set_ia(void *tls_ctx,
-				       struct tls_connection *conn,
-				       int tls_ia);
-
-/**
  * tls_connection_get_keys - Get master key and random data from TLS connection
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
@@ -322,7 +305,7 @@
  * not exported from the TLS library, tls_connection_prf() is required so that
  * further keying material can be derived from the master secret. If not
  * implemented, the function will still need to be defined, but it can just
- * return -1. Example implementation of this function is in tls_prf() function
+ * return -1. Example implementation of this function is in tls_prf_sha1_md5()
  * when it is called with seed set to client_random|server_random (or
  * server_random|client_random).
  */
@@ -364,6 +347,12 @@
 					 const struct wpabuf *in_data,
 					 struct wpabuf **appl_data);
 
+struct wpabuf * tls_connection_handshake2(void *tls_ctx,
+					  struct tls_connection *conn,
+					  const struct wpabuf *in_data,
+					  struct wpabuf **appl_data,
+					  int *more_data_needed);
+
 /**
  * tls_connection_server_handshake - Process TLS handshake (server side)
  * @tls_ctx: TLS context data from tls_init()
@@ -409,6 +398,11 @@
 				       struct tls_connection *conn,
 				       const struct wpabuf *in_data);
 
+struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
+					struct tls_connection *conn,
+					const struct wpabuf *in_data,
+					int *more_data_needed);
+
 /**
  * tls_connection_resumed - Was session resumption used
  * @tls_ctx: TLS context data from tls_init()
@@ -514,7 +508,6 @@
 int tls_connection_get_keyblock_size(void *tls_ctx,
 				     struct tls_connection *conn);
 
-#define TLS_CAPABILITY_IA 0x0001 /* TLS Inner Application (TLS/IA) */
 /**
  * tls_capabilities - Get supported TLS capabilities
  * @tls_ctx: TLS context data from tls_init()
@@ -522,42 +515,6 @@
  */
 unsigned int tls_capabilities(void *tls_ctx);
 
-/**
- * tls_connection_ia_send_phase_finished - Send a TLS/IA PhaseFinished message
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @final: 1 = FinalPhaseFinished, 0 = IntermediatePhaseFinished
- * Returns: Encrypted TLS/IA data, %NULL on failure
- *
- * This function is used to send the TLS/IA end phase message, e.g., when the
- * EAP server completes EAP-TTLSv1.
- */
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final);
-
-/**
- * tls_connection_ia_final_phase_finished - Has final phase been completed
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * Returns: 1 if valid FinalPhaseFinished has been received, 0 if not, or -1
- * on failure
- */
-int __must_check tls_connection_ia_final_phase_finished(
-	void *tls_ctx, struct tls_connection *conn);
-
-/**
- * tls_connection_ia_permute_inner_secret - Permute TLS/IA inner secret
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @key: Session key material (session_key vectors with 2-octet length), or
- * %NULL if no session key was generating in the current phase
- * @key_len: Length of session key material
- * Returns: 0 on success, -1 on failure
- */
-int __must_check tls_connection_ia_permute_inner_secret(
-	void *tls_ctx, struct tls_connection *conn,
-	const u8 *key, size_t key_len);
-
 typedef int (*tls_session_ticket_cb)
 (void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
  const u8 *server_random, u8 *master_secret);
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index c3a7358..afa5268 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -1,6 +1,6 @@
 /*
  * SSL/TLS interface functions for GnuTLS
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -19,28 +19,12 @@
 #include <gnutls/pkcs12.h>
 #endif /* PKCS12_FUNCS */
 
-#ifdef CONFIG_GNUTLS_EXTRA
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
-#define GNUTLS_IA
-#include <gnutls/extra.h>
-#if LIBGNUTLS_VERSION_NUMBER == 0x010302
-/* This function is not included in the current gnutls/extra.h even though it
- * should be, so define it here as a workaround for the time being. */
-int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
-#endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
-#endif /* CONFIG_GNUTLS_EXTRA */
-
 #include "common.h"
 #include "tls.h"
 
 
-#ifndef TLS_RANDOM_SIZE
-#define TLS_RANDOM_SIZE 32
-#endif
-#ifndef TLS_MASTER_SIZE
-#define TLS_MASTER_SIZE 48
-#endif
+#define WPA_TLS_RANDOM_SIZE 32
+#define WPA_TLS_MASTER_SIZE 48
 
 
 #if LIBGNUTLS_VERSION_NUMBER < 0x010302
@@ -77,9 +61,9 @@
 	gnutls_mac_algorithm_t write_mac_algorithm;
 	gnutls_compression_method_t write_compression_algorithm;
 	cipher_suite_st current_cipher_suite;
-	opaque master_secret[TLS_MASTER_SIZE];
-	opaque client_random[TLS_RANDOM_SIZE];
-	opaque server_random[TLS_RANDOM_SIZE];
+	opaque master_secret[WPA_TLS_MASTER_SIZE];
+	opaque client_random[WPA_TLS_RANDOM_SIZE];
+	opaque server_random[WPA_TLS_RANDOM_SIZE];
 	/* followed by stuff we are not interested in */
 } security_parameters_st;
 
@@ -118,21 +102,6 @@
 
 	int params_set;
 	gnutls_certificate_credentials_t xcred;
-
-	int tls_ia;
-	int final_phase_finished;
-
-#ifdef GNUTLS_IA
-	gnutls_ia_server_credentials_t iacred_srv;
-	gnutls_ia_client_credentials_t iacred_cli;
-
-	/* Session keys generated in the current phase for inner secret
-	 * permutation before generating/verifying PhaseFinished. */
-	u8 *session_keys;
-	size_t session_keys_len;
-
-	u8 inner_secret[TLS_MASTER_SIZE];
-#endif /* GNUTLS_IA */
 };
 
 
@@ -285,8 +254,12 @@
 static int tls_gnutls_init_session(struct tls_global *global,
 				   struct tls_connection *conn)
 {
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
+	const char *err;
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
 	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
 	const int protos[2] = { GNUTLS_TLS1, 0 };
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
 	int ret;
 
 	ret = gnutls_init(&conn->session,
@@ -301,6 +274,15 @@
 	if (ret < 0)
 		goto fail;
 
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
+	ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
+					 &err);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
+			   "'%s'", err);
+		goto fail;
+	}
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
 	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
 	if (ret < 0)
 		goto fail;
@@ -308,6 +290,7 @@
 	ret = gnutls_protocol_set_priority(conn->session, protos);
 	if (ret < 0)
 		goto fail;
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
 
 	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
 	gnutls_transport_set_push_function(conn->session, tls_push_func);
@@ -364,17 +347,6 @@
 	if (conn == NULL)
 		return;
 
-#ifdef GNUTLS_IA
-	if (conn->iacred_srv)
-		gnutls_ia_free_server_credentials(conn->iacred_srv);
-	if (conn->iacred_cli)
-		gnutls_ia_free_client_credentials(conn->iacred_cli);
-	if (conn->session_keys) {
-		os_memset(conn->session_keys, 0, conn->session_keys_len);
-		os_free(conn->session_keys);
-	}
-#endif /* GNUTLS_IA */
-
 	gnutls_certificate_free_credentials(conn->xcred);
 	gnutls_deinit(conn->session);
 	os_free(conn->pre_shared_secret);
@@ -407,14 +379,6 @@
 	wpabuf_free(conn->push_buf);
 	conn->push_buf = NULL;
 	conn->established = 0;
-	conn->final_phase_finished = 0;
-#ifdef GNUTLS_IA
-	if (conn->session_keys) {
-		os_memset(conn->session_keys, 0, conn->session_keys_len);
-		os_free(conn->session_keys);
-	}
-	conn->session_keys_len = 0;
-#endif /* GNUTLS_IA */
 
 	gnutls_deinit(conn->session);
 	if (tls_gnutls_init_session(global, conn)) {
@@ -597,11 +561,13 @@
 				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
 		}
 
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
 		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
 			gnutls_certificate_set_verify_flags(
 				conn->xcred,
 				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
 		}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
 	}
 
 	if (params->client_cert && params->private_key) {
@@ -646,7 +612,6 @@
 		}
 	}
 
-	conn->tls_ia = params->tls_ia;
 	conn->params_set = 1;
 
 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
@@ -656,28 +621,6 @@
 			   gnutls_strerror(ret));
 	}
 
-#ifdef GNUTLS_IA
-	if (conn->iacred_cli)
-		gnutls_ia_free_client_credentials(conn->iacred_cli);
-
-	ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
-			   gnutls_strerror(ret));
-		return -1;
-	}
-
-	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
-				     conn->iacred_cli);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
-			   gnutls_strerror(ret));
-		gnutls_ia_free_client_credentials(conn->iacred_cli);
-		conn->iacred_cli = NULL;
-		return -1;
-	}
-#endif /* GNUTLS_IE */
-
 	return ret;
 }
 
@@ -729,11 +672,13 @@
 				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
 		}
 
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
 		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
 			gnutls_certificate_set_verify_flags(
 				global->xcred,
 				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
 		}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
 	}
 
 	if (params->client_cert && params->private_key) {
@@ -822,10 +767,11 @@
 
 	os_memset(keys, 0, sizeof(*keys));
 
+#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
 	sec = &conn->session->security_parameters;
 	keys->master_key = sec->master_secret;
-	keys->master_key_len = TLS_MASTER_SIZE;
+	keys->master_key_len = WPA_TLS_MASTER_SIZE;
 	keys->client_random = sec->client_random;
 	keys->server_random = sec->server_random;
 #else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
@@ -835,16 +781,12 @@
 		(u8 *) gnutls_session_get_server_random(conn->session);
 	/* No access to master_secret */
 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
 
-#ifdef GNUTLS_IA
-	gnutls_ia_extract_inner_secret(conn->session,
-				       (char *) conn->inner_secret);
-	keys->inner_secret = conn->inner_secret;
-	keys->inner_secret_len = TLS_MASTER_SIZE;
-#endif /* GNUTLS_IA */
-
-	keys->client_random_len = TLS_RANDOM_SIZE;
-	keys->server_random_len = TLS_RANDOM_SIZE;
+#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
+	keys->client_random_len = WPA_TLS_RANDOM_SIZE;
+	keys->server_random_len = WPA_TLS_RANDOM_SIZE;
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
 
 	return 0;
 }
@@ -883,11 +825,13 @@
 
 	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
 		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
+		*err = GNUTLS_A_INTERNAL_ERROR;
 		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
 			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
 				   "algorithm");
 			*err = GNUTLS_A_INSUFFICIENT_SECURITY;
 		}
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
 		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
 			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
 				   "activated");
@@ -897,6 +841,7 @@
 			wpa_printf(MSG_INFO, "TLS: Certificate expired");
 			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
 		}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
 		return -1;
 	}
 
@@ -988,7 +933,7 @@
 				 wpabuf_size(ad));
 	wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
 	if (res < 0) {
-		wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
+		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
 			   "(%s)", __func__, (int) res,
 			   gnutls_strerror(res));
 		wpabuf_free(ad);
@@ -1062,20 +1007,7 @@
 			goto out;
 		}
 
-#ifdef CONFIG_GNUTLS_EXTRA
-		if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
-			wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
-			conn->failed++;
-			return NULL;
-		}
-#endif /* CONFIG_GNUTLS_EXTRA */
-
-		if (conn->tls_ia)
-			wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
-		else {
-			wpa_printf(MSG_DEBUG, "TLS: Handshake completed "
-				   "successfully");
-		}
+		wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
 		conn->established = 1;
 		if (conn->push_buf == NULL) {
 			/* Need to return something to get final TLS ACK. */
@@ -1122,12 +1054,6 @@
 	ssize_t res;
 	struct wpabuf *buf;
 
-#ifdef GNUTLS_IA
-	if (conn->tls_ia)
-		res = gnutls_ia_send(conn->session, wpabuf_head(in_data),
-				     wpabuf_len(in_data));
-	else
-#endif /* GNUTLS_IA */
 	res = gnutls_record_send(conn->session, wpabuf_head(in_data),
 				 wpabuf_len(in_data));
 	if (res < 0) {
@@ -1170,65 +1096,6 @@
 	if (out == NULL)
 		return NULL;
 
-#ifdef GNUTLS_IA
-	if (conn->tls_ia) {
-		res = gnutls_ia_recv(conn->session, wpabuf_mhead(out),
-				     wpabuf_size(out));
-		if (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
-		    res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) {
-			int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
-			wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished",
-				   __func__, final ? "Final" : "Intermediate");
-
-			res = gnutls_ia_permute_inner_secret(
-				conn->session, conn->session_keys_len,
-				(char *) conn->session_keys);
-			if (conn->session_keys) {
-				os_memset(conn->session_keys, 0,
-					  conn->session_keys_len);
-				os_free(conn->session_keys);
-			}
-			conn->session_keys = NULL;
-			conn->session_keys_len = 0;
-			if (res) {
-				wpa_printf(MSG_DEBUG, "%s: Failed to permute "
-					   "inner secret: %s",
-					   __func__, gnutls_strerror(res));
-				wpabuf_free(out);
-				return NULL;
-			}
-
-			res = gnutls_ia_verify_endphase(conn->session,
-							wpabuf_head(out));
-			if (res == 0) {
-				wpa_printf(MSG_DEBUG, "%s: Correct endphase "
-					   "checksum", __func__);
-			} else {
-				wpa_printf(MSG_INFO, "%s: Endphase "
-					   "verification failed: %s",
-					   __func__, gnutls_strerror(res));
-				wpabuf_free(out);
-				return NULL;
-			}
-
-			if (final)
-				conn->final_phase_finished = 1;
-
-			return out;
-		}
-
-		if (res < 0) {
-			wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
-				   "(%s)", __func__, (int) res,
-				   gnutls_strerror(res));
-			wpabuf_free(out);
-			return NULL;
-		}
-		wpabuf_put(out, res);
-		return out;
-	}
-#endif /* GNUTLS_IA */
-
 	res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
 				 wpabuf_size(out));
 	if (res < 0) {
@@ -1319,133 +1186,7 @@
 
 unsigned int tls_capabilities(void *tls_ctx)
 {
-	unsigned int capa = 0;
-
-#ifdef GNUTLS_IA
-	capa |= TLS_CAPABILITY_IA;
-#endif /* GNUTLS_IA */
-
-	return capa;
-}
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-#ifdef GNUTLS_IA
-	int ret;
-
-	if (conn == NULL)
-		return -1;
-
-	conn->tls_ia = tls_ia;
-	if (!tls_ia)
-		return 0;
-
-	ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
-			   gnutls_strerror(ret));
-		return -1;
-	}
-
-	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
-				     conn->iacred_srv);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
-			   gnutls_strerror(ret));
-		gnutls_ia_free_server_credentials(conn->iacred_srv);
-		conn->iacred_srv = NULL;
-		return -1;
-	}
-
 	return 0;
-#else /* GNUTLS_IA */
-	return -1;
-#endif /* GNUTLS_IA */
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-#ifdef GNUTLS_IA
-	int ret;
-	struct wpabuf *buf;
-
-	if (conn == NULL || conn->session == NULL || !conn->tls_ia)
-		return NULL;
-
-	ret = gnutls_ia_permute_inner_secret(conn->session,
-					     conn->session_keys_len,
-					     (char *) conn->session_keys);
-	if (conn->session_keys) {
-		os_memset(conn->session_keys, 0, conn->session_keys_len);
-		os_free(conn->session_keys);
-	}
-	conn->session_keys = NULL;
-	conn->session_keys_len = 0;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s",
-			   __func__, gnutls_strerror(ret));
-		return NULL;
-	}
-
-	ret = gnutls_ia_endphase_send(conn->session, final);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s",
-			   __func__, gnutls_strerror(ret));
-		return NULL;
-	}
-
-	buf = conn->push_buf;
-	conn->push_buf = NULL;
-	return buf;
-#else /* GNUTLS_IA */
-	return NULL;
-#endif /* GNUTLS_IA */
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return -1;
-
-	return conn->final_phase_finished;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-#ifdef GNUTLS_IA
-	if (conn == NULL || !conn->tls_ia)
-		return -1;
-
-	if (conn->session_keys) {
-		os_memset(conn->session_keys, 0, conn->session_keys_len);
-		os_free(conn->session_keys);
-	}
-	conn->session_keys_len = 0;
-
-	if (key) {
-		conn->session_keys = os_malloc(key_len);
-		if (conn->session_keys == NULL)
-			return -1;
-		os_memcpy(conn->session_keys, key, key_len);
-		conn->session_keys_len = key_len;
-	} else {
-		conn->session_keys = NULL;
-		conn->session_keys_len = 0;
-	}
-
-	return 0;
-#else /* GNUTLS_IA */
-	return -1;
-#endif /* GNUTLS_IA */
 }
 
 
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index cc165f6..f5e31d9 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -290,13 +290,6 @@
 }
 
 
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
 int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
 			    struct tls_keys *keys)
 {
@@ -339,6 +332,17 @@
 					 const struct wpabuf *in_data,
 					 struct wpabuf **appl_data)
 {
+	return tls_connection_handshake2(tls_ctx, conn, in_data, appl_data,
+					 NULL);
+}
+
+
+struct wpabuf * tls_connection_handshake2(void *tls_ctx,
+					  struct tls_connection *conn,
+					  const struct wpabuf *in_data,
+					  struct wpabuf **appl_data,
+					  int *need_more_data)
+{
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
 	u8 *res, *ad;
 	size_t res_len, ad_len;
@@ -351,7 +355,7 @@
 	res = tlsv1_client_handshake(conn->client,
 				     in_data ? wpabuf_head(in_data) : NULL,
 				     in_data ? wpabuf_len(in_data) : 0,
-				     &res_len, &ad, &ad_len);
+				     &res_len, &ad, &ad_len, need_more_data);
 	if (res == NULL)
 		return NULL;
 	out = wpabuf_alloc_ext_data(res, res_len);
@@ -462,23 +466,23 @@
 				       struct tls_connection *conn,
 				       const struct wpabuf *in_data)
 {
+	return tls_connection_decrypt2(tls_ctx, conn, in_data, NULL);
+}
+
+
+struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
+					struct tls_connection *conn,
+					const struct wpabuf *in_data,
+					int *need_more_data)
+{
+	if (need_more_data)
+		*need_more_data = 0;
+
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
 	if (conn->client) {
-		struct wpabuf *buf;
-		int res;
-		buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
-		if (buf == NULL)
-			return NULL;
-		res = tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
-					   wpabuf_len(in_data),
-					   wpabuf_mhead(buf),
-					   wpabuf_size(buf));
-		if (res < 0) {
-			wpabuf_free(buf);
-			return NULL;
-		}
-		wpabuf_put(buf, res);
-		return buf;
+		return tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
+					    wpabuf_len(in_data),
+					    need_more_data);
 	}
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
@@ -611,28 +615,6 @@
 }
 
 
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}
-
-
 int tls_connection_set_session_ticket_cb(void *tls_ctx,
 					 struct tls_connection *conn,
 					 tls_session_ticket_cb cb,
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index 0c836bb..927edf5 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -84,13 +84,6 @@
 }
 
 
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
 int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
 			    struct tls_keys *keys)
 {
@@ -205,25 +198,3 @@
 {
 	return 0;
 }
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}
diff --git a/src/crypto/tls_nss.c b/src/crypto/tls_nss.c
index ad834b6..09a1e73 100644
--- a/src/crypto/tls_nss.c
+++ b/src/crypto/tls_nss.c
@@ -419,13 +419,6 @@
 }
 
 
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
 int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
 			    struct tls_keys *keys)
 {
@@ -649,28 +642,6 @@
 }
 
 
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}
-
-
 int tls_connection_set_session_ticket_cb(void *tls_ctx,
 					 struct tls_connection *conn,
 					 tls_session_ticket_cb cb,
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 14ff87e..8374096 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -59,6 +59,7 @@
 	void (*event_cb)(void *ctx, enum tls_event ev,
 			 union tls_event_data *data);
 	void *cb_ctx;
+	int cert_in_cb;
 };
 
 static struct tls_global *tls_global = NULL;
@@ -694,6 +695,7 @@
 		if (conf) {
 			tls_global->event_cb = conf->event_cb;
 			tls_global->cb_ctx = conf->cb_ctx;
+			tls_global->cert_in_cb = conf->cert_in_cb;
 		}
 
 #ifdef CONFIG_FIPS
@@ -1144,7 +1146,7 @@
 		return;
 
 	os_memset(&ev, 0, sizeof(ev));
-	if (conn->cert_probe) {
+	if (conn->cert_probe || tls_global->cert_in_cb) {
 		cert = get_x509_cert(err_cert);
 		ev.peer_cert.cert = cert;
 	}
@@ -1661,6 +1663,7 @@
 
 	if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
 					 SSL_FILETYPE_ASN1) != 1 &&
+	    SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 &&
 	    SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
 					 SSL_FILETYPE_PEM) != 1) {
 		tls_show_errors(MSG_INFO, __func__,
@@ -2809,35 +2812,6 @@
 }
 
 
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}
-
-
 #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
 /* Pre-shared secred requires a patch to openssl, so this function is
  * commented out unless explicitly needed for EAP-FAST in order to be able to
diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c
index 4a94e99..a33d24e 100644
--- a/src/crypto/tls_schannel.c
+++ b/src/crypto/tls_schannel.c
@@ -736,32 +736,3 @@
 {
 	return 0;
 }
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final);
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}
diff --git a/src/drivers/Apple80211.h b/src/drivers/Apple80211.h
deleted file mode 100644
index 2a612e7..0000000
--- a/src/drivers/Apple80211.h
+++ /dev/null
@@ -1,156 +0,0 @@
-#ifndef APPLE80211_H
-#define APPLE80211_H
-
-/*
- * Apple80211 framework definitions
- * This is an undocumented interface and the definitions here are based on
- * information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and
- * whatever related information can be found with google and experiments ;-).
- */
-
-typedef struct __WirelessRef *WirelessRef;
-typedef SInt32 WirelessError;
-#define errWirelessNoError 0
-
-typedef struct WirelessInfo {
-	UInt16 link_qual;
-	UInt16 comms_qual;
-	UInt16 signal;
-	UInt16 noise;
-	UInt16 port_stat;
-	UInt16 client_mode;
-	UInt16 res1;
-	UInt16 power;
-	UInt16 res2;
-	UInt8 bssID[6];
-	UInt8 ssid[34];
-} WirelessInfo;
-
-typedef struct WirelessInfo2 {
-	/* TODO - these are probably not in correct order or complete */
-	WirelessInfo info1;
-	UInt8 macAddress[6];
-} WirelessInfo2;
-
-typedef struct WirelessNetworkInfo {
-	UInt16 channel;
-	UInt16 noise;
-	UInt16 signal;
-	UInt8 bssid[6];
-	UInt16 beacon_int;
-	UInt16 capability;
-	UInt16 ssid_len;
-	UInt8 ssid[32];
-} WirelessNetworkInfo;
-
-typedef int wirelessKeyType; /* TODO */
-
-int WirelessIsAvailable(void);
-WirelessError WirelessAttach(WirelessRef *ref, UInt32 res);
-WirelessError WirelessDetach(WirelessRef ref);
-WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes,
-			      void *out_ptr, int out_bytes);
-WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled);
-WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled);
-WirelessError WirelessSetPower(WirelessRef ref, UInt8 power);
-WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power);
-WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info);
-WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info);
-WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results,
-			   UInt32 strip_dups);
-WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results,
-				CFArrayRef *ibss_results, UInt32 strip_dups);
-WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results,
-				   UInt32 strip_dups, CFStringRef ssid);
-WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid,
-				    UInt32 strip_dups, CFArrayRef *results);
-WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid);
-WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid,
-			      CFStringRef passwd);
-WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid);
-/*
- * Set WEP key
- * ref: wireless reference from WirelessAttach()
- * type: ?
- * key_idx: 0..3
- * key_len: 13 for WEP-104 or 0 for clearing the key
- * key: Pointer to the key or %NULL if key_len = 0
- */
-WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type,
-			     int key_idx, int key_len,
-			     const unsigned char *key);
-/*
- * Set WPA key (e.g., PMK for 4-way handshake)
- * ref: wireless reference from WirelessAttach()
- * type: 0..4; 1 = PMK
- * key_len: 16, 32, or 0
- * key: Pointer to the key or %NULL if key_len = 0
- */
-WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type,
-				int key_len, const unsigned char *key);
-WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid,
-				CFStringRef key);
-WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res,
-				 CFStringRef key);
-WirelessError WirelessDisassociate(WirelessRef ref);
-
-/*
- * Get a copy of scan results for the given SSID
- * The returned dictionary includes following entries:
- * beaconInterval: CFNumber(kCFNumberSInt32Type)
- * SSID: CFData buffer of the SSID
- * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2
- * name: Name of the network (SSID string)
- * BSSID: CFData buffer of the BSSID
- * channel: CFNumber(kCFNumberSInt32Type)
- * signal: CFNumber(kCFNumberSInt32Type)
- * appleIE: CFData
- * WPSNOPINRequired: CFBoolean
- * noise: CFNumber(kCFNumberSInt32Type)
- * capability: CFNumber(kCFNumberSInt32Type)
- * uniCipher: CFArray of CFNumber(kCFNumberSInt32Type)
- * appleIE_Version: CFNumber(kCFNumberSInt32Type)
- * appleIE_Robust: CFBoolean
- * WPSConfigured: CFBoolean
- * scanWasDirected: CFBoolean
- * appleIE_Product: CFNumber(kCFNumberSInt32Type)
- * authModes: CFArray of CFNumber(kCFNumberSInt32Type)
- * multiCipher: CFNumber(kCFNumberSInt32Type)
- */
-CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid);
-
-/*
- * Get information about the current association
- * The returned dictionary includes following entries:
- * keyData: CFData buffer of the key (e.g., 32-octet PSK)
- * multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP?
- * channel: CFNumber(kCFNumberSInt32Type)
- * isIBSS: CFBoolean
- * authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open,
- *	129 = WPA2-Enterprise
- * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2
- * SSID: CFData buffer of the SSID
- * cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP?
- */
-CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref);
-
-WirelessError WirelessConfigure(WirelessRef ref);
-
-/*
- * Get ASP information
- * The returned dictionary includes following entries:
- * Version: version number (e.g., 3.0)
- * Channel: channel (e.g., 1)
- * Vendor: vendor (e.g., 2)
- */
-CFDictionaryRef WirelessGetInfoASP(void);
-
-/*
- * Get a copy of the interface dictionary
- * The returned dictionary has a key,value pairs for wireless interfaces.
- * The key is the interface name and the value is the driver identifier, e.g.,
- * en1: com.apple.driver.AirPort.Atheros
- */
-CFDictionaryRef WirelessCopyInterfaceDict(void);
-
-#endif /* APPLE80211_H */
diff --git a/src/drivers/MobileApple80211.c b/src/drivers/MobileApple80211.c
deleted file mode 100644
index ce004fe..0000000
--- a/src/drivers/MobileApple80211.c
+++ /dev/null
@@ -1,189 +0,0 @@
-#include "includes.h"
-#include <dlfcn.h>
-
-#include "common.h"
-
-#include <CoreFoundation/CoreFoundation.h>
-#include "MobileApple80211.h"
-
-/*
- * Code for dynamically loading Apple80211 functions from Aeropuerto to avoid
- * having to link with full Preferences.framework.
- */
-
-static void *aeropuerto = NULL;
-
-
-int _Apple80211Initialized(void)
-{
-	return aeropuerto ? 1 : 0;
-}
-
-
-static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL;
-
-int Apple80211Open(Apple80211Ref *ctx)
-{
-	return __Apple80211Open(ctx);
-}
-
-
-static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL;
-
-int Apple80211Close(Apple80211Ref ctx)
-{
-	return __Apple80211Close(ctx);
-}
-
-
-static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list)
-	= NULL;
-
-int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list)
-{
-	return __Apple80211GetIfListCopy(handle, list);
-}
-
-
-static int (*__Apple80211BindToInterface)(Apple80211Ref handle,
-					  CFStringRef interface) = NULL;
-
-int Apple80211BindToInterface(Apple80211Ref handle,
-			      CFStringRef interface)
-{
-	return __Apple80211BindToInterface(handle, interface);
-}
-
-
-static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle,
-					       CFStringRef *name) = NULL;
-
-int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
-				   CFStringRef *name)
-{
-	return __Apple80211GetInterfaceNameCopy(handle, name);
-}
-
-
-static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle,
-				      CFDictionaryRef *info) = NULL;
-
-int Apple80211GetInfoCopy(Apple80211Ref handle,
-			  CFDictionaryRef *info)
-{
-	return __Apple80211GetInfoCopy(handle, info);
-}
-
-
-static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL;
-
-int Apple80211GetPower(Apple80211Ref handle, char *pwr)
-{
-	return __Apple80211GetPower(handle, pwr);
-}
-
-
-static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL;
-
-int Apple80211SetPower(Apple80211Ref handle, char pwr)
-{
-	return __Apple80211SetPower(handle, pwr);
-}
-
-
-static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list,
-			       CFDictionaryRef parameters) = NULL;
-
-int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
-		   CFDictionaryRef parameters)
-{
-	return __Apple80211Scan(handle, list, parameters);
-}
-
-
-static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss,
-				    CFStringRef password) = NULL;
-
-int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
-			CFStringRef password)
-{
-	return __Apple80211Associate(handle, bss, password);
-}
-
-
-static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle,
-					       CFDictionaryRef bss,
-					       CFStringRef password,
-					       CFDictionaryRef *info) =
-	NULL;
-
-int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
-				   CFStringRef password, CFDictionaryRef *info)
-{
-	return __Apple80211AssociateAndCopyInfo(handle, bss, password, info);
-}
-
-
-static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field,
-				    CFDictionaryRef arg2, void *value) = NULL;
-
-int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
-			void *value)
-{
-	return __Apple80211CopyValue(handle, field, arg2, value);
-}
-
-
-#define DLSYM(s) \
-do { \
-	__ ## s = dlsym(aeropuerto, #s); \
-	if (__ ## s == NULL) { \
-		wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \
-			   "symbol '" #s "' (%s)", dlerror()); \
-		err = 1; \
-	} \
-} while (0)
-
-
-__attribute__ ((constructor))
-void _Apple80211_constructor(void)
-{
-	const char *fname = "/System/Library/SystemConfiguration/"
-		"Aeropuerto.bundle/Aeropuerto";
-	int err = 0;
-
-	aeropuerto = dlopen(fname, RTLD_LAZY);
-	if (!aeropuerto) {
-		wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s "
-			   "for symbols", fname);
-		return;
-	}
-
-	DLSYM(Apple80211Open);
-	DLSYM(Apple80211Close);
-	DLSYM(Apple80211GetIfListCopy);
-	DLSYM(Apple80211BindToInterface);
-	DLSYM(Apple80211GetInterfaceNameCopy);
-	DLSYM(Apple80211GetInfoCopy);
-	DLSYM(Apple80211GetPower);
-	DLSYM(Apple80211SetPower);
-	DLSYM(Apple80211Scan);
-	DLSYM(Apple80211Associate);
-	DLSYM(Apple80211AssociateAndCopyInfo);
-	DLSYM(Apple80211CopyValue);
-
-	if (err) {
-		dlclose(aeropuerto);
-		aeropuerto = NULL;
-	}
-}
-
-
-__attribute__ ((destructor))
-void _Apple80211_destructor(void)
-{
-	if (aeropuerto) {
-		dlclose(aeropuerto);
-		aeropuerto = NULL;
-	}
-}
diff --git a/src/drivers/MobileApple80211.h b/src/drivers/MobileApple80211.h
deleted file mode 100644
index 64d439d..0000000
--- a/src/drivers/MobileApple80211.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef MOBILEAPPLE80211_H
-#define MOBILEAPPLE80211_H
-
-/*
- * MobileApple80211 interface for iPhone/iPod touch
- * These functions are available from Aeropuerto.
- */
-
-struct Apple80211;
-typedef struct Apple80211 *Apple80211Ref;
-
-int Apple80211Open(Apple80211Ref *ctx);
-int Apple80211Close(Apple80211Ref ctx);
-int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list);
-int Apple80211BindToInterface(Apple80211Ref handle,
-			      CFStringRef interface);
-int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
-				   CFStringRef *name);
-int Apple80211GetInfoCopy(Apple80211Ref handle,
-			  CFDictionaryRef *info);
-int Apple80211GetPower(Apple80211Ref handle, char *pwr);
-int Apple80211SetPower(Apple80211Ref handle, char pwr);
-
-/* parameters can be NULL; returns scan results in CFArrayRef *list;
- * caller will need to free with CFRelease() */
-int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
-		   CFDictionaryRef parameters);
-
-int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
-			CFStringRef password);
-int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
-				   CFStringRef password,
-				   CFDictionaryRef *info);
-
-enum {
-	APPLE80211_VALUE_SSID = 1,
-	APPLE80211_VALUE_BSSID = 9
-};
-
-int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
-			void *value);
-
-#endif /* MOBILEAPPLE80211_H */
diff --git a/src/drivers/android_drv.h b/src/drivers/android_drv.h
new file mode 100644
index 0000000..6df7160
--- /dev/null
+++ b/src/drivers/android_drv.h
@@ -0,0 +1,62 @@
+/*
+ * Android driver interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ */
+
+#ifndef ANDROID_DRV_H
+#define ANDROID_DRV_H
+
+#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE "
+
+#define WEXT_CSCAN_AMOUNT		9
+
+#define MAX_SSID_LEN 32
+
+#define MAX_DRV_CMD_SIZE		248
+#define DRV_NUMBER_SEQUENTIAL_ERRORS	4
+
+#define WEXT_PNOSETUP_HEADER		"PNOSETUP "
+#define WEXT_PNOSETUP_HEADER_SIZE	9
+#define WEXT_PNO_TLV_PREFIX		'S'
+#define WEXT_PNO_TLV_VERSION		'1'
+#define WEXT_PNO_TLV_SUBVERSION		'2'
+#define WEXT_PNO_TLV_RESERVED		'0'
+#define WEXT_PNO_VERSION_SIZE		4
+#define WEXT_PNO_AMOUNT			16
+#define WEXT_PNO_SSID_SECTION		'S'
+/* SSID header size is SSID section type above + SSID length */
+#define WEXT_PNO_SSID_HEADER_SIZE	2
+#define WEXT_PNO_SCAN_INTERVAL_SECTION	'T'
+#define WEXT_PNO_SCAN_INTERVAL_LENGTH	2
+#define WEXT_PNO_SCAN_INTERVAL		30
+/* Scan interval size is scan interval section type + scan interval length
+ * above */
+#define WEXT_PNO_SCAN_INTERVAL_SIZE	(1 + WEXT_PNO_SCAN_INTERVAL_LENGTH)
+#define WEXT_PNO_REPEAT_SECTION		'R'
+#define WEXT_PNO_REPEAT_LENGTH		1
+#define WEXT_PNO_REPEAT			4
+/* Repeat section size is Repeat section type + Repeat value length above */
+#define WEXT_PNO_REPEAT_SIZE		(1 + WEXT_PNO_REPEAT_LENGTH)
+#define WEXT_PNO_MAX_REPEAT_SECTION	'M'
+#define WEXT_PNO_MAX_REPEAT_LENGTH	1
+#define WEXT_PNO_MAX_REPEAT		3
+/* Max Repeat section size is Max Repeat section type + Max Repeat value length
+ * above */
+#define WEXT_PNO_MAX_REPEAT_SIZE	(1 + WEXT_PNO_MAX_REPEAT_LENGTH)
+/* This corresponds to the size of all sections expect SSIDs */
+#define WEXT_PNO_NONSSID_SECTIONS_SIZE \
+(WEXT_PNO_SCAN_INTERVAL_SIZE + WEXT_PNO_REPEAT_SIZE + WEXT_PNO_MAX_REPEAT_SIZE)
+/* PNO Max command size is total of header, version, ssid and other sections +
+ * Null termination */
+#define WEXT_PNO_MAX_COMMAND_SIZE \
+	(WEXT_PNOSETUP_HEADER_SIZE + WEXT_PNO_VERSION_SIZE \
+	 + WEXT_PNO_AMOUNT * (WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN) \
+	 + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1)
+
+#endif /* ANDROID_DRV_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 19f732d..ceed531 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -35,14 +35,6 @@
 #define HOSTAPD_CHAN_HT40MINUS 0x00000020
 #define HOSTAPD_CHAN_HT40 0x00000040
 
-#ifdef ANDROID_BRCM_P2P_PATCH
-/**
- * Monitor interface name is derived from p2p interface name
- * We need to reset p2p interface name early to take care of extra character in
- */
-#define WPA_MONITOR_IFNAME_PREFIX	"m."
-#endif
-
 /**
  * struct hostapd_channel_data - Channel information
  */
@@ -68,6 +60,8 @@
 	u8 max_tx_power;
 };
 
+#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
+
 /**
  * struct hostapd_hw_modes - Supported hardware mode information
  */
@@ -111,6 +105,8 @@
 	 * a_mpdu_params - A-MPDU (IEEE 802.11n) parameters
 	 */
 	u8 a_mpdu_params;
+
+	unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
 };
 
 
@@ -203,7 +199,7 @@
 	const char *drv_name;
 };
 
-#define WPAS_MAX_SCAN_SSIDS 10
+#define WPAS_MAX_SCAN_SSIDS 16
 
 /**
  * struct wpa_driver_scan_params - Scan parameters
@@ -272,6 +268,15 @@
 	 * num_filter_ssids - Number of entries in filter_ssids array
 	 */
 	size_t num_filter_ssids;
+
+	/**
+	 * p2p_probe - Used to disable CCK (802.11b) rates for P2P probes
+	 *
+	 * When set, the driver is expected to remove rates 1, 2, 5.5, and 11
+	 * Mbps from the support rates element(s) in the Probe Request frames
+	 * and not to transmit the frames at any of those rates.
+	 */
+	u8 p2p_probe;
 };
 
 /**
@@ -290,6 +295,12 @@
 	size_t wep_key_len[4];
 	int wep_tx_keyidx;
 	int local_state_change;
+
+	/**
+	 * p2p - Whether this connection is a P2P group
+	 */
+	int p2p;
+
 };
 
 enum wps_mode {
@@ -353,6 +364,11 @@
 	size_t wpa_ie_len;
 
 	/**
+	 * wpa_proto - Bitfield of WPA_PROTO_* values to indicate WPA/WPA2
+	 */
+	unsigned int wpa_proto;
+
+	/**
 	 * pairwise_suite - Selected pairwise cipher suite
 	 *
 	 * This is usually ignored if @wpa_ie is used.
@@ -502,6 +518,183 @@
 	int uapsd;
 };
 
+enum hide_ssid {
+	NO_SSID_HIDING,
+	HIDDEN_SSID_ZERO_LEN,
+	HIDDEN_SSID_ZERO_CONTENTS
+};
+
+struct wpa_driver_ap_params {
+	/**
+	 * head - Beacon head from IEEE 802.11 header to IEs before TIM IE
+	 */
+	const u8 *head;
+
+	/**
+	 * head_len - Length of the head buffer in octets
+	 */
+	size_t head_len;
+
+	/**
+	 * tail - Beacon tail following TIM IE
+	 */
+	const u8 *tail;
+
+	/**
+	 * tail_len - Length of the tail buffer in octets
+	 */
+	size_t tail_len;
+
+	/**
+	 * dtim_period - DTIM period
+	 */
+	int dtim_period;
+
+	/**
+	 * beacon_int - Beacon interval
+	 */
+	int beacon_int;
+
+	/**
+	 * basic_rates: -1 terminated array of basic rates in 100 kbps
+	 *
+	 * This parameter can be used to set a specific basic rate set for the
+	 * BSS. If %NULL, default basic rate set is used.
+	 */
+	int *basic_rates;
+
+	/**
+	 * proberesp - Probe Response template
+	 *
+	 * This is used by drivers that reply to Probe Requests internally in
+	 * AP mode and require the full Probe Response template.
+	 */
+	const u8 *proberesp;
+
+	/**
+	 * proberesp_len - Length of the proberesp buffer in octets
+	 */
+	size_t proberesp_len;
+
+	/**
+	 * ssid - The SSID to use in Beacon/Probe Response frames
+	 */
+	const u8 *ssid;
+
+	/**
+	 * ssid_len - Length of the SSID (1..32)
+	 */
+	size_t ssid_len;
+
+	/**
+	 * hide_ssid - Whether to hide the SSID
+	 */
+	enum hide_ssid hide_ssid;
+
+	/**
+	 * pairwise_ciphers - WPA_CIPHER_* bitfield
+	 */
+	unsigned int pairwise_ciphers;
+
+	/**
+	 * group_cipher - WPA_CIPHER_*
+	 */
+	unsigned int group_cipher;
+
+	/**
+	 * key_mgmt_suites - WPA_KEY_MGMT_* bitfield
+	 */
+	unsigned int key_mgmt_suites;
+
+	/**
+	 * auth_algs - WPA_AUTH_ALG_* bitfield
+	 */
+	unsigned int auth_algs;
+
+	/**
+	 * wpa_version - WPA_PROTO_* bitfield
+	 */
+	unsigned int wpa_version;
+
+	/**
+	 * privacy - Whether privacy is used in the BSS
+	 */
+	int privacy;
+
+	/**
+	 * beacon_ies - WPS/P2P IE(s) for Beacon frames
+	 *
+	 * This is used to add IEs like WPS IE and P2P IE by drivers that do
+	 * not use the full Beacon template.
+	 */
+	const struct wpabuf *beacon_ies;
+
+	/**
+	 * proberesp_ies - P2P/WPS IE(s) for Probe Response frames
+	 *
+	 * This is used to add IEs like WPS IE and P2P IE by drivers that
+	 * reply to Probe Request frames internally.
+	 */
+	const struct wpabuf *proberesp_ies;
+
+	/**
+	 * assocresp_ies - WPS IE(s) for (Re)Association Response frames
+	 *
+	 * This is used to add IEs like WPS IE by drivers that reply to
+	 * (Re)Association Request frames internally.
+	 */
+	const struct wpabuf *assocresp_ies;
+
+	/**
+	 * isolate - Whether to isolate frames between associated stations
+	 *
+	 * If this is non-zero, the AP is requested to disable forwarding of
+	 * frames between associated stations.
+	 */
+	int isolate;
+
+	/**
+	 * cts_protect - Whether CTS protection is enabled
+	 */
+	int cts_protect;
+
+	/**
+	 * preamble - Whether short preamble is enabled
+	 */
+	int preamble;
+
+	/**
+	 * short_slot_time - Whether short slot time is enabled
+	 *
+	 * 0 = short slot time disable, 1 = short slot time enabled, -1 = do
+	 * not set (e.g., when 802.11g mode is not in use)
+	 */
+	int short_slot_time;
+
+	/**
+	 * ht_opmode - HT operation mode or -1 if HT not in use
+	 */
+	int ht_opmode;
+
+	/**
+	 * interworking - Whether Interworking is enabled
+	 */
+	int interworking;
+
+	/**
+	 * hessid - Homogeneous ESS identifier or %NULL if not set
+	 */
+	const u8 *hessid;
+
+	/**
+	 * access_network_type - Access Network Type (0..15)
+	 *
+	 * This is used for filtering Probe Request frames when Interworking is
+	 * enabled.
+	 */
+	u8 access_network_type;
+};
+
 /**
  * struct wpa_driver_capa - Driver capability information
  */
@@ -530,7 +723,7 @@
 #define WPA_DRIVER_FLAGS_DRIVER_IE	0x00000001
 /* Driver needs static WEP key setup after association command */
 #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
-#define WPA_DRIVER_FLAGS_USER_SPACE_MLME 0x00000004
+/* unused: 0x00000004 */
 /* Driver takes care of RSN 4-way handshake internally; PMK is configured with
  * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
 #define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
@@ -571,9 +764,24 @@
 #define WPA_DRIVER_FLAGS_OFFCHANNEL_TX			0x00008000
 /* Driver indicates TX status events for EAPOL Data frames */
 #define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS		0x00010000
+/* Driver indicates TX status events for Deauth/Disassoc frames */
+#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS		0x00020000
+/* Driver supports roaming (BSS selection) in firmware */
+#define WPA_DRIVER_FLAGS_BSS_SELECTION			0x00040000
+/* Driver supports operating as a TDLS peer */
+#define WPA_DRIVER_FLAGS_TDLS_SUPPORT			0x00080000
+/* Driver requires external TDLS setup/teardown/discovery */
+#define WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP		0x00100000
+/* Driver indicates support for Probe Response offloading in AP mode */
+#define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD		0x00200000
+/* Driver supports U-APSD in AP mode */
+#define WPA_DRIVER_FLAGS_AP_UAPSD			0x00400000
 	unsigned int flags;
 
 	int max_scan_ssids;
+	int max_sched_scan_ssids;
+	int sched_scan_supported;
+	int max_match_sets;
 
 	/**
 	 * max_remain_on_chan - Maximum remain-on-channel duration in msec
@@ -585,6 +793,20 @@
 	 * supports in AP mode
 	 */
 	unsigned int max_stations;
+
+	/**
+	 * probe_resp_offloads - Bitmap of supported protocols by the driver
+	 * for Probe Response offloading.
+	 */
+/* Driver Probe Response offloading support for WPS ver. 1 */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS		0x00000001
+/* Driver Probe Response offloading support for WPS ver. 2 */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2		0x00000002
+/* Driver Probe Response offloading support for P2P */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P		0x00000004
+/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING	0x00000008
+	unsigned int probe_resp_offloads;
 };
 
 
@@ -610,6 +832,9 @@
 	size_t supp_rates_len;
 	u16 listen_interval;
 	const struct ieee80211_ht_capabilities *ht_capabilities;
+	u32 flags; /* bitmask of WPA_STA_* flags */
+	int set; /* Set STA parameters instead of add */
+	u8 qosinfo;
 };
 
 struct hostapd_freq_params {
@@ -661,6 +886,7 @@
 };
 
 struct wpa_init_params {
+	void *global_priv;
 	const u8 *bssid;
 	const char *ifname;
 	const u8 *ssid;
@@ -693,6 +919,7 @@
 #define WPA_STA_WMM BIT(1)
 #define WPA_STA_SHORT_PREAMBLE BIT(2)
 #define WPA_STA_MFP BIT(3)
+#define WPA_STA_TDLS_PEER BIT(4)
 
 /**
  * struct p2p_params - P2P parameters for driver-based P2P management
@@ -1079,91 +1306,21 @@
 	 * flags: Variable for returning hardware feature flags
 	 * Returns: Pointer to allocated hardware data on success or %NULL on
 	 * failure. Caller is responsible for freeing this.
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to %wpa_supplicant or hostapd.
 	 */
 	struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
 							 u16 *num_modes,
 							 u16 *flags);
 
 	/**
-	 * set_channel - Set channel
-	 * @priv: Private driver interface data
-	 * @phymode: HOSTAPD_MODE_IEEE80211B, ..
-	 * @chan: IEEE 802.11 channel number
-	 * @freq: Frequency of the channel in MHz
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
-	 */
-	int (*set_channel)(void *priv, enum hostapd_hw_mode phymode, int chan,
-			   int freq);
-
-	/**
-	 * set_ssid - Set SSID
-	 * @priv: Private driver interface data
-	 * @ssid: SSID
-	 * @ssid_len: SSID length
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
-	 */
-	int (*set_ssid)(void *priv, const u8 *ssid, size_t ssid_len);
-
-	/**
-	 * set_bssid - Set BSSID
-	 * @priv: Private driver interface data
-	 * @bssid: BSSID
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
-	 */
-	int (*set_bssid)(void *priv, const u8 *bssid);
-
-	/**
 	 * send_mlme - Send management frame from MLME
 	 * @priv: Private driver interface data
 	 * @data: IEEE 802.11 management frame with IEEE 802.11 header
 	 * @data_len: Size of the management frame
+	 * @noack: Do not wait for this frame to be acked (disable retries)
 	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
 	 */
-	int (*send_mlme)(void *priv, const u8 *data, size_t data_len);
-
-	/**
-	 * mlme_add_sta - Add a STA entry into the driver/netstack
-	 * @priv: Private driver interface data
-	 * @addr: MAC address of the STA (e.g., BSSID of the AP)
-	 * @supp_rates: Supported rate set (from (Re)AssocResp); in IEEE 802.11
-	 * format (one octet per rate, 1 = 0.5 Mbps)
-	 * @supp_rates_len: Number of entries in supp_rates
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant. When the MLME code
-	 * completes association with an AP, this function is called to
-	 * configure the driver/netstack with a STA entry for data frame
-	 * processing (TX rate control, encryption/decryption).
-	 */
-	int (*mlme_add_sta)(void *priv, const u8 *addr, const u8 *supp_rates,
-			    size_t supp_rates_len);
-
-	/**
-	 * mlme_remove_sta - Remove a STA entry from the driver/netstack
-	 * @priv: Private driver interface data
-	 * @addr: MAC address of the STA (e.g., BSSID of the AP)
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
-	 */
-	int (*mlme_remove_sta)(void *priv, const u8 *addr);
+	int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
+			 int noack);
 
 	/**
 	 * update_ft_ies - Update FT (IEEE 802.11r) IEs
@@ -1292,24 +1449,25 @@
 			    struct wpa_driver_auth_params *params);
 
 	/**
-	 * set_beacon - Set Beacon frame template
+	 * set_ap - Set Beacon and Probe Response information for AP mode
 	 * @priv: Private driver interface data
-	 * @head: Beacon head from IEEE 802.11 header to IEs before TIM IE
-	 * @head_len: Length of the head buffer in octets
-	 * @tail: Beacon tail following TIM IE
-	 * @tail_len: Length of the tail buffer in octets
-	 * @dtim_period: DTIM period
-	 * @beacon_int: Beacon interval
-	 * Returns: 0 on success, -1 on failure
+	 * @params: Parameters to use in AP mode
 	 *
-	 * This function is used to configure Beacon template for the driver in
+	 * This function is used to configure Beacon template and/or extra IEs
+	 * to add for Beacon and Probe Response frames for the driver in
 	 * AP mode. The driver is responsible for building the full Beacon
 	 * frame by concatenating the head part with TIM IE generated by the
-	 * driver/firmware and finishing with the tail part.
+	 * driver/firmware and finishing with the tail part. Depending on the
+	 * driver architectue, this can be done either by using the full
+	 * template or the set of additional IEs (e.g., WPS and P2P IE).
+	 * Similarly, Probe Response processing depends on the driver design.
+	 * If the driver (or firmware) takes care of replying to Probe Request
+	 * frames, the extra IEs provided here needs to be added to the Probe
+	 * Response frames.
+	 *
+	 * Returns: 0 on success, -1 on failure
 	 */
-	int (*set_beacon)(void *priv, const u8 *head, size_t head_len,
-			  const u8 *tail, size_t tail_len, int dtim_period,
-			  int beacon_int);
+	int (*set_ap)(void *priv, struct wpa_driver_ap_params *params);
 
 	/**
 	 * hapd_init - Initialize driver interface (hostapd only)
@@ -1318,7 +1476,7 @@
 	 * Returns: Pointer to private data, %NULL on failure
 	 *
 	 * This function is used instead of init() or init2() when the driver
-	 * wrapper is used withh hostapd.
+	 * wrapper is used with hostapd.
 	 */
 	void * (*hapd_init)(struct hostapd_data *hapd,
 			    struct wpa_init_params *params);
@@ -1338,8 +1496,10 @@
 	 * This is an optional function to configure the kernel driver to
 	 * enable/disable IEEE 802.1X support and set WPA/WPA2 parameters. This
 	 * can be left undefined (set to %NULL) if IEEE 802.1X support is
-	 * always enabled and the driver uses set_beacon() to set WPA/RSN IE
+	 * always enabled and the driver uses set_ap() to set WPA/RSN IE
 	 * for Beacon frames.
+	 *
+	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params);
 
@@ -1351,7 +1511,9 @@
 	 *
 	 * This is an optional function to configure privacy field in the
 	 * kernel driver for Beacon frames. This can be left undefined (set to
-	 * %NULL) if the driver uses the Beacon template from set_beacon().
+	 * %NULL) if the driver uses the Beacon template from set_ap().
+	 *
+	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*set_privacy)(void *priv, int enabled);
 
@@ -1393,7 +1555,9 @@
 	 * This is an optional function to add information elements in the
 	 * kernel driver for Beacon and Probe Response frames. This can be left
 	 * undefined (set to %NULL) if the driver uses the Beacon template from
-	 * set_beacon().
+	 * set_ap().
+	 *
+	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len);
 
@@ -1467,8 +1631,7 @@
 	 * Returns: Length of the SSID on success, -1 on failure
 	 *
 	 * This function need not be implemented if the driver uses Beacon
-	 * template from set_beacon() and does not reply to Probe Request
-	 * frames.
+	 * template from set_ap() and does not reply to Probe Request frames.
 	 */
 	int (*hapd_get_ssid)(void *priv, u8 *buf, int len);
 
@@ -1478,6 +1641,8 @@
 	 * @buf: SSID
 	 * @len: Length of the SSID in octets
 	 * Returns: 0 on success, -1 on failure
+	 *
+	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*hapd_set_ssid)(void *priv, const u8 *buf, int len);
 
@@ -1501,6 +1666,9 @@
 	 * This function is used to add a station entry to the driver once the
 	 * station has completed association. This is only used if the driver
 	 * does not take care of association processing.
+	 *
+	 * With TDLS, this function is also used to add or set (params->set 1)
+	 * TDLS peer entries.
 	 */
 	int (*sta_add)(void *priv, struct hostapd_sta_add_params *params);
 
@@ -1557,41 +1725,6 @@
 			     int total_flags, int flags_or, int flags_and);
 
 	/**
-	 * set_rate_sets - Set supported and basic rate sets (AP only)
-	 * @priv: Private driver interface data
-	 * @supp_rates: -1 terminated array of supported rates in 100 kbps
-	 * @basic_rates: -1 terminated array of basic rates in 100 kbps
-	 * @mode: hardware mode (HOSTAPD_MODE_*)
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates,
-			     int mode);
-
-	/**
-	 * set_cts_protect - Set CTS protection mode (AP only)
-	 * @priv: Private driver interface data
-	 * @value: Whether CTS protection is enabled
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_cts_protect)(void *priv, int value);
-
-	/**
-	 * set_preamble - Set preamble mode (AP only)
-	 * @priv: Private driver interface data
-	 * @value: Whether short preamble is enabled
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_preamble)(void *priv, int value);
-
-	/**
-	 * set_short_slot_time - Set short slot time (AP only)
-	 * @priv: Private driver interface data
-	 * @value: Whether short slot time is enabled
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_short_slot_time)(void *priv, int value);
-
-	/**
 	 * set_tx_queue_params - Set TX queue parameters
 	 * @priv: Private driver interface data
 	 * @queue: Queue number (0 = VO, 1 = VI, 2 = BE, 3 = BK)
@@ -1604,17 +1737,6 @@
 				   int cw_max, int burst_time);
 
 	/**
-	 * valid_bss_mask - Validate BSSID mask
-	 * @priv: Private driver interface data
-	 * @addr: Address
-	 * @mask: Mask
-	 * Returns: 0 if mask is valid, -1 if mask is not valid, 1 if mask can
-	 * be used, but the main interface address must be the first address in
-	 * the block if mask is applied
-	 */
-	int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask);
-
-	/**
 	 * if_add - Add a virtual interface
 	 * @priv: Private driver interface data
 	 * @type: Interface type
@@ -1709,19 +1831,6 @@
 	int (*set_radius_acl_expire)(void *priv, const u8 *mac);
 
 	/**
-	 * set_ht_params - Set HT parameters (AP only)
-	 * @priv: Private driver interface data
-	 * @ht_capab: HT Capabilities IE
-	 * @ht_capab_len: Length of ht_capab in octets
-	 * @ht_oper: HT Operation IE
-	 * @ht_oper_len: Length of ht_oper in octets
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_ht_params)(void *priv,
-			     const u8 *ht_capab, size_t ht_capab_len,
-			     const u8 *ht_oper, size_t ht_oper_len);
-
-	/**
 	 * set_ap_wps_ie - Add WPS IE(s) into Beacon/Probe Response frames (AP)
 	 * @priv: Private driver interface data
 	 * @beacon: WPS IE(s) for Beacon frames or %NULL to remove extra IE(s)
@@ -1733,7 +1842,7 @@
 	 *
 	 * This is an optional function to add WPS IE in the kernel driver for
 	 * Beacon and Probe Response frames. This can be left undefined (set
-	 * to %NULL) if the driver uses the Beacon template from set_beacon()
+	 * to %NULL) if the driver uses the Beacon template from set_ap()
 	 * and does not process Probe Request frames. If the driver takes care
 	 * of (Re)Association frame processing, the assocresp buffer includes
 	 * WPS IE(s) that need to be added to (Re)Association Response frames
@@ -1746,6 +1855,8 @@
 	 * also used to provide Probe Response IEs for P2P Listen state
 	 * operations for drivers that generate the Probe Response frames
 	 * internally.
+	 *
+	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*set_ap_wps_ie)(void *priv, const struct wpabuf *beacon,
 			     const struct wpabuf *proberesp,
@@ -1782,6 +1893,7 @@
 	 * @bssid: BSSID (Address 3)
 	 * @data: Frame body
 	 * @data_len: data length in octets
+	 @ @no_cck: Whether CCK rates must not be used to transmit this frame
 	 * Returns: 0 on success, -1 on failure
 	 *
 	 * This command can be used to request the driver to transmit an action
@@ -1799,7 +1911,7 @@
 	 */
 	int (*send_action)(void *priv, unsigned int freq, unsigned int wait,
 			   const u8 *dst, const u8 *src, const u8 *bssid,
-			   const u8 *data, size_t data_len);
+			   const u8 *data, size_t data_len, int no_cck);
 
 	/**
 	 * send_action_cancel_wait - Cancel action frame TX wait
@@ -1866,19 +1978,6 @@
 	int (*probe_req_report)(void *priv, int report);
 
 	/**
-	 * disable_11b_rates - Set whether IEEE 802.11b rates are used for TX
-	 * @priv: Private driver interface data
-	 * @disabled: Whether IEEE 802.11b rates are disabled
-	 * Returns: 0 on success, -1 on failure (or if not supported)
-	 *
-	 * This command is used to disable IEEE 802.11b rates (1, 2, 5.5, and
-	 * 11 Mbps) as TX rates for data and management frames. This can be
-	 * used to optimize channel use when there is no need to support IEEE
-	 * 802.11b-only devices.
-	 */
-	int (*disable_11b_rates)(void *priv, int disabled);
-
-	/**
 	 * deinit_ap - Deinitialize AP mode
 	 * @priv: Private driver interface data
 	 * Returns: 0 on success, -1 on failure (or if not supported)
@@ -1990,11 +2089,6 @@
 	int (*ampdu)(void *priv, int ampdu);
 
 	/**
-	 * set_intra_bss - Enables/Disables intra BSS bridging
-	 */
-	int (*set_intra_bss)(void *priv, int enabled);
-
-	/**
 	 * get_radio_name - Get physical radio name for the device
 	 * @priv: Private driver interface data
 	 * Returns: Radio name or %NULL if not known
@@ -2132,7 +2226,7 @@
 	 * struct wpa_driver_capa.
 	 */
 	int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr,
-				 u16 config_methods);
+				 u16 config_methods, int join);
 
 	/**
 	 * p2p_sd_request - Schedule a service discovery query
@@ -2232,7 +2326,7 @@
 	 * @status_code: Status Code or Reason Code to use (if needed)
 	 * @buf: TDLS IEs to add to the message
 	 * @len: Length of buf in octets
-	 * Returns: 0 on success, -1 on failure
+	 * Returns: 0 on success, negative (<0) on failure
 	 *
 	 * This optional function can be used to send packet to driver which is
 	 * responsible for receiving and sending all TDLS packets.
@@ -2241,6 +2335,16 @@
 			      u8 dialog_token, u16 status_code,
 			      const u8 *buf, size_t len);
 
+	/**
+	 * tdls_oper - Ask the driver to perform high-level TDLS operations
+	 * @priv: Private driver interface data
+	 * @oper: TDLS high-level operation. See %enum tdls_oper
+	 * @peer: Destination (peer) MAC address
+	 * Returns: 0 on success, negative (<0) on failure
+	 *
+	 * This optional function can be used to send high-level TDLS commands
+	 * to the driver.
+	 */
 	int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer);
 
 	/**
@@ -2259,9 +2363,11 @@
 	 * This function can be used to set authentication algorithms for AP
 	 * mode when static WEP is used. If the driver uses user space MLME/SME
 	 * implementation, there is no need to implement this function.
+	 *
+	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*set_authmode)(void *priv, int authmode);
-
+#ifdef ANDROID
 	/**
 	 * driver_cmd - execute driver-specific command
 	 * @priv: private driver interface data
@@ -2272,6 +2378,135 @@
 	 * Returns: 0 on success, -1 on failure
 	 */
 	 int (*driver_cmd)(void *priv, char *cmd, char *buf, size_t buf_len);
+#endif
+	/**
+	 * set_rekey_info - Set rekey information
+	 * @priv: Private driver interface data
+	 * @kek: Current KEK
+	 * @kck: Current KCK
+	 * @replay_ctr: Current EAPOL-Key Replay Counter
+	 *
+	 * This optional function can be used to provide information for the
+	 * driver/firmware to process EAPOL-Key frames in Group Key Handshake
+	 * while the host (including wpa_supplicant) is sleeping.
+	 */
+	void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck,
+			       const u8 *replay_ctr);
+
+	/**
+	 * sta_assoc - Station association indication
+	 * @priv: Private driver interface data
+	 * @own_addr: Source address and BSSID for association frame
+	 * @addr: MAC address of the station to associate
+	 * @reassoc: flag to indicate re-association
+	 * @status: association response status code
+	 * @ie: assoc response ie buffer
+	 * @len: ie buffer length
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function indicates the driver to send (Re)Association
+	 * Response frame to the station.
+	 */
+	 int (*sta_assoc)(void *priv, const u8 *own_addr, const u8 *addr,
+			  int reassoc, u16 status, const u8 *ie, size_t len);
+
+	/**
+	 * sta_auth - Station authentication indication
+	 * @priv: Private driver interface data
+	 * @own_addr: Source address and BSSID for authentication frame
+	 * @addr: MAC address of the station to associate
+	 * @seq: authentication sequence number
+	 * @status: authentication response status code
+	 * @ie: authentication frame ie buffer
+	 * @len: ie buffer length
+	 *
+	 * This function indicates the driver to send Authentication frame
+	 * to the station.
+	 */
+	 int (*sta_auth)(void *priv, const u8 *own_addr, const u8 *addr,
+			 u16 seq, u16 status, const u8 *ie, size_t len);
+
+	/**
+	 * add_tspec - Add traffic stream
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the station to associate
+	 * @tspec_ie: tspec ie buffer
+	 * @tspec_ielen: tspec ie length
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function adds the traffic steam for the station
+	 * and fills the medium_time in tspec_ie.
+	 */
+	 int (*add_tspec)(void *priv, const u8 *addr, u8 *tspec_ie,
+			  size_t tspec_ielen);
+
+	/**
+	 * add_sta_node - Add a station node in the driver
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the station to add
+	 * @auth_alg: authentication algorithm used by the station
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function adds the station node in the driver, when
+	 * the station gets added by FT-over-DS.
+	 */
+	int (*add_sta_node)(void *priv, const u8 *addr, u16 auth_alg);
+
+	/**
+	 * sched_scan - Request the driver to initiate scheduled scan
+	 * @priv: Private driver interface data
+	 * @params: Scan parameters
+	 * @interval: Interval between scan cycles in milliseconds
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This operation should be used for scheduled scan offload to
+	 * the hardware. Every time scan results are available, the
+	 * driver should report scan results event for wpa_supplicant
+	 * which will eventually request the results with
+	 * wpa_driver_get_scan_results2(). This operation is optional
+	 * and if not provided or if it returns -1, we fall back to
+	 * normal host-scheduled scans.
+	 */
+	int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params,
+			  u32 interval);
+
+	/**
+	 * stop_sched_scan - Request the driver to stop a scheduled scan
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This should cause the scheduled scan to be stopped and
+	 * results should stop being sent. Must be supported if
+	 * sched_scan is supported.
+	 */
+	int (*stop_sched_scan)(void *priv);
+
+	/**
+	 * poll_client - Probe (null data or such) the given station
+	 * @priv: Private driver interface data
+	 * @own_addr: MAC address of sending interface
+	 * @addr: MAC address of the station to probe
+	 * @qos: Indicates whether station is QoS station
+	 *
+	 * This function is used to verify whether an associated station is
+	 * still present. This function does not need to be implemented if the
+	 * driver provides such inactivity polling mechanism.
+	 */
+	void (*poll_client)(void *priv, const u8 *own_addr,
+			    const u8 *addr, int qos);
+#ifdef ANDROID_P2P
+	/**
+	 * go_switch_channel - Announce channel switch and migrate the GO to a
+	 * given frequency.
+	 * @priv: Private driver interface data
+	 * @freq: frequency in MHz
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is used to move the GO to the legacy STA channel to avoid
+	 * frequency conflict in single channel concurrency.
+	 */
+	int (*go_switch_channel)(void *priv, unsigned int freq);
+#endif
 };
 
 
@@ -2674,7 +2909,35 @@
 	/**
 	 * EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore
 	 */
-	EVENT_IBSS_PEER_LOST
+	EVENT_IBSS_PEER_LOST,
+
+	/**
+	 * EVENT_DRIVER_GTK_REKEY - Device/driver did GTK rekey
+	 *
+	 * This event carries the new replay counter to notify wpa_supplicant
+	 * of the current EAPOL-Key Replay Counter in case the driver/firmware
+	 * completed Group Key Handshake while the host (including
+	 * wpa_supplicant was sleeping).
+	 */
+	EVENT_DRIVER_GTK_REKEY,
+
+	/**
+	 * EVENT_SCHED_SCAN_STOPPED - Scheduled scan was stopped
+	 */
+	EVENT_SCHED_SCAN_STOPPED,
+
+	/**
+	 * EVENT_DRIVER_CLIENT_POLL_OK - Station responded to poll
+	 *
+	 * This event indicates that the station responded to the poll
+	 * initiated with @poll_client.
+	 */
+	EVENT_DRIVER_CLIENT_POLL_OK,
+
+	/**
+	 * EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status
+	 */
+	EVENT_EAPOL_TX_STATUS
 };
 
 
@@ -2898,7 +3161,9 @@
 	 */
 	struct auth_info {
 		u8 peer[ETH_ALEN];
+		u8 bssid[ETH_ALEN];
 		u16 auth_type;
+		u16 auth_transaction;
 		u16 status_code;
 		const u8 *ies;
 		size_t ies_len;
@@ -2966,8 +3231,9 @@
 	 * struct rx_from_unknown - Data for EVENT_RX_FROM_UNKNOWN events
 	 */
 	struct rx_from_unknown {
-		const u8 *frame;
-		size_t len;
+		const u8 *bssid;
+		const u8 *addr;
+		int wds;
 	} rx_from_unknown;
 
 	/**
@@ -3075,6 +3341,18 @@
 		const u8 *sa;
 
 		/**
+		 * da - Destination address of the received Probe Request frame
+		 *	or %NULL if not available
+		 */
+		const u8 *da;
+
+		/**
+		 * bssid - BSSID of the received Probe Request frame or %NULL
+		 *	if not available
+		 */
+		const u8 *bssid;
+
+		/**
 		 * ie - IEs from the Probe Request body
 		 */
 		const u8 *ie;
@@ -3206,6 +3484,39 @@
 	struct ibss_peer_lost {
 		u8 peer[ETH_ALEN];
 	} ibss_peer_lost;
+
+	/**
+	 * struct driver_gtk_rekey - Data for EVENT_DRIVER_GTK_REKEY
+	 */
+	struct driver_gtk_rekey {
+		const u8 *bssid;
+		const u8 *replay_ctr;
+	} driver_gtk_rekey;
+
+	/**
+	 * struct client_poll - Data for EVENT_DRIVER_CLIENT_POLL_OK events
+	 * @addr: station address
+	 */
+	struct client_poll {
+		u8 addr[ETH_ALEN];
+	} client_poll;
+
+	/**
+	 * struct eapol_tx_status
+	 * @dst: Original destination
+	 * @data: Data starting with IEEE 802.1X header (!)
+	 * @data_len: Length of data
+	 * @ack: Indicates ack or lost frame
+	 *
+	 * This corresponds to hapd_send_eapol if the frame sent
+	 * there isn't just reported as EVENT_TX_STATUS.
+	 */
+	struct eapol_tx_status {
+		const u8 *dst;
+		const u8 *data;
+		int data_len;
+		int ack;
+	} eapol_tx_status;
 };
 
 /**
@@ -3258,4 +3569,10 @@
 	wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
 }
 
+/* driver_common.c */
+void wpa_scan_results_free(struct wpa_scan_results *res);
+
+/* Convert wpa_event_type to a string for logging */
+const char * event_to_string(enum wpa_event_type event);
+
 #endif /* DRIVER_H */
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 1e78f6e..b17d1a6 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -34,7 +34,7 @@
  */
 #define ATH_WPS_IE
 
-#include "os/linux/include/ieee80211_external.h"
+#include "ieee80211_external.h"
 
 
 #ifdef CONFIG_WPS
@@ -45,7 +45,7 @@
 #endif
 #endif /* CONFIG_WPS */
 
-#include "wireless_copy.h"
+#include "linux_wext.h"
 
 #include "driver.h"
 #include "eloop.h"
@@ -641,6 +641,7 @@
 
 	wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
 		   (unsigned long) ie_len);
+	wpa_hexdump(MSG_DEBUG, "atheros: set_generic_elem", ie, ie_len);
 
 	wpabuf_free(drv->wpa_ie);
 	drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len);
@@ -658,6 +659,8 @@
 			  wpabuf_len(drv->wps_beacon_ie));
 		app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie);
 	}
+	wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(Beacon)",
+		    app_ie->app_buf, app_ie->app_buflen);
 	set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
 		     sizeof(struct ieee80211req_getset_appiebuf) +
 		     app_ie->app_buflen);
@@ -672,6 +675,8 @@
 			wpabuf_len(drv->wps_probe_resp_ie);
 	} else
 		app_ie->app_buflen = ie_len;
+	wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(ProbeResp)",
+		    app_ie->app_buf, app_ie->app_buflen);
 	set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
 		     sizeof(struct ieee80211req_getset_appiebuf) +
 		     app_ie->app_buflen);
@@ -748,6 +753,8 @@
 
 	os_memset(&event, 0, sizeof(event));
 	event.rx_probe_req.sa = mgmt->sa;
+	event.rx_probe_req.da = mgmt->da;
+	event.rx_probe_req.bssid = mgmt->bssid;
 	event.rx_probe_req.ie = mgmt->u.probe_req.variable;
 	event.rx_probe_req.ie_len =
 		len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
@@ -785,8 +792,9 @@
 	u8 buf[512];
 	struct ieee80211req_getset_appiebuf *beac_ie;
 
-	wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
-		   (unsigned long) len);
+	wpa_printf(MSG_DEBUG, "%s buflen = %lu frametype=%u", __func__,
+		   (unsigned long) len, frametype);
+	wpa_hexdump(MSG_DEBUG, "atheros: IE", ie, len);
 
 	beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
 	beac_ie->app_frmtype = frametype;
@@ -797,11 +805,15 @@
 	if (((frametype == IEEE80211_APPIE_FRAME_BEACON) ||
 	     (frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) &&
 	    (drv->wpa_ie != NULL)) {
+		wpa_hexdump_buf(MSG_DEBUG, "atheros: Append WPA/RSN IE",
+				drv->wpa_ie);
 		os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie),
 			  wpabuf_len(drv->wpa_ie));
 		beac_ie->app_buflen += wpabuf_len(drv->wpa_ie);
 	}
 
+	wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF",
+		    beac_ie->app_buf, beac_ie->app_buflen);
 	return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
 			    sizeof(struct ieee80211req_getset_appiebuf) +
 			    beac_ie->app_buflen);
@@ -814,6 +826,11 @@
 {
 	struct atheros_driver_data *drv = priv;
 
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - beacon", beacon);
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - proberesp",
+			proberesp);
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - assocresp",
+			assocresp);
 	wpabuf_free(drv->wps_beacon_ie);
 	drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL;
 	wpabuf_free(drv->wps_probe_resp_ie);
@@ -1332,6 +1349,8 @@
 	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
 	iwr.u.essid.pointer = (caddr_t) buf;
 	iwr.u.essid.length = len;
+	iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ?
+		IW_ESSID_MAX_SIZE : len;
 
 	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
 		perror("ioctl[SIOCGIWESSID]");
@@ -1374,6 +1393,34 @@
 	return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode);
 }
 
+static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
+{
+	/*
+	 * TODO: Use this to replace set_authmode, set_privacy, set_ieee8021x,
+	 * set_generic_elem, and hapd_set_ssid.
+	 */
+
+	wpa_printf(MSG_DEBUG, "atheros: set_ap - pairwise_ciphers=0x%x "
+		   "group_cipher=0x%x key_mgmt_suites=0x%x auth_algs=0x%x "
+		   "wpa_version=0x%x privacy=%d interworking=%d",
+		   params->pairwise_ciphers, params->group_cipher,
+		   params->key_mgmt_suites, params->auth_algs,
+		   params->wpa_version, params->privacy, params->interworking);
+	wpa_hexdump_ascii(MSG_DEBUG, "atheros: SSID",
+			  params->ssid, params->ssid_len);
+	if (params->hessid)
+		wpa_printf(MSG_DEBUG, "atheros: HESSID " MACSTR,
+			   MAC2STR(params->hessid));
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: beacon_ies",
+			params->beacon_ies);
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: proberesp_ies",
+			params->proberesp_ies);
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies",
+			params->assocresp_ies);
+
+	return 0;
+}
+
 const struct wpa_driver_ops wpa_driver_atheros_ops = {
 	.name			= "atheros",
 	.hapd_init		= atheros_init,
@@ -1396,4 +1443,5 @@
 	.commit			= atheros_commit,
 	.set_ap_wps_ie		= atheros_set_ap_wps_ie,
 	.set_authmode		= atheros_set_authmode,
+	.set_ap			= atheros_set_ap,
 };
diff --git a/src/drivers/driver_broadcom.c b/src/drivers/driver_broadcom.c
deleted file mode 100644
index cb88543..0000000
--- a/src/drivers/driver_broadcom.c
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with old Broadcom wl.o driver
- * Copyright (c) 2004, Nikki Chumkov <nikki@gattaca.ru>
- * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * Please note that the newer Broadcom driver ("hybrid Linux driver") supports
- * Linux wireless extensions and does not need (or even work) with this old
- * driver wrapper. Use driver_wext.c with that driver.
- */
-
-#include "includes.h"
-
-#include <sys/ioctl.h>
-
-#include "common.h"
-
-#if 0
-#include <netpacket/packet.h>
-#include <net/ethernet.h>     /* the L2 protocols */
-#else
-#include <linux/if_packet.h>
-#include <linux/if_ether.h>   /* The L2 protocols */
-#endif
-#include <net/if.h>
-#include <typedefs.h>
-
-/* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
- * WRT54G GPL tarball. */
-#include <wlioctl.h>
-
-#include "driver.h"
-#include "eloop.h"
-
-struct wpa_driver_broadcom_data {
-	void *ctx;
-	int ioctl_sock;
-	int event_sock;
-	char ifname[IFNAMSIZ + 1];
-};
-
-
-#ifndef WLC_DEAUTHENTICATE
-#define WLC_DEAUTHENTICATE 143
-#endif
-#ifndef WLC_DEAUTHENTICATE_WITH_REASON
-#define WLC_DEAUTHENTICATE_WITH_REASON 201
-#endif
-#ifndef WLC_SET_TKIP_COUNTERMEASURES
-#define WLC_SET_TKIP_COUNTERMEASURES 202
-#endif
-
-#if !defined(PSK_ENABLED) /* NEW driver interface */
-#define WL_VERSION 360130
-/* wireless authentication bit vector */
-#define WPA_ENABLED 1
-#define PSK_ENABLED 2
-                                                                                
-#define WAUTH_WPA_ENABLED(wauth)  ((wauth) & WPA_ENABLED)
-#define WAUTH_PSK_ENABLED(wauth)  ((wauth) & PSK_ENABLED)
-#define WAUTH_ENABLED(wauth)    ((wauth) & (WPA_ENABLED | PSK_ENABLED))
-
-#define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
-
-typedef wl_wsec_key_t wsec_key_t;
-#endif
-
-typedef struct {
-	uint32 val;
-	struct ether_addr ea;
-	uint16 res;
-} wlc_deauth_t;
-
-
-static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
-					     void *timeout_ctx);
-
-static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
-			  void *buf, int len)
-{
-	struct ifreq ifr;
-	wl_ioctl_t ioc;
-	int ret = 0;
-
-	wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
-		   drv->ifname, cmd, len, buf);
-	/* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
-
-	ioc.cmd = cmd;
-	ioc.buf = buf;
-	ioc.len = len;
-	os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
-	ifr.ifr_data = (caddr_t) &ioc;
-	if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
-		if (cmd != WLC_GET_MAGIC)
-			perror(ifr.ifr_name);
-		wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
-			   cmd, ret);
-	}
-
-	return ret;
-}
-
-static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
-		return 0;
-	
-	os_memset(bssid, 0, ETH_ALEN);
-	return -1;
-}
-
-static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wlc_ssid_t s;
-	
-	if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
-		return -1;
-
-	os_memcpy(ssid, s.SSID, s.SSID_len);
-	return s.SSID_len;
-}
-
-static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	unsigned int wauth, wsec;
-	struct ether_addr ea;
-
-	os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
-	if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
-	    -1 ||
-	    broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
-		return -1;
-
-	if (enable) {
-		wauth = PSK_ENABLED;
-		wsec = TKIP_ENABLED;
-	} else {
-		wauth = 255;
-		wsec &= ~(TKIP_ENABLED | AES_ENABLED);
-	}
-
-	if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
-	    -1 ||
-	    broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
-		return -1;
-
-	/* FIX: magic number / error handling? */
-	broadcom_ioctl(drv, 122, &ea, sizeof(ea));
-
-	return 0;
-}
-
-static int wpa_driver_broadcom_set_key(const char *ifname, void *priv,
-				       enum wpa_alg alg,
-				       const u8 *addr, int key_idx, int set_tx,
-				       const u8 *seq, size_t seq_len,
-				       const u8 *key, size_t key_len)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	int ret;
-	wsec_key_t wkt;
-
-	os_memset(&wkt, 0, sizeof wkt);
-	wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
-		   set_tx ? "PRIMARY " : "", key_idx, alg);
-	if (key && key_len > 0)
-		wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
-
-	switch (alg) {
-	case WPA_ALG_NONE:
-		wkt.algo = CRYPTO_ALGO_OFF;
-		break;
-	case WPA_ALG_WEP:
-		wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
-		break;
-	case WPA_ALG_TKIP:
-		wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
-		break;
-	case WPA_ALG_CCMP:
-		wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
-			       * AES_OCB_MSDU, AES_OCB_MPDU? */
-		break;
-	default:
-		wkt.algo = CRYPTO_ALGO_NALG;
-		break;
-	}
-
-	if (seq && seq_len > 0)
-		wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
-
-	if (addr)
-		wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
-
-	wkt.index = key_idx;
-	wkt.len = key_len;
-	if (key && key_len > 0) {
-		os_memcpy(wkt.data, key, key_len);
-		if (key_len == 32) {
-			/* hack hack hack XXX */
-			os_memcpy(&wkt.data[16], &key[24], 8);
-			os_memcpy(&wkt.data[24], &key[16], 8);
-		}
-	}
-	/* wkt.algo = CRYPTO_ALGO_...; */
-	wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
-	if (addr && set_tx)
-		os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
-	ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
-	if (addr && set_tx) {
-		/* FIX: magic number / error handling? */
-		broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
-	}
-	return ret;
-}
-
-
-static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
-					      void *sock_ctx)
-{
-	char buf[8192];
-	int left;
-	wl_wpa_header_t *wwh;
-	union wpa_event_data data;
-	u8 *resp_ies = NULL;
-
-	if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
-		return;
-
-	wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
-
-	if ((size_t) left < sizeof(wl_wpa_header_t))
-		return;
-
-	wwh = (wl_wpa_header_t *) buf;
-
-	if (wwh->snap.type != WL_WPA_ETHER_TYPE)
-		return;
-	if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-
-	switch (wwh->type) {
-	case WLC_ASSOC_MSG:
-		left -= WL_WPA_HEADER_LEN;
-		wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
-			   left);
-		if (left > 0) {
-			resp_ies = os_malloc(left);
-			if (resp_ies == NULL)
-				return;
-			os_memcpy(resp_ies, buf + WL_WPA_HEADER_LEN, left);
-			data.assoc_info.resp_ies = resp_ies;
-			data.assoc_info.resp_ies_len = left;
-		}
-
-		wpa_supplicant_event(ctx, EVENT_ASSOC, &data);
-		os_free(resp_ies);
-		break;
-	case WLC_DISASSOC_MSG:
-		wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
-		wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
-		break;
-	case WLC_PTK_MIC_MSG:
-		wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
-		data.michael_mic_failure.unicast = 1;
-		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-		break;
-	case WLC_GTK_MIC_MSG:
-		wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
-		data.michael_mic_failure.unicast = 0;
-		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
-			   wwh->type);
-		break;
-	}
-}	
-
-static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
-{
-	int s;
-	struct sockaddr_ll ll;
-	struct wpa_driver_broadcom_data *drv;
-	struct ifreq ifr;
-
-	/* open socket to kernel */
-	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-		perror("socket");
-		return NULL;
-	}
-	/* do it */
-	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
-		perror(ifr.ifr_name);
-		return NULL;
-	}
-
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->ioctl_sock = s;
-
-	s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
-	if (s < 0) {
-		perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-
-	os_memset(&ll, 0, sizeof(ll));
-	ll.sll_family = AF_PACKET;
-	ll.sll_protocol = ntohs(ETH_P_802_2);
-	ll.sll_ifindex = ifr.ifr_ifindex;
-	ll.sll_hatype = 0;
-	ll.sll_pkttype = PACKET_HOST;
-	ll.sll_halen = 0;
-
-	if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
-		perror("bind(netlink)");
-		close(s);
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-
-	eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
-				 NULL);
-	drv->event_sock = s;
-	wpa_driver_broadcom_set_wpa(drv, 1);
-
-	return drv;
-}
-
-static void wpa_driver_broadcom_deinit(void *priv)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wpa_driver_broadcom_set_wpa(drv, 0);
-	eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
-	eloop_unregister_read_sock(drv->event_sock);
-	close(drv->event_sock);
-	close(drv->ioctl_sock);
-	os_free(drv);
-}
-
-static int wpa_driver_broadcom_set_countermeasures(void *priv,
-						   int enabled)
-{
-#if 0
-	struct wpa_driver_broadcom_data *drv = priv;
-	/* FIX: ? */
-	return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
-			      sizeof(enabled));
-#else
-	return 0;
-#endif
-}
-
-static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	/* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
-	int _restrict = (enabled ? 1 : 0);
-	
-	if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT, 
-			   &_restrict, sizeof(_restrict)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
-			   &_restrict, sizeof(_restrict)) < 0)
-		return -1;
-
-	return 0;
-}
-
-static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
-					     void *timeout_ctx)
-{
-	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-static int wpa_driver_broadcom_scan(void *priv,
-				    struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wlc_ssid_t wst = { 0, "" };
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
-		wst.SSID_len = ssid_len;
-		os_memcpy(wst.SSID, ssid, ssid_len);
-	}
-	
-	if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
-		return -1;
-
-	eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
-	eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
-			       drv->ctx);
-	return 0;
-}
-
-
-static const int frequency_list[] = { 
-	2412, 2417, 2422, 2427, 2432, 2437, 2442,
-	2447, 2452, 2457, 2462, 2467, 2472, 2484 
-};
-
-struct bss_ie_hdr {
-	u8 elem_id;
-	u8 len;
-	u8 oui[3];
-	/* u8 oui_type; */
-	/* u16 version; */
-} __attribute__ ((packed));
-
-static struct wpa_scan_results *
-wpa_driver_broadcom_get_scan_results(void *priv)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	char *buf;
-	wl_scan_results_t *wsr;
-	wl_bss_info_t *wbi;
-	size_t ap_num;
-	struct wpa_scan_results *res;
-
-	buf = os_malloc(WLC_IOCTL_MAXLEN);
-	if (buf == NULL)
-		return NULL;
-
-	wsr = (wl_scan_results_t *) buf;
-
-	wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
-	wsr->version = 107;
-	wsr->count = 0;
-
-	if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
-		os_free(buf);
-		return NULL;
-	}
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL) {
-		os_free(buf);
-		return NULL;
-	}
-
-	res->res = os_zalloc(wsr->count * sizeof(struct wpa_scan_res *));
-	if (res->res == NULL) {
-		os_free(res);
-		os_free(buf);
-		return NULL;
-	}
-
-	for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
-		struct wpa_scan_res *r;
-		r = os_malloc(sizeof(*r) + wbi->ie_length);
-		if (r == NULL)
-			break;
-		res->res[res->num++] = r;
-
-		os_memcpy(r->bssid, &wbi->BSSID, ETH_ALEN);
-		r->freq = frequency_list[wbi->channel - 1];
-		/* get ie's */
-		os_memcpy(r + 1, wbi + 1, wbi->ie_length);
-		r->ie_len = wbi->ie_length;
-
-		wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
-	}
-
-	wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
-		   "BSSes)",
-		   wsr->buflen, (unsigned long) ap_num);
-	
-	os_free(buf);
-	return res;
-	}
-
-static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
-					      int reason_code)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wlc_deauth_t wdt;
-	wdt.val = reason_code;
-	os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
-	wdt.res = 0x7fff;
-	return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
-			      sizeof(wdt));
-}
-
-static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
-					    int reason_code)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	return broadcom_ioctl(drv, WLC_DISASSOC, NULL, 0);
-}
-
-static int
-wpa_driver_broadcom_associate(void *priv,
-			      struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wlc_ssid_t s;
-	int infra = 1;
-	int auth = 0;
-	int wsec = 4;
-	int dummy;
-	int wpa_auth;
-	int ret;
-
-	ret = wpa_driver_broadcom_set_drop_unencrypted(
-		drv, params->drop_unencrypted);
-
-	s.SSID_len = params->ssid_len;
-	os_memcpy(s.SSID, params->ssid, params->ssid_len);
-
-	switch (params->pairwise_suite) {
-	case CIPHER_WEP40:
-	case CIPHER_WEP104:
-		wsec = 1;
-		break;
-
-	case CIPHER_TKIP:
-		wsec = 2;
-		break;
-
-	case CIPHER_CCMP:
-		wsec = 4;
-		break;
-
-	default:
-		wsec = 0;
-		break;
-	}
-
-	switch (params->key_mgmt_suite) {
-	case KEY_MGMT_802_1X:
-		wpa_auth = 1;
-		break;
-
-	case KEY_MGMT_PSK:
-		wpa_auth = 2;
-		break;
-
-	default:
-		wpa_auth = 255;
-		break;
-	}
-
-	/* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
-	 * group_suite, key_mgmt_suite);
-	 * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
-	 * wl join uses wlc_sec_wep here, not wlc_set_wsec */
-
-	if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
-			   sizeof(wpa_auth)) < 0 ||
-	    broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
-		return -1;
-
-	return ret;
-}
-
-const struct wpa_driver_ops wpa_driver_broadcom_ops = {
-	.name = "broadcom",
-	.desc = "Broadcom wl.o driver",
-	.get_bssid = wpa_driver_broadcom_get_bssid,
-	.get_ssid = wpa_driver_broadcom_get_ssid,
-	.set_key = wpa_driver_broadcom_set_key,
-	.init = wpa_driver_broadcom_init,
-	.deinit = wpa_driver_broadcom_deinit,
-	.set_countermeasures = wpa_driver_broadcom_set_countermeasures,
-	.scan2 = wpa_driver_broadcom_scan,
-	.get_scan_results2 = wpa_driver_broadcom_get_scan_results,
-	.deauthenticate = wpa_driver_broadcom_deauthenticate,
-	.disassociate = wpa_driver_broadcom_disassociate,
-	.associate = wpa_driver_broadcom_associate,
-};
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
new file mode 100644
index 0000000..26ca8d6
--- /dev/null
+++ b/src/drivers/driver_common.c
@@ -0,0 +1,90 @@
+/*
+ * Common driver-related functions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include "utils/common.h"
+#include "driver.h"
+
+void wpa_scan_results_free(struct wpa_scan_results *res)
+{
+	size_t i;
+
+	if (res == NULL)
+		return;
+
+	for (i = 0; i < res->num; i++)
+		os_free(res->res[i]);
+	os_free(res->res);
+	os_free(res);
+}
+
+
+const char * event_to_string(enum wpa_event_type event)
+{
+#define E2S(n) case EVENT_ ## n: return #n
+	switch (event) {
+	E2S(ASSOC);
+	E2S(DISASSOC);
+	E2S(MICHAEL_MIC_FAILURE);
+	E2S(SCAN_RESULTS);
+	E2S(ASSOCINFO);
+	E2S(INTERFACE_STATUS);
+	E2S(PMKID_CANDIDATE);
+	E2S(STKSTART);
+	E2S(TDLS);
+	E2S(FT_RESPONSE);
+	E2S(IBSS_RSN_START);
+	E2S(AUTH);
+	E2S(DEAUTH);
+	E2S(ASSOC_REJECT);
+	E2S(AUTH_TIMED_OUT);
+	E2S(ASSOC_TIMED_OUT);
+	E2S(FT_RRB_RX);
+	E2S(WPS_BUTTON_PUSHED);
+	E2S(TX_STATUS);
+	E2S(RX_FROM_UNKNOWN);
+	E2S(RX_MGMT);
+	E2S(RX_ACTION);
+	E2S(REMAIN_ON_CHANNEL);
+	E2S(CANCEL_REMAIN_ON_CHANNEL);
+	E2S(MLME_RX);
+	E2S(RX_PROBE_REQ);
+	E2S(NEW_STA);
+	E2S(EAPOL_RX);
+	E2S(SIGNAL_CHANGE);
+	E2S(INTERFACE_ENABLED);
+	E2S(INTERFACE_DISABLED);
+	E2S(CHANNEL_LIST_CHANGED);
+	E2S(INTERFACE_UNAVAILABLE);
+	E2S(BEST_CHANNEL);
+	E2S(UNPROT_DEAUTH);
+	E2S(UNPROT_DISASSOC);
+	E2S(STATION_LOW_ACK);
+	E2S(P2P_DEV_FOUND);
+	E2S(P2P_GO_NEG_REQ_RX);
+	E2S(P2P_GO_NEG_COMPLETED);
+	E2S(P2P_PROV_DISC_REQUEST);
+	E2S(P2P_PROV_DISC_RESPONSE);
+	E2S(P2P_SD_REQUEST);
+	E2S(P2P_SD_RESPONSE);
+	E2S(IBSS_PEER_LOST);
+	E2S(DRIVER_GTK_REKEY);
+	E2S(SCHED_SCAN_STOPPED);
+	E2S(DRIVER_CLIENT_POLL_OK);
+	E2S(EAPOL_TX_STATUS);
+	}
+
+	return "UNKNOWN";
+#undef E2S
+}
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index e855c1b..8fc0efd 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -15,7 +15,7 @@
 #include "includes.h"
 #include <sys/ioctl.h>
 
-#include "wireless_copy.h"
+#include "linux_wext.h"
 #include "common.h"
 #include "driver.h"
 #include "driver_wext.h"
@@ -23,8 +23,6 @@
 #include "driver_hostap.h"
 
 
-#ifdef HOSTAPD
-
 #include <net/if_arp.h>
 #include <netpacket/packet.h>
 
@@ -32,6 +30,7 @@
 #include "netlink.h"
 #include "linux_ioctl.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 
 
 /* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X
@@ -84,8 +83,8 @@
 
 	sa = hdr->addr2;
 	os_memset(&event, 0, sizeof(event));
-	event.rx_from_unknown.frame = buf;
-	event.rx_from_unknown.len = len;
+	event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
+	event.rx_from_unknown.addr = sa;
 	wpa_supplicant_event(drv->hapd, EVENT_RX_FROM_UNKNOWN, &event);
 
 	pos = (u8 *) (hdr + 1);
@@ -148,7 +147,6 @@
 {
 	struct ieee80211_hdr *hdr;
 	u16 fc, extra_len, type, stype;
-	unsigned char *extra = NULL;
 	size_t data_len = len;
 	int ver;
 	union wpa_event_data event;
@@ -185,7 +183,6 @@
 			return;
 		}
 		len -= extra_len + 2;
-		extra = buf + len;
 	} else if (ver == 1 || ver == 2) {
 		handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0);
 		return;
@@ -273,7 +270,7 @@
 }
 
 
-static int hostap_send_mlme(void *priv, const u8 *msg, size_t len)
+static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack)
 {
 	struct hostap_driver_data *drv = priv;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
@@ -322,7 +319,7 @@
 	pos += 2;
 	memcpy(pos, data, data_len);
 
-	res = hostap_send_mlme(drv, (u8 *) hdr, len);
+	res = hostap_send_mlme(drv, (u8 *) hdr, len, 0);
 	if (res < 0) {
 		wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
 			   "failed: %d (%s)",
@@ -1054,7 +1051,26 @@
 	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
 	mgmt.u.deauth.reason_code = host_to_le16(reason);
 	return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
-				sizeof(mgmt.u.deauth));
+				sizeof(mgmt.u.deauth), 0);
+}
+
+
+static int hostap_set_freq(void *priv, struct hostapd_freq_params *freq)
+{
+	struct hostap_driver_data *drv = priv;
+	struct iwreq iwr;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+	iwr.u.freq.m = freq->channel;
+	iwr.u.freq.e = 0;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+		perror("ioctl[SIOCSIWFREQ]");
+		return -1;
+	}
+
+	return 0;
 }
 
 
@@ -1072,7 +1088,7 @@
 	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
 	mgmt.u.disassoc.reason_code = host_to_le16(reason);
 	return  hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
-				 sizeof(mgmt.u.disassoc));
+				 sizeof(mgmt.u.disassoc), 0);
 }
 
 
@@ -1126,492 +1142,38 @@
 	return mode;
 }
 
-#else /* HOSTAPD */
 
-struct wpa_driver_hostap_data {
-	void *wext; /* private data for driver_wext */
-	void *ctx;
-	char ifname[IFNAMSIZ + 1];
-	int sock;
-	int current_mode; /* infra/adhoc */
-};
-
-
-static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg);
-
-
-static int hostapd_ioctl(struct wpa_driver_hostap_data *drv,
-			 struct prism2_hostapd_param *param,
-			 int len, int show_err)
+static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr,
+					  const u8 *addr, int qos)
 {
-	struct iwreq iwr;
+	struct ieee80211_hdr hdr;
 
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) param;
-	iwr.u.data.length = len;
+	os_memset(&hdr, 0, sizeof(hdr));
 
-	if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
-		int ret = errno;
-		if (show_err)
-			perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
-		return ret;
-	}
+	/*
+	 * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
+	 * but it is apparently not retried so TX Exc events
+	 * are not received for it.
+	 * This is the reason the driver overrides the default
+	 * handling.
+	 */
+	hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA,
+					 WLAN_FC_STYPE_DATA);
 
-	return 0;
+	hdr.frame_control |=
+		host_to_le16(WLAN_FC_FROMDS);
+	os_memcpy(hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+	os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+	os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+	hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0);
 }
 
 
-static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data *drv,
-					const u8 *wpa_ie, size_t wpa_ie_len)
-{
-	struct prism2_hostapd_param *param;
-	int res;
-	size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
-	if (blen < sizeof(*param))
-		blen = sizeof(*param);
-
-	param = os_zalloc(blen);
-	if (param == NULL)
-		return -1;
-
-	param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
-	param->u.generic_elem.len = wpa_ie_len;
-	os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
-	res = hostapd_ioctl(drv, param, blen, 1);
-
-	os_free(param);
-
-	return res;
-}
-
-
-static int prism2param(struct wpa_driver_hostap_data *drv, int param,
-		       int value)
-{
-	struct iwreq iwr;
-	int *i, ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	i = (int *) iwr.u.name;
-	*i++ = param;
-	*i++ = value;
-
-	if (ioctl(drv->sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
-		perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
-		ret = -1;
-	}
-	return ret;
-}
-
-
-static int wpa_driver_hostap_set_wpa(void *priv, int enabled)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	int ret = 0;
-
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-
-	if (!enabled && wpa_driver_hostap_set_wpa_ie(drv, NULL, 0) < 0)
-		ret = -1;
-	if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, enabled ? 2 : 0) < 0)
-		ret = -1;
-	if (prism2param(drv, PRISM2_PARAM_WPA, enabled) < 0)
-		ret = -1;
-
-	return ret;
-}
-
-
-static void show_set_key_error(struct prism2_hostapd_param *param)
-{
-	switch (param->u.crypt.err) {
-	case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
-		wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
-			   param->u.crypt.alg);
-		wpa_printf(MSG_INFO, "You may need to load kernel module to "
-			   "register that algorithm.");
-		wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
-			   "WEP.");
-		break;
-	case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
-		wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
-			   MAC2STR(param->sta_addr));
-		break;
-	case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
-		wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
-		break;
-	case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
-		wpa_printf(MSG_INFO, "Key setting failed.");
-		break;
-	case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
-		wpa_printf(MSG_INFO, "TX key index setting failed.");
-		break;
-	case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
-		wpa_printf(MSG_INFO, "Card configuration failed.");
-		break;
-	}
-}
-
-
-static int wpa_driver_hostap_set_key(const char *ifname, void *priv,
-				     enum wpa_alg alg, const u8 *addr,
-				     int key_idx, int set_tx,
-				     const u8 *seq, size_t seq_len,
-				     const u8 *key, size_t key_len)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	struct prism2_hostapd_param *param;
-	u8 *buf;
-	size_t blen;
-	int ret = 0;
-	char *alg_name;
-
-	switch (alg) {
-	case WPA_ALG_NONE:
-		alg_name = "none";
-		break;
-	case WPA_ALG_WEP:
-		alg_name = "WEP";
-		break;
-	case WPA_ALG_TKIP:
-		alg_name = "TKIP";
-		break;
-	case WPA_ALG_CCMP:
-		alg_name = "CCMP";
-		break;
-	default:
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
-		   "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-
-	if (seq_len > 8)
-		return -2;
-
-	blen = sizeof(*param) + key_len;
-	buf = os_zalloc(blen);
-	if (buf == NULL)
-		return -1;
-
-	param = (struct prism2_hostapd_param *) buf;
-	param->cmd = PRISM2_SET_ENCRYPTION;
-	/* TODO: In theory, STA in client mode can use five keys; four default
-	 * keys for receiving (with keyidx 0..3) and one individual key for
-	 * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
-	 * keyidx 0 is reserved for this unicast use and default keys can only
-	 * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
-	 * This should be fine for more or less all cases, but for completeness
-	 * sake, the driver could be enhanced to support the missing key. */
-#if 0
-	if (addr == NULL)
-		os_memset(param->sta_addr, 0xff, ETH_ALEN);
-	else
-		os_memcpy(param->sta_addr, addr, ETH_ALEN);
-#else
-	os_memset(param->sta_addr, 0xff, ETH_ALEN);
-#endif
-	os_strlcpy((char *) param->u.crypt.alg, alg_name,
-		   HOSTAP_CRYPT_ALG_NAME_LEN);
-	param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
-	param->u.crypt.idx = key_idx;
-	if (seq)
-		os_memcpy(param->u.crypt.seq, seq, seq_len);
-	param->u.crypt.key_len = key_len;
-	os_memcpy((u8 *) (param + 1), key, key_len);
-
-	if (hostapd_ioctl(drv, param, blen, 1)) {
-		wpa_printf(MSG_WARNING, "Failed to set encryption.");
-		show_set_key_error(param);
-		ret = -1;
-	}
-	os_free(buf);
-
-	return ret;
-}
-
-
-static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return prism2param(drv, PRISM2_PARAM_TKIP_COUNTERMEASURES, enabled);
-}
-
-
-static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv,
-				   int type)
-{
-	struct iwreq iwr;
-	int *i, ret = 0;
-
-	wpa_printf(MSG_DEBUG, "%s: type=%d", __FUNCTION__, type);
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	i = (int *) iwr.u.name;
-	*i++ = type;
-
-	if (ioctl(drv->sock, PRISM2_IOCTL_RESET, &iwr) < 0) {
-	        perror("ioctl[PRISM2_IOCTL_RESET]");
-	        ret = -1;
-	}
-	return ret;
-}
-
-
-static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data *drv,
-				  const u8 *addr, int cmd, int reason_code)
-{
-	struct prism2_hostapd_param param;
-	int ret;
-
-	/* There does not seem to be a better way of deauthenticating or
-	 * disassociating with Prism2/2.5/3 than sending the management frame
-	 * and then resetting the Port0 to make sure both the AP and the STA
-	 * end up in disconnected state. */
-	os_memset(&param, 0, sizeof(param));
-	param.cmd = PRISM2_HOSTAPD_MLME;
-	os_memcpy(param.sta_addr, addr, ETH_ALEN);
-	param.u.mlme.cmd = cmd;
-	param.u.mlme.reason_code = reason_code;
-	ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
-	if (ret == 0) {
-		os_sleep(0, 100000);
-		ret = wpa_driver_hostap_reset(drv, 2);
-	}
-	return ret;
-}
-
-
-static int wpa_driver_hostap_deauthenticate(void *priv, const u8 *addr,
-					    int reason_code)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DEAUTH,
-				      reason_code);
-}
-
-
-static int wpa_driver_hostap_disassociate(void *priv, const u8 *addr,
-					  int reason_code)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DISASSOC,
-				      reason_code);
-}
-
-
-static int
-wpa_driver_hostap_associate(void *priv,
-			    struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	int ret = 0;
-	int allow_unencrypted_eapol;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED,
-			params->drop_unencrypted) < 0)
-		ret = -1;
-	if (wpa_driver_hostap_set_auth_alg(drv, params->auth_alg) < 0)
-		ret = -1;
-	if (params->mode != drv->current_mode) {
-		/* At the moment, Host AP driver requires host_roaming=2 for
-		 * infrastructure mode and host_roaming=0 for adhoc. */
-		if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING,
-				params->mode == IEEE80211_MODE_IBSS ? 0 : 2) <
-		    0) {
-			wpa_printf(MSG_DEBUG, "%s: failed to set host_roaming",
-				   __func__);
-		}
-		drv->current_mode = params->mode;
-	}
-
-	if (prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
-			params->key_mgmt_suite != KEY_MGMT_NONE) < 0)
-		ret = -1;
-	if (wpa_driver_hostap_set_wpa_ie(drv, params->wpa_ie,
-					 params->wpa_ie_len) < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_mode(drv->wext, params->mode) < 0)
-		ret = -1;
-	if (params->freq &&
-	    wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
-	    < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
-		ret = -1;
-
-	/* Allow unencrypted EAPOL messages even if pairwise keys are set when
-	 * not using WPA. IEEE 802.1X specifies that these frames are not
-	 * encrypted, but WPA encrypts them when pairwise keys are in use. */
-	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-	    params->key_mgmt_suite == KEY_MGMT_PSK)
-		allow_unencrypted_eapol = 0;
-	else
-		allow_unencrypted_eapol = 1;
-	
-	if (prism2param(drv, PRISM2_PARAM_IEEE_802_1X,
-			allow_unencrypted_eapol) < 0) {
-		wpa_printf(MSG_DEBUG, "hostap: Failed to configure "
-			   "ieee_802_1x param");
-		/* Ignore this error.. driver_hostap.c can also be used with
-		 * other drivers that do not support this prism2_param. */
-	}
-
-	return ret;
-}
-
-
-static int wpa_driver_hostap_scan(void *priv,
-				  struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	struct prism2_hostapd_param param;
-	int ret;
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	if (ssid == NULL) {
-		/* Use standard Linux Wireless Extensions ioctl if possible
-		 * because some drivers using hostap code in wpa_supplicant
-		 * might not support Host AP specific scan request (with SSID
-		 * info). */
-		return wpa_driver_wext_scan(drv->wext, params);
-	}
-
-	if (ssid_len > 32)
-		ssid_len = 32;
-
-	os_memset(&param, 0, sizeof(param));
-	param.cmd = PRISM2_HOSTAPD_SCAN_REQ;
-	param.u.scan_req.ssid_len = ssid_len;
-	os_memcpy(param.u.scan_req.ssid, ssid, ssid_len);
-	ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
-
-	/* Not all drivers generate "scan completed" wireless event, so try to
-	 * read results after a timeout. */
-	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
-			     drv->ctx);
-	eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv->wext,
-			       drv->ctx);
-
-	return ret;
-}
-
-
-static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	int algs = 0;
-
-	if (auth_alg & WPA_AUTH_ALG_OPEN)
-		algs |= 1;
-	if (auth_alg & WPA_AUTH_ALG_SHARED)
-		algs |= 2;
-	if (auth_alg & WPA_AUTH_ALG_LEAP)
-		algs |= 4;
-	if (algs == 0)
-		algs = 1; /* at least one algorithm should be set */
-
-	return prism2param(drv, PRISM2_PARAM_AP_AUTH_ALGS, algs);
-}
-
-
-static int wpa_driver_hostap_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_hostap_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static struct wpa_scan_results * wpa_driver_hostap_get_scan_results(void *priv)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_hostap_set_operstate(void *priv, int state)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static void * wpa_driver_hostap_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_hostap_data *drv;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->wext = wpa_driver_wext_init(ctx, ifname);
-	if (drv->wext == NULL) {
-		os_free(drv);
-		return NULL;
-	}
-
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0) {
-		perror("socket");
-		wpa_driver_wext_deinit(drv->wext);
-		os_free(drv);
-		return NULL;
-	}
-
-	if (os_strncmp(ifname, "wlan", 4) == 0) {
-		/*
-		 * Host AP driver may use both wlan# and wifi# interface in
-		 * wireless events.
-		 */
-		char ifname2[IFNAMSIZ + 1];
-		os_strlcpy(ifname2, ifname, sizeof(ifname2));
-		os_memcpy(ifname2, "wifi", 4);
-		wpa_driver_wext_alternative_ifindex(drv->wext, ifname2);
-	}
-
-	wpa_driver_hostap_set_wpa(drv, 1);
-
-	return drv;
-}
-
-
-static void wpa_driver_hostap_deinit(void *priv)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	wpa_driver_hostap_set_wpa(drv, 0);
-	wpa_driver_wext_deinit(drv->wext);
-	close(drv->sock);
-	os_free(drv);
-}
-
-#endif /* HOSTAPD */
-
-
 const struct wpa_driver_ops wpa_driver_hostap_ops = {
 	.name = "hostap",
 	.desc = "Host AP driver (Intersil Prism2/2.5/3)",
 	.set_key = wpa_driver_hostap_set_key,
-#ifdef HOSTAPD
 	.hapd_init = hostap_init,
 	.hapd_deinit = hostap_driver_deinit,
 	.set_ieee8021x = hostap_set_ieee8021x,
@@ -1632,17 +1194,6 @@
 	.sta_clear_stats = hostap_sta_clear_stats,
 	.get_hw_feature_data = hostap_get_hw_feature_data,
 	.set_ap_wps_ie = hostap_set_ap_wps_ie,
-#else /* HOSTAPD */
-	.get_bssid = wpa_driver_hostap_get_bssid,
-	.get_ssid = wpa_driver_hostap_get_ssid,
-	.set_countermeasures = wpa_driver_hostap_set_countermeasures,
-	.scan2 = wpa_driver_hostap_scan,
-	.get_scan_results2 = wpa_driver_hostap_get_scan_results,
-	.deauthenticate = wpa_driver_hostap_deauthenticate,
-	.disassociate = wpa_driver_hostap_disassociate,
-	.associate = wpa_driver_hostap_associate,
-	.init = wpa_driver_hostap_init,
-	.deinit = wpa_driver_hostap_deinit,
-	.set_operstate = wpa_driver_hostap_set_operstate,
-#endif /* HOSTAPD */
+	.set_freq = hostap_set_freq,
+	.poll_client = wpa_driver_hostap_poll_client,
 };
diff --git a/src/drivers/driver_iphone.m b/src/drivers/driver_iphone.m
deleted file mode 100644
index 8213fda..0000000
--- a/src/drivers/driver_iphone.m
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
- * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#define Boolean __DummyBoolean
-#include <CoreFoundation/CoreFoundation.h>
-#undef Boolean
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-
-#include "MobileApple80211.h"
-
-struct wpa_driver_iphone_data {
-	void *ctx;
-	Apple80211Ref wireless_ctx;
-	CFArrayRef scan_results;
-	int ctrl_power;
-};
-
-
-static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
-{
-	const void *res;
-	CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
-						    kCFStringEncodingMacRoman);
-	if (str == NULL)
-		return NULL;
-
-	res = CFDictionaryGetValue(dict, str);
-	CFRelease(str);
-	return res;
-}
-
-
-static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	CFDataRef data;
-	int err, len;
-
-	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
-				  &data);
-	if (err != 0) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
-			   "failed: %d", err);
-		return -1;
-	}
-
-	len = CFDataGetLength(data);
-	if (len > 32) {
-		CFRelease(data);
-		return -1;
-	}
-	os_memcpy(ssid, CFDataGetBytePtr(data), len);
-	CFRelease(data);
-
-	return len;
-}
-
-
-static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	CFStringRef data;
-	int err;
-	int a1, a2, a3, a4, a5, a6;
-
-	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
-				  &data);
-	if (err != 0) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
-			   "failed: %d", err);
-		return -1;
-	}
-
-	sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
-	       "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
-	bssid[0] = a1;
-	bssid[1] = a2;
-	bssid[2] = a3;
-	bssid[3] = a4;
-	bssid[4] = a5;
-	bssid[5] = a6;
-
-	CFRelease(data);
-
-	return 0;
-}
-
-
-static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	int err;
-
-	if (drv->scan_results) {
-		CFRelease(drv->scan_results);
-		drv->scan_results = NULL;
-	}
-
-	err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
-			   err);
-		return -1;
-	}
-
-	eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
-			       drv->ctx);
-	return 0;
-}
-
-
-static int wpa_driver_iphone_get_scan_results(void *priv,
-					      struct wpa_scan_result *results,
-					      size_t max_size)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	size_t i, num;
-
-	if (drv->scan_results == NULL)
-		return 0;
-
-	num = CFArrayGetCount(drv->scan_results);
-	if (num > max_size)
-		num = max_size;
-	os_memset(results, 0, num * sizeof(struct wpa_scan_result));
-
-	for (i = 0; i < num; i++) {
-		struct wpa_scan_result *res = &results[i];
-		CFDictionaryRef dict =
-			CFArrayGetValueAtIndex(drv->scan_results, i);
-		CFDataRef data;
-		CFStringRef str;
-		CFNumberRef num;
-		int val;
-
-		data = cfdict_get_key_str(dict, "SSID");
-		if (data) {
-			res->ssid_len = CFDataGetLength(data);
-			if (res->ssid_len > 32)
-				res->ssid_len = 32;
-			os_memcpy(res->ssid, CFDataGetBytePtr(data),
-				  res->ssid_len);
-		}
-
-		str = cfdict_get_key_str(dict, "BSSID");
-		if (str) {
-			int a1, a2, a3, a4, a5, a6;
-			sscanf(CFStringGetCStringPtr(
-				       str, kCFStringEncodingMacRoman),
-			       "%x:%x:%x:%x:%x:%x",
-			       &a1, &a2, &a3, &a4, &a5, &a6);
-			res->bssid[0] = a1;
-			res->bssid[1] = a2;
-			res->bssid[2] = a3;
-			res->bssid[3] = a4;
-			res->bssid[4] = a5;
-			res->bssid[5] = a6;
-		}
-
-		num = cfdict_get_key_str(dict, "CAPABILITIES");
-		if (num) {
-			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-				res->caps = val;
-		}
-
-		num = cfdict_get_key_str(dict, "CHANNEL");
-		if (num) {
-			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-				res->freq = 2407 + val * 5;
-		}
-
-		num = cfdict_get_key_str(dict, "RSSI");
-		if (num) {
-			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-				res->level = val;
-		}
-
-		num = cfdict_get_key_str(dict, "NOISE");
-		if (num) {
-			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-				res->noise = val;
-		}
-
-		data = cfdict_get_key_str(dict, "IE");
-		if (data) {
-			u8 *ptr = (u8 *) CFDataGetBytePtr(data);
-			int len = CFDataGetLength(data);
-			u8 *pos = ptr, *end = ptr + len;
-
-			while (pos + 2 < end) {
-				if (pos + 2 + pos[1] > end)
-					break;
-				if (pos[0] == WLAN_EID_RSN &&
-				    pos[1] <= SSID_MAX_WPA_IE_LEN) {
-					os_memcpy(res->rsn_ie, pos,
-						  2 + pos[1]);
-					res->rsn_ie_len = 2 + pos[1];
-				}
-				if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
-				    pos[1] > 4 && pos[2] == 0x00 &&
-				    pos[3] == 0x50 && pos[4] == 0xf2 &&
-				    pos[5] == 0x01) {
-					os_memcpy(res->wpa_ie, pos,
-						  2 + pos[1]);
-					res->wpa_ie_len = 2 + pos[1];
-				}
-
-				pos = pos + 2 + pos[1];
-			}
-		}
-	}
-
-	return num;
-}
-
-
-static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_iphone_data *drv = eloop_ctx;
-	u8 bssid[ETH_ALEN];
-
-	if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
-		eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
-				       drv, drv->ctx);
-		return;
-	}
-
-	wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
-}
-
-
-static int wpa_driver_iphone_associate(
-	void *priv, struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	int i, num, err;
-	size_t ssid_len;
-	CFDictionaryRef bss = NULL;
-
-	/*
-	 * TODO: Consider generating parameters instead of just using an entry
-	 * from scan results in order to support ap_scan=2.
-	 */
-
-	if (drv->scan_results == NULL) {
-		wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
-			   "associate");
-		return -1;
-	}
-
-	num = CFArrayGetCount(drv->scan_results);
-
-	for (i = 0; i < num; i++) {
-		CFDictionaryRef dict =
-			CFArrayGetValueAtIndex(drv->scan_results, i);
-		CFDataRef data;
-
-		data = cfdict_get_key_str(dict, "SSID");
-		if (data == NULL)
-			continue;
-
-		ssid_len = CFDataGetLength(data);
-		if (ssid_len != params->ssid_len ||
-		    os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
-		    != 0)
-			continue;
-
-		bss = dict;
-		break;
-	}
-
-	if (bss == NULL) {
-		wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
-			   "results - cannot associate");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
-		   "from scan results");
-
-	err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
-			   "%d", err);
-		return -1;
-	}
-
-	/*
-	 * Driver is actually already associated; report association from an
-	 * eloop callback.
-	 */
-	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
-	eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
-			       drv->ctx);
-
-	return 0;
-}
-
-
-static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr,
-				     int key_idx, int set_tx, const u8 *seq,
-				     size_t seq_len, const u8 *key,
-				     size_t key_len)
-{
-	/*
-	 * TODO: Need to either support configuring PMK for 4-way handshake or
-	 * PTK for TKIP/CCMP.
-	 */
-	return -1;
-}
-
-
-static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-	os_memset(capa, 0, sizeof(*capa));
-
-	capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-	capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
-		WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
-	capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
-		WPA_DRIVER_AUTH_LEAP;
-	capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
-
-	return 0;
-}
-
-
-static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_iphone_data *drv;
-	int err;
-	char power;
-	CFStringRef name;
-	CFDictionaryRef dict;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->ctx = ctx;
-	err = Apple80211Open(&drv->wireless_ctx);
-	if (err) {
-		wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
-			   err);
-		os_free(drv);
-		return NULL;
-	}
-
-	name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
-					 kCFStringEncodingISOLatin1);
-	if (name == NULL) {
-		wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
-		Apple80211Close(drv->wireless_ctx);
-		os_free(drv);
-		return NULL;
-	}
-
-	err = Apple80211BindToInterface(drv->wireless_ctx, name);
-	CFRelease(name);
-
-	if (err) {
-		wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
-			   "failed: %d", err);
-		Apple80211Close(drv->wireless_ctx);
-		os_free(drv);
-		return NULL;
-	}
-
-	err = Apple80211GetPower(drv->wireless_ctx, &power);
-	if (err)
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
-			   err);
-
-	wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
-
-	if (!power) {
-		drv->ctrl_power = 1;
-		err = Apple80211SetPower(drv->wireless_ctx, 1);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
-				   "failed: %d", err);
-			Apple80211Close(drv->wireless_ctx);
-			os_free(drv);
-			return NULL;
-		}
-	}
-
-	err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
-	if (err == 0) {
-		CFShow(dict);
-		CFRelease(dict);
-	} else {
-		printf("Apple80211GetInfoCopy: %d\n", err);
-	}
-
-	return drv;
-}
-
-
-static void wpa_driver_iphone_deinit(void *priv)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	int err;
-
-	eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
-	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
-
-	if (drv->ctrl_power) {
-		wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
-		err = Apple80211SetPower(drv->wireless_ctx, 0);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
-				   "failed: %d", err);
-		}
-	}
-
-	err = Apple80211Close(drv->wireless_ctx);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
-			   err);
-	}
-
-	if (drv->scan_results)
-		CFRelease(drv->scan_results);
-
-	os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_iphone_ops = {
-	.name = "iphone",
-	.desc = "iPhone/iPod touch Apple80211 driver",
-	.get_ssid = wpa_driver_iphone_get_ssid,
-	.get_bssid = wpa_driver_iphone_get_bssid,
-	.init = wpa_driver_iphone_init,
-	.deinit = wpa_driver_iphone_deinit,
-	.scan = wpa_driver_iphone_scan,
-	.get_scan_results = wpa_driver_iphone_get_scan_results,
-	.associate = wpa_driver_iphone_associate,
-	.set_key = wpa_driver_iphone_set_key,
-	.get_capa = wpa_driver_iphone_get_capa,
-};
diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c
index 630fbf4..edb086f 100644
--- a/src/drivers/driver_madwifi.c
+++ b/src/drivers/driver_madwifi.c
@@ -27,7 +27,7 @@
 #include "driver_wext.h"
 #include "eloop.h"
 #include "common/ieee802_11_defs.h"
-#include "wireless_copy.h"
+#include "linux_wext.h"
 
 /*
  * Avoid conflicts with wpa_supplicant definitions by undefining a definition.
@@ -71,8 +71,6 @@
 
 #define WPA_KEY_RSC_LEN 8
 
-#ifdef HOSTAPD
-
 #include "priv_netlink.h"
 #include "netlink.h"
 #include "linux_ioctl.h"
@@ -734,6 +732,8 @@
 
 	os_memset(&event, 0, sizeof(event));
 	event.rx_probe_req.sa = mgmt->sa;
+	event.rx_probe_req.da = mgmt->da;
+	event.rx_probe_req.bssid = mgmt->bssid;
 	event.rx_probe_req.ie = mgmt->u.probe_req.variable;
 	event.rx_probe_req.ie_len =
 		len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
@@ -804,6 +804,24 @@
 #define madwifi_set_ap_wps_ie NULL
 #endif /* CONFIG_WPS */
 
+static int madwifi_set_freq(void *priv, struct hostapd_freq_params *freq)
+{
+	struct madwifi_driver_data *drv = priv;
+	struct iwreq iwr;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+	iwr.u.freq.m = freq->channel;
+	iwr.u.freq.e = 0;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+		perror("ioctl[SIOCSIWFREQ]");
+		return -1;
+	}
+
+	return 0;
+}
+
 static void
 madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
 {
@@ -1274,554 +1292,11 @@
 	return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
 }
 
-#else /* HOSTAPD */
-
-struct wpa_driver_madwifi_data {
-	void *wext; /* private data for driver_wext */
-	void *ctx;
-	char ifname[IFNAMSIZ + 1];
-	int sock;
-};
-
-static int wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg);
-static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
-					       size_t ies_len);
-
-
-static int
-set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
-	     int show_err)
-{
-	struct iwreq iwr;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	if (len < IFNAMSIZ &&
-	    op != IEEE80211_IOCTL_SET_APPIEBUF) {
-		/*
-		 * Argument data fits inline; put it there.
-		 */
-		os_memcpy(iwr.u.name, data, len);
-	} else {
-		/*
-		 * Argument data too big for inline transfer; setup a
-		 * parameter block instead; the kernel will transfer
-		 * the data for the driver.
-		 */
-		iwr.u.data.pointer = data;
-		iwr.u.data.length = len;
-	}
-
-	if (ioctl(drv->sock, op, &iwr) < 0) {
-		if (show_err) {
-#ifdef MADWIFI_NG
-			int first = IEEE80211_IOCTL_SETPARAM;
-			int last = IEEE80211_IOCTL_KICKMAC;
-			static const char *opnames[] = {
-				"ioctl[IEEE80211_IOCTL_SETPARAM]",
-				"ioctl[IEEE80211_IOCTL_GETPARAM]",
-				"ioctl[IEEE80211_IOCTL_SETMODE]",
-				"ioctl[IEEE80211_IOCTL_GETMODE]",
-				"ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
-				"ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
-				"ioctl[IEEE80211_IOCTL_SETCHANLIST]",
-				"ioctl[IEEE80211_IOCTL_GETCHANLIST]",
-				"ioctl[IEEE80211_IOCTL_CHANSWITCH]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
-				"ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_GETCHANINFO]",
-				"ioctl[IEEE80211_IOCTL_SETOPTIE]",
-				"ioctl[IEEE80211_IOCTL_GETOPTIE]",
-				"ioctl[IEEE80211_IOCTL_SETMLME]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_SETKEY]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_DELKEY]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_ADDMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_DELMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_WDSMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_WDSDELMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_KICKMAC]",
-			};
-#else /* MADWIFI_NG */
-			int first = IEEE80211_IOCTL_SETPARAM;
-			int last = IEEE80211_IOCTL_CHANLIST;
-			static const char *opnames[] = {
-				"ioctl[IEEE80211_IOCTL_SETPARAM]",
-				"ioctl[IEEE80211_IOCTL_GETPARAM]",
-				"ioctl[IEEE80211_IOCTL_SETKEY]",
-				"ioctl[IEEE80211_IOCTL_GETKEY]",
-				"ioctl[IEEE80211_IOCTL_DELKEY]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_SETMLME]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_SETOPTIE]",
-				"ioctl[IEEE80211_IOCTL_GETOPTIE]",
-				"ioctl[IEEE80211_IOCTL_ADDMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_DELMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_CHANLIST]",
-			};
-#endif /* MADWIFI_NG */
-			int idx = op - first;
-			if (first <= op && op <= last &&
-			    idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
-			    && opnames[idx])
-				perror(opnames[idx]);
-			else
-				perror("ioctl[unknown???]");
-		}
-		return -1;
-	}
-	return 0;
-}
-
-static int
-set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
-	      int show_err)
-{
-	struct iwreq iwr;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.mode = op;
-	os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg));
-
-	if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
-		if (show_err) 
-			perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
-		return -1;
-	}
-	return 0;
-}
-
-static int
-wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
-			      const u8 *wpa_ie, size_t wpa_ie_len)
-{
-	struct iwreq iwr;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	/* NB: SETOPTIE is not fixed-size so must not be inlined */
-	iwr.u.data.pointer = (void *) wpa_ie;
-	iwr.u.data.length = wpa_ie_len;
-
-	if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
-		perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
-		return -1;
-	}
-	return 0;
-}
-
-static int
-wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
-			   const u8 *addr)
-{
-	struct ieee80211req_del_key wk;
-
-	wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
-	os_memset(&wk, 0, sizeof(wk));
-	wk.idk_keyix = key_idx;
-	if (addr != NULL)
-		os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
-
-	return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
-}
-
-static int
-wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-			   const u8 *addr, int key_idx, int set_tx,
-			   const u8 *seq, size_t seq_len,
-			   const u8 *key, size_t key_len)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct ieee80211req_key wk;
-	char *alg_name;
-	u_int8_t cipher;
-
-	if (alg == WPA_ALG_NONE)
-		return wpa_driver_madwifi_del_key(drv, key_idx, addr);
-
-	switch (alg) {
-	case WPA_ALG_WEP:
-		if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
-					      ETH_ALEN) == 0) {
-			/*
-			 * madwifi did not seem to like static WEP key
-			 * configuration with IEEE80211_IOCTL_SETKEY, so use
-			 * Linux wireless extensions ioctl for this.
-			 */
-			return wpa_driver_wext_set_key(ifname, drv->wext, alg,
-						       addr, key_idx, set_tx,
-						       seq, seq_len,
-						       key, key_len);
-		}
-		alg_name = "WEP";
-		cipher = IEEE80211_CIPHER_WEP;
-		break;
-	case WPA_ALG_TKIP:
-		alg_name = "TKIP";
-		cipher = IEEE80211_CIPHER_TKIP;
-		break;
-	case WPA_ALG_CCMP:
-		alg_name = "CCMP";
-		cipher = IEEE80211_CIPHER_AES_CCM;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
-			__FUNCTION__, alg);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
-		   "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-
-	if (seq_len > sizeof(u_int64_t)) {
-		wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big",
-			   __FUNCTION__, (unsigned long) seq_len);
-		return -2;
-	}
-	if (key_len > sizeof(wk.ik_keydata)) {
-		wpa_printf(MSG_DEBUG, "%s: key length %lu too big",
-			   __FUNCTION__, (unsigned long) key_len);
-		return -3;
-	}
-
-	os_memset(&wk, 0, sizeof(wk));
-	wk.ik_type = cipher;
-	wk.ik_flags = IEEE80211_KEY_RECV;
-	if (addr == NULL ||
-	    os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
-		wk.ik_flags |= IEEE80211_KEY_GROUP;
-	if (set_tx) {
-		wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
-		os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
-	} else
-		os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
-	wk.ik_keyix = key_idx;
-	wk.ik_keylen = key_len;
-#ifdef WORDS_BIGENDIAN
-	if (seq) {
-		size_t i;
-		u8 tmp[WPA_KEY_RSC_LEN];
-		os_memset(tmp, 0, sizeof(tmp));
-		for (i = 0; i < seq_len; i++)
-			tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i];
-		os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN);
-	}
-#else /* WORDS_BIGENDIAN */
-	if (seq)
-		os_memcpy(&wk.ik_keyrsc, seq, seq_len);
-#endif /* WORDS_BIGENDIAN */
-	os_memcpy(wk.ik_keydata, key, key_len);
-
-	return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
-}
-
-static int
-wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1);
-}
-
-static int
-wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	mlme.im_op = IEEE80211_MLME_DEAUTH;
-	mlme.im_reason = reason_code;
-	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
-	return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
-}
-
-static int
-wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	mlme.im_op = IEEE80211_MLME_DISASSOC;
-	mlme.im_reason = reason_code;
-	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
-	return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
-}
-
-static int
-wpa_driver_madwifi_associate(void *priv,
-			     struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret = 0, privacy = 1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED,
-			  params->drop_unencrypted, 1) < 0)
-		ret = -1;
-	if (wpa_driver_madwifi_set_auth_alg(drv, params->auth_alg) < 0)
-		ret = -1;
-
-	/*
-	 * NB: Don't need to set the freq or cipher-related state as
-	 *     this is implied by the bssid which is used to locate
-	 *     the scanned node state which holds it.  The ssid is
-	 *     needed to disambiguate an AP that broadcasts multiple
-	 *     ssid's but uses the same bssid.
-	 */
-	/* XXX error handling is wrong but unclear what to do... */
-	if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie,
-					  params->wpa_ie_len) < 0)
-		ret = -1;
-
-	if (params->pairwise_suite == CIPHER_NONE &&
-	    params->group_suite == CIPHER_NONE &&
-	    params->key_mgmt_suite == KEY_MGMT_NONE &&
-	    params->wpa_ie_len == 0)
-		privacy = 0;
-
-	if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
-		ret = -1;
-
-	if (params->wpa_ie_len &&
-	    set80211param(drv, IEEE80211_PARAM_WPA,
-			  params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0)
-		ret = -1;
-
-	if (params->bssid == NULL) {
-		/* ap_scan=2 mode - driver takes care of AP selection and
-		 * roaming */
-		/* FIX: this does not seem to work; would probably need to
-		 * change something in the driver */
-		if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0)
-			ret = -1;
-
-		if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
-					     params->ssid_len) < 0)
-			ret = -1;
-	} else {
-		if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
-			ret = -1;
-		if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
-					     params->ssid_len) < 0)
-			ret = -1;
-		os_memset(&mlme, 0, sizeof(mlme));
-		mlme.im_op = IEEE80211_MLME_ASSOC;
-		os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
-		if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
-				 sizeof(mlme), 1) < 0) {
-			wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed",
-				   __func__);
-			ret = -1;
-		}
-	}
-
-	return ret;
-}
-
-static int
-wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	int authmode;
-
-	if ((auth_alg & WPA_AUTH_ALG_OPEN) &&
-	    (auth_alg & WPA_AUTH_ALG_SHARED))
-		authmode = IEEE80211_AUTH_AUTO;
-	else if (auth_alg & WPA_AUTH_ALG_SHARED)
-		authmode = IEEE80211_AUTH_SHARED;
-	else
-		authmode = IEEE80211_AUTH_OPEN;
-
-	return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
-}
-
-static int
-wpa_driver_madwifi_scan(void *priv, struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	wpa_driver_madwifi_set_probe_req_ie(drv, params->extra_ies,
-					    params->extra_ies_len);
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	/* set desired ssid before scan */
-	/* FIX: scan should not break the current association, so using
-	 * set_ssid may not be the best way of doing this.. */
-	if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0)
-		ret = -1;
-
-	if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
-		perror("ioctl[SIOCSIWSCAN]");
-		ret = -1;
-	}
-
-	/*
-	 * madwifi delivers a scan complete event so no need to poll, but
-	 * register a backup timeout anyway to make sure that we recover even
-	 * if the driver does not send this event for any reason. This timeout
-	 * will only be used if the event is not delivered (event handler will
-	 * cancel the timeout).
-	 */
-	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
-			     drv->ctx);
-	eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
-			       drv->ctx);
-
-	return ret;
-}
-
-static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static struct wpa_scan_results *
-wpa_driver_madwifi_get_scan_results(void *priv)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_madwifi_set_operstate(void *priv, int state)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
-					       size_t ies_len)
-{
-	struct ieee80211req_getset_appiebuf *probe_req_ie;
-	int ret;
-
-	probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len);
-	if (probe_req_ie == NULL)
-		return -1;
-
-	probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ;
-	probe_req_ie->app_buflen = ies_len;
-	os_memcpy(probe_req_ie->app_buf, ies, ies_len);
-
-	ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie,
-			   sizeof(struct ieee80211req_getset_appiebuf) +
-			   ies_len, 1);
-
-	os_free(probe_req_ie);
-
-	return ret;
-}
-
-
-static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_madwifi_data *drv;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->wext = wpa_driver_wext_init(ctx, ifname);
-	if (drv->wext == NULL)
-		goto fail;
-
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0)
-		goto fail2;
-
-	if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
-			   "roaming", __FUNCTION__);
-		goto fail3;
-	}
-
-	if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
-			   __FUNCTION__);
-		goto fail3;
-	}
-
-	return drv;
-
-fail3:
-	close(drv->sock);
-fail2:
-	wpa_driver_wext_deinit(drv->wext);
-fail:
-	os_free(drv);
-	return NULL;
-}
-
-
-static void wpa_driver_madwifi_deinit(void *priv)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-
-	if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE",
-			   __FUNCTION__);
-	}
-	if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based "
-			   "roaming", __FUNCTION__);
-	}
-	if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy "
-			   "flag", __FUNCTION__);
-	}
-	if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to disable WPA",
-			   __FUNCTION__);
-	}
-
-	wpa_driver_wext_deinit(drv->wext);
-
-	close(drv->sock);
-	os_free(drv);
-}
-
-#endif /* HOSTAPD */
-
 
 const struct wpa_driver_ops wpa_driver_madwifi_ops = {
 	.name			= "madwifi",
 	.desc			= "MADWIFI 802.11 support (Atheros, etc.)",
 	.set_key		= wpa_driver_madwifi_set_key,
-#ifdef HOSTAPD
 	.hapd_init		= madwifi_init,
 	.hapd_deinit		= madwifi_deinit,
 	.set_ieee8021x		= madwifi_set_ieee8021x,
@@ -1840,17 +1315,5 @@
 	.sta_clear_stats        = madwifi_sta_clear_stats,
 	.commit			= madwifi_commit,
 	.set_ap_wps_ie		= madwifi_set_ap_wps_ie,
-#else /* HOSTAPD */
-	.get_bssid		= wpa_driver_madwifi_get_bssid,
-	.get_ssid		= wpa_driver_madwifi_get_ssid,
-	.init			= wpa_driver_madwifi_init,
-	.deinit			= wpa_driver_madwifi_deinit,
-	.set_countermeasures	= wpa_driver_madwifi_set_countermeasures,
-	.scan2			= wpa_driver_madwifi_scan,
-	.get_scan_results2	= wpa_driver_madwifi_get_scan_results,
-	.deauthenticate		= wpa_driver_madwifi_deauthenticate,
-	.disassociate		= wpa_driver_madwifi_disassociate,
-	.associate		= wpa_driver_madwifi_associate,
-	.set_operstate		= wpa_driver_madwifi_set_operstate,
-#endif /* HOSTAPD */
+	.set_freq		= madwifi_set_freq,
 };
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index aeb7304..dbe9a28 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -3213,119 +3213,33 @@
 }
 
 
-const struct wpa_driver_ops wpa_driver_ndis_ops = {
-	"ndis",
-	"Windows NDIS driver",
-	wpa_driver_ndis_get_bssid,
-	wpa_driver_ndis_get_ssid,
-	wpa_driver_ndis_set_key,
-	wpa_driver_ndis_init,
-	wpa_driver_ndis_deinit,
-	NULL /* set_param */,
-	NULL /* set_countermeasures */,
-	wpa_driver_ndis_deauthenticate,
-	wpa_driver_ndis_disassociate,
-	wpa_driver_ndis_associate,
-	wpa_driver_ndis_add_pmkid,
-	wpa_driver_ndis_remove_pmkid,
-	wpa_driver_ndis_flush_pmkid,
-	wpa_driver_ndis_get_capa,
-	wpa_driver_ndis_poll,
-	wpa_driver_ndis_get_ifname,
-	wpa_driver_ndis_get_mac_addr,
-	NULL /* send_eapol */,
-	NULL /* set_operstate */,
-	NULL /* mlme_setprotection */,
-	NULL /* get_hw_feature_data */,
-	NULL /* set_channel */,
-	NULL /* set_ssid */,
-	NULL /* set_bssid */,
-	NULL /* send_mlme */,
-	NULL /* mlme_add_sta */,
-	NULL /* mlme_remove_sta */,
-	NULL /* update_ft_ies */,
-	NULL /* send_ft_action */,
-	wpa_driver_ndis_get_scan_results,
-	NULL /* set_country */,
-	NULL /* global_init */,
-	NULL /* global_deinit */,
-	NULL /* init2 */,
-	wpa_driver_ndis_get_interfaces,
-	wpa_driver_ndis_scan,
-	NULL /* authenticate */,
-	NULL /* set_beacon */,
-	NULL /* hapd_init */,
-	NULL /* hapd_deinit */,
-	NULL /* set_ieee8021x */,
-	NULL /* set_privacy */,
-	NULL /* get_seqnum */,
-	NULL /* flush */,
-	NULL /* set_generic_elem */,
-	NULL /* read_sta_data */,
-	NULL /* hapd_send_eapol */,
-	NULL /* sta_deauth */,
-	NULL /* sta_disassoc */,
-	NULL /* sta_remove */,
-	NULL /* hapd_get_ssid */,
-	NULL /* hapd_set_ssid */,
-	NULL /* hapd_set_countermeasures */,
-	NULL /* sta_add */,
-	NULL /* get_inact_sec */,
-	NULL /* sta_clear_stats */,
-	NULL /* set_freq */,
-	NULL /* set_rts */,
-	NULL /* set_frag */,
-	NULL /* sta_set_flags */,
-	NULL /* set_rate_sets */,
-	NULL /* set_cts_protect */,
-	NULL /* set_preamble */,
-	NULL /* set_short_slot_time */,
-	NULL /* set_tx_queue_params */,
-	NULL /* valid_bss_mask */,
-	NULL /* if_add */,
-	NULL /* if_remove */,
-	NULL /* set_sta_vlan */,
-	NULL /* commit */,
-	NULL /* send_ether */,
-	NULL /* set_radius_acl_auth */,
-	NULL /* set_radius_acl_expire */,
-	NULL /* set_ht_params */,
-	NULL /* set_ap_wps_ie */,
-	NULL /* set_supp_port */,
-	NULL /* set_wds_sta */,
-	NULL /* send_action */,
-	NULL /* send_action_cancel_wait */,
-	NULL /* remain_on_channel */,
-	NULL /* cancel_remain_on_channel */,
-	NULL /* probe_req_report */,
-	NULL /* disable_11b_rates */,
-	NULL /* deinit_ap */,
-	NULL /* suspend */,
-	NULL /* resume */,
-	NULL /* signal_monitor */,
-	NULL /* send_frame */,
-	NULL /* shared_freq */,
-	NULL /* get_noa */,
-	NULL /* set_noa */,
-	NULL /* set_p2p_powersave */,
-	NULL /* ampdu */,
-	NULL /* set_intra_bss */,
-	NULL /* get_radio_name */,
-	NULL /* p2p_find */,
-	NULL /* p2p_stop_find */,
-	NULL /* p2p_listen */,
-	NULL /* p2p_connect */,
-	NULL /* wps_success_cb */,
-	NULL /* p2p_group_formation_failed */,
-	NULL /* p2p_set_params */,
-	NULL /* p2p_prov_disc_req */,
-	NULL /* p2p_sd_request */,
-	NULL /* p2p_sd_cancel_request */,
-	NULL /* p2p_sd_response */,
-	NULL /* p2p_service_update */,
-	NULL /* p2p_reject */,
-	NULL /* p2p_invite */,
-	NULL /* send_tdls_mgmt */,
-	NULL /* tdls_oper */,
-	NULL /* signal_poll */
-};
+static const char *ndis_drv_name = "ndis";
+static const char *ndis_drv_desc = "Windows NDIS driver";
+
+struct wpa_driver_ops wpa_driver_ndis_ops;
+
+void driver_ndis_init_ops(void)
+{
+	os_memset(&wpa_driver_ndis_ops, 0, sizeof(wpa_driver_ndis_ops));
+	wpa_driver_ndis_ops.name = ndis_drv_name;
+	wpa_driver_ndis_ops.desc = ndis_drv_desc;
+	wpa_driver_ndis_ops.get_bssid = wpa_driver_ndis_get_bssid;
+	wpa_driver_ndis_ops.get_ssid = wpa_driver_ndis_get_ssid;
+	wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key;
+	wpa_driver_ndis_ops.init = wpa_driver_ndis_init;
+	wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit;
+	wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate;
+	wpa_driver_ndis_ops.disassociate = wpa_driver_ndis_disassociate;
+	wpa_driver_ndis_ops.associate = wpa_driver_ndis_associate;
+	wpa_driver_ndis_ops.add_pmkid = wpa_driver_ndis_add_pmkid;
+	wpa_driver_ndis_ops.remove_pmkid = wpa_driver_ndis_remove_pmkid;
+	wpa_driver_ndis_ops.flush_pmkid = wpa_driver_ndis_flush_pmkid;
+	wpa_driver_ndis_ops.get_capa = wpa_driver_ndis_get_capa;
+	wpa_driver_ndis_ops.poll = wpa_driver_ndis_poll;
+	wpa_driver_ndis_ops.get_ifname = wpa_driver_ndis_get_ifname;
+	wpa_driver_ndis_ops.get_mac_addr = wpa_driver_ndis_get_mac_addr;
+	wpa_driver_ndis_ops.get_scan_results2 =
+		wpa_driver_ndis_get_scan_results;
+	wpa_driver_ndis_ops.get_interfaces = wpa_driver_ndis_get_interfaces;
+	wpa_driver_ndis_ops.scan2 = wpa_driver_ndis_scan;
+}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index df309c5..a00f703 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -28,21 +28,47 @@
 #include <linux/rtnetlink.h>
 #include <netpacket/packet.h>
 #include <linux/filter.h>
+#include <linux/errqueue.h>
 #include "nl80211_copy.h"
 
 #include "common.h"
 #include "eloop.h"
 #include "utils/list.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "l2_packet/l2_packet.h"
 #include "netlink.h"
 #include "linux_ioctl.h"
 #include "radiotap.h"
 #include "radiotap_iter.h"
 #include "rfkill.h"
 #include "driver.h"
-#if defined(ANDROID_BRCM_P2P_PATCH) && !defined(HOSTAPD)
+#if defined(ANDROID_P2P) && !defined(HOSTAPD)
 #include "wpa_supplicant_i.h"
 #endif
+#ifndef SO_WIFI_STATUS
+# if defined(__sparc__)
+#  define SO_WIFI_STATUS	0x0025
+# elif defined(__parisc__)
+#  define SO_WIFI_STATUS	0x4022
+# else
+#  define SO_WIFI_STATUS	41
+# endif
+
+# define SCM_WIFI_STATUS	SO_WIFI_STATUS
+#endif
+
+#ifndef SO_EE_ORIGIN_TXSTATUS
+#define SO_EE_ORIGIN_TXSTATUS	4
+#endif
+
+#ifndef PACKET_TX_TIMESTAMP
+#define PACKET_TX_TIMESTAMP	16
+#endif
+
+#ifdef ANDROID
+#include "android_drv.h"
+#endif /* ANDROID */
 #ifdef CONFIG_LIBNL20
 /* libnl 2.0 compatibility code */
 #define nl_handle nl_sock
@@ -91,6 +117,37 @@
 #endif /* CONFIG_LIBNL20 */
 
 
+static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
+{
+	struct nl_handle *handle;
+
+	handle = nl80211_handle_alloc(cb);
+	if (handle == NULL) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+			   "callbacks (%s)", dbg);
+		return NULL;
+	}
+
+	if (genl_connect(handle)) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
+			   "netlink (%s)", dbg);
+		nl80211_handle_destroy(handle);
+		return NULL;
+	}
+
+	return handle;
+}
+
+
+static void nl_destroy_handles(struct nl_handle **handle)
+{
+	if (*handle == NULL)
+		return;
+	nl80211_handle_destroy(*handle);
+	*handle = NULL;
+}
+
+
 #ifndef IFF_LOWER_UP
 #define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
 #endif
@@ -107,8 +164,30 @@
 
 struct nl80211_global {
 	struct dl_list interfaces;
+	int if_add_ifindex;
+	struct netlink_data *netlink;
+	struct nl_cb *nl_cb;
+	struct nl_handle *nl;
+	int nl80211_id;
+	int ioctl_sock; /* socket for ioctl() use */
+
+	struct nl_handle *nl_event;
 };
 
+struct nl80211_wiphy_data {
+	struct dl_list list;
+	struct dl_list bsss;
+	struct dl_list drvs;
+
+	struct nl_handle *nl_beacons;
+	struct nl_cb *nl_cb;
+
+	int wiphy_idx;
+};
+
+static void nl80211_global_deinit(void *priv);
+static void wpa_driver_nl80211_deinit(void *priv);
+
 struct i802_bss {
 	struct wpa_driver_nl80211_data *drv;
 	struct i802_bss *next;
@@ -118,19 +197,28 @@
 	unsigned int beacon_set:1;
 	unsigned int added_if_into_bridge:1;
 	unsigned int added_bridge:1;
+
+	u8 addr[ETH_ALEN];
+
+	int freq;
+
+	struct nl_handle *nl_preq, *nl_mgmt;
+	struct nl_cb *nl_cb;
+
+	struct nl80211_wiphy_data *wiphy_data;
+	struct dl_list wiphy_list;
 };
 
 struct wpa_driver_nl80211_data {
 	struct nl80211_global *global;
 	struct dl_list list;
-	u8 addr[ETH_ALEN];
+	struct dl_list wiphy_list;
 	char phyname[32];
 	void *ctx;
-	struct netlink_data *netlink;
-	int ioctl_sock; /* socket for ioctl() use */
 	int ifindex;
 	int if_removed;
 	int if_disabled;
+	int ignore_if_down_event;
 	struct rfkill_data *rfkill;
 	struct wpa_driver_capa capa;
 	int has_capability;
@@ -139,42 +227,43 @@
 
 	int scan_complete_events;
 
-	struct nl_handle *nl_handle;
-	struct nl_handle *nl_handle_event;
-	struct nl_handle *nl_handle_preq;
-	struct nl_cache *nl_cache;
-	struct nl_cache *nl_cache_event;
-	struct nl_cache *nl_cache_preq;
 	struct nl_cb *nl_cb;
-	struct genl_family *nl80211;
 
 	u8 auth_bssid[ETH_ALEN];
 	u8 bssid[ETH_ALEN];
 	int associated;
 	u8 ssid[32];
 	size_t ssid_len;
-	int nlmode;
-	int ap_scan_as_station;
+	enum nl80211_iftype nlmode;
+	enum nl80211_iftype ap_scan_as_station;
 	unsigned int assoc_freq;
 
 	int monitor_sock;
 	int monitor_ifidx;
-	int no_monitor_iface_capab;
-	int disable_11b_rates;
+	int monitor_refcount;
 
+	unsigned int disabled_11b_rates:1;
 	unsigned int pending_remain_on_chan:1;
+	unsigned int in_interface_list:1;
+	unsigned int device_ap_sme:1;
+	unsigned int poll_command_supported:1;
+	unsigned int data_tx_status:1;
+	unsigned int scan_for_auth:1;
+	unsigned int retry_auth:1;
+	unsigned int use_monitor:1;
 
 	u64 remain_on_chan_cookie;
 	u64 send_action_cookie;
 
 	unsigned int last_mgmt_freq;
-	unsigned int ap_oper_freq;
 
 	struct wpa_driver_scan_filter *filter_ssids;
 	size_t num_filter_ssids;
 
 	struct i802_bss first_bss;
 
+	int eapol_tx_sock;
+
 #ifdef HOSTAPD
 	int eapol_sock; /* socket for EAPOL frames */
 
@@ -185,12 +274,27 @@
 	int last_freq;
 	int last_freq_ht;
 #endif /* HOSTAPD */
+
+	/* From failed authentication command */
+	int auth_freq;
+	u8 auth_bssid_[ETH_ALEN];
+	u8 auth_ssid[32];
+	size_t auth_ssid_len;
+	int auth_alg;
+	u8 *auth_ie;
+	size_t auth_ie_len;
+	u8 auth_wep_key[4][16];
+	size_t auth_wep_key_len[4];
+	int auth_wep_tx_keyidx;
+	int auth_local_state_change;
+	int auth_p2p;
 };
 
 
 static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
 					    void *timeout_ctx);
-static int wpa_driver_nl80211_set_mode(void *priv, int mode);
+static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+				       enum nl80211_iftype nlmode);
 static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
 static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
@@ -198,22 +302,28 @@
 				   int local_state_change);
 static void nl80211_remove_monitor_interface(
 	struct wpa_driver_nl80211_data *drv);
-static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
+static int nl80211_send_frame_cmd(struct i802_bss *bss,
 				  unsigned int freq, unsigned int wait,
-				  const u8 *buf, size_t buf_len, u64 *cookie);
+				  const u8 *buf, size_t buf_len, u64 *cookie,
+				  int no_cck, int no_ack, int offchanok);
 static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID
+static int android_pno_start(struct i802_bss *bss,
+			     struct wpa_driver_scan_params *params);
+static int android_pno_stop(struct i802_bss *bss);
+#endif /* ANDROID */
+#ifdef ANDROID_P2P
 static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
 				  enum wpa_event_type type,
 				  const u8 *frame, size_t len);
-int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
 int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
 int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
 int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
 				  const struct wpabuf *proberesp,
 				  const struct wpabuf *assocresp);
-#endif
 
+#endif
 #ifdef HOSTAPD
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
@@ -222,12 +332,19 @@
 					enum wpa_driver_if_type type,
 					const char *ifname);
 #else /* HOSTAPD */
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+}
+
+static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+}
+
+static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 {
 	return 0;
 }
 #endif /* HOSTAPD */
-
 #ifdef ANDROID
 extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
 					 size_t buf_len);
@@ -238,12 +355,36 @@
 				     int ifindex, int disabled);
 
 static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
+static int wpa_driver_nl80211_authenticate_retry(
+	struct wpa_driver_nl80211_data *drv);
+
+
+static int is_ap_interface(enum nl80211_iftype nlmode)
+{
+	return (nlmode == NL80211_IFTYPE_AP ||
+		nlmode == NL80211_IFTYPE_P2P_GO);
+}
+
+
+static int is_sta_interface(enum nl80211_iftype nlmode)
+{
+	return (nlmode == NL80211_IFTYPE_STATION ||
+		nlmode == NL80211_IFTYPE_P2P_CLIENT);
+}
+
+
+static int is_p2p_interface(enum nl80211_iftype nlmode)
+{
+	return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
+		nlmode == NL80211_IFTYPE_P2P_GO);
+}
 
 
 struct nl80211_bss_info_arg {
 	struct wpa_driver_nl80211_data *drv;
 	struct wpa_scan_results *res;
 	unsigned int assoc_freq;
+	u8 assoc_bssid[ETH_ALEN];
 };
 
 static int bss_info_handler(struct nl_msg *msg, void *arg);
@@ -279,7 +420,7 @@
 }
 
 
-static int send_and_recv(struct wpa_driver_nl80211_data *drv,
+static int send_and_recv(struct nl80211_global *global,
 			 struct nl_handle *nl_handle, struct nl_msg *msg,
 			 int (*valid_handler)(struct nl_msg *, void *),
 			 void *valid_data)
@@ -287,7 +428,7 @@
 	struct nl_cb *cb;
 	int err = -ENOMEM;
 
-	cb = nl_cb_clone(drv->nl_cb);
+	cb = nl_cb_clone(global->nl_cb);
 	if (!cb)
 		goto out;
 
@@ -314,13 +455,22 @@
 }
 
 
+static int send_and_recv_msgs_global(struct nl80211_global *global,
+				     struct nl_msg *msg,
+				     int (*valid_handler)(struct nl_msg *, void *),
+				     void *valid_data)
+{
+	return send_and_recv(global, global->nl, msg, valid_handler,
+			     valid_data);
+}
+
 int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
 			      struct nl_msg *msg,
 			      int (*valid_handler)(struct nl_msg *, void *),
 			      void *valid_data)
 {
-	return send_and_recv(drv, drv->nl_handle, msg, valid_handler,
-			     valid_data);
+	return send_and_recv(drv->global, drv->global->nl, msg,
+			     valid_handler, valid_data);
 }
 
 
@@ -361,7 +511,7 @@
 }
 
 
-static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
+static int nl_get_multicast_id(struct nl80211_global *global,
 			       const char *family, const char *group)
 {
 	struct nl_msg *msg;
@@ -371,11 +521,11 @@
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
-	genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),
+	genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
 		    0, 0, CTRL_CMD_GETFAMILY, 0);
 	NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
 
-	ret = send_and_recv_msgs(drv, msg, family_handler, &res);
+	ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
 	msg = NULL;
 	if (ret == 0)
 		ret = res.id;
@@ -386,6 +536,235 @@
 }
 
 
+static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
+			  struct nl_msg *msg, int flags, uint8_t cmd)
+{
+	return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
+			   0, flags, cmd, 0);
+}
+
+
+struct wiphy_idx_data {
+	int wiphy_idx;
+};
+
+
+static int netdev_info_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct wiphy_idx_data *info = arg;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (tb[NL80211_ATTR_WIPHY])
+		info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_get_wiphy_index(struct i802_bss *bss)
+{
+	struct nl_msg *msg;
+	struct wiphy_idx_data data = {
+		.wiphy_idx = -1,
+	};
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+	if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+		return data.wiphy_idx;
+	msg = NULL;
+nla_put_failure:
+	nlmsg_free(msg);
+	return -1;
+}
+
+
+static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
+				    struct nl80211_wiphy_data *w)
+{
+	struct nl_msg *msg;
+	int ret = -1;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx);
+
+	ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
+			   "failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+		goto nla_put_failure;
+	}
+	ret = 0;
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
+{
+	struct nl80211_wiphy_data *w = eloop_ctx;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Beacon event message available");
+
+	nl_recvmsgs(handle, w->nl_cb);
+}
+
+
+static int process_beacon_event(struct nl_msg *msg, void *arg)
+{
+	struct nl80211_wiphy_data *w = arg;
+	struct wpa_driver_nl80211_data *drv;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	union wpa_event_data event;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (gnlh->cmd != NL80211_CMD_FRAME) {
+		wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
+			   gnlh->cmd);
+		return NL_SKIP;
+	}
+
+	if (!tb[NL80211_ATTR_FRAME])
+		return NL_SKIP;
+
+	dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
+			 wiphy_list) {
+		os_memset(&event, 0, sizeof(event));
+		event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
+		event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
+		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+	}
+
+	return NL_SKIP;
+}
+
+
+static struct nl80211_wiphy_data *
+nl80211_get_wiphy_data_ap(struct i802_bss *bss)
+{
+	static DEFINE_DL_LIST(nl80211_wiphys);
+	struct nl80211_wiphy_data *w;
+	int wiphy_idx, found = 0;
+	struct i802_bss *tmp_bss;
+
+	if (bss->wiphy_data != NULL)
+		return bss->wiphy_data;
+
+	wiphy_idx = nl80211_get_wiphy_index(bss);
+
+	dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
+		if (w->wiphy_idx == wiphy_idx)
+			goto add;
+	}
+
+	/* alloc new one */
+	w = os_zalloc(sizeof(*w));
+	if (w == NULL)
+		return NULL;
+	w->wiphy_idx = wiphy_idx;
+	dl_list_init(&w->bsss);
+	dl_list_init(&w->drvs);
+
+	w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!w->nl_cb) {
+		os_free(w);
+		return NULL;
+	}
+	nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+	nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event,
+		  w);
+
+	w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
+					 "wiphy beacons");
+	if (w->nl_beacons == NULL) {
+		os_free(w);
+		return NULL;
+	}
+
+	if (nl80211_register_beacons(bss->drv, w)) {
+		nl_destroy_handles(&w->nl_beacons);
+		os_free(w);
+		return NULL;
+	}
+
+	eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
+				 nl80211_recv_beacons, w, w->nl_beacons);
+
+	dl_list_add(&nl80211_wiphys, &w->list);
+
+add:
+	/* drv entry for this bss already there? */
+	dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+		if (tmp_bss->drv == bss->drv) {
+			found = 1;
+			break;
+		}
+	}
+	/* if not add it */
+	if (!found)
+		dl_list_add(&w->drvs, &bss->drv->wiphy_list);
+
+	dl_list_add(&w->bsss, &bss->wiphy_list);
+	bss->wiphy_data = w;
+	return w;
+}
+
+
+static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
+{
+	struct nl80211_wiphy_data *w = bss->wiphy_data;
+	struct i802_bss *tmp_bss;
+	int found = 0;
+
+	if (w == NULL)
+		return;
+	bss->wiphy_data = NULL;
+	dl_list_del(&bss->wiphy_list);
+
+	/* still any for this drv present? */
+	dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+		if (tmp_bss->drv == bss->drv) {
+			found = 1;
+			break;
+		}
+	}
+	/* if not remove it */
+	if (!found)
+		dl_list_del(&bss->drv->wiphy_list);
+
+	if (!dl_list_empty(&w->bsss))
+		return;
+
+	eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
+
+	nl_cb_put(w->nl_cb);
+	nl_destroy_handles(&w->nl_beacons);
+	dl_list_del(&w->list);
+	os_free(w);
+}
+
+
 static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
 {
 	struct i802_bss *bss = priv;
@@ -479,17 +858,33 @@
 }
 
 
+static struct wpa_driver_nl80211_data *
+nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
+{
+	struct wpa_driver_nl80211_data *drv;
+	dl_list_for_each(drv, &global->interfaces,
+			 struct wpa_driver_nl80211_data, list) {
+		if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
+		    have_ifidx(drv, idx))
+			return drv;
+	}
+	return NULL;
+}
+
+
 static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
 						 struct ifinfomsg *ifi,
 						 u8 *buf, size_t len)
 {
-	struct wpa_driver_nl80211_data *drv = ctx;
+	struct nl80211_global *global = ctx;
+	struct wpa_driver_nl80211_data *drv;
 	int attrlen, rta_len;
 	struct rtattr *attr;
 	u32 brid = 0;
+	char namebuf[IFNAMSIZ];
 
-	if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len) &&
-	    !have_ifidx(drv, ifi->ifi_index)) {
+	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+	if (!drv) {
 		wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
 			   "ifindex %d", ifi->ifi_index);
 		return;
@@ -504,15 +899,38 @@
 		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 
 	if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
+		if (if_indextoname(ifi->ifi_index, namebuf) &&
+		    linux_iface_up(drv->global->ioctl_sock,
+				   drv->first_bss.ifname) > 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
+				   "event since interface %s is up", namebuf);
+			return;
+		}
 		wpa_printf(MSG_DEBUG, "nl80211: Interface down");
-		drv->if_disabled = 1;
-		wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
+		if (drv->ignore_if_down_event) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
+				   "event generated by mode change");
+			drv->ignore_if_down_event = 0;
+		} else {
+			drv->if_disabled = 1;
+			wpa_supplicant_event(drv->ctx,
+					     EVENT_INTERFACE_DISABLED, NULL);
+		}
 	}
 
 	if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
-		wpa_printf(MSG_DEBUG, "nl80211: Interface up");
-		drv->if_disabled = 0;
-		wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
+		if (if_indextoname(ifi->ifi_index, namebuf) &&
+		    linux_iface_up(drv->global->ioctl_sock,
+				   drv->first_bss.ifname) == 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+				   "event since interface %s is down",
+				   namebuf);
+		} else {
+			wpa_printf(MSG_DEBUG, "nl80211: Interface up");
+			drv->if_disabled = 0;
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+					     NULL);
+		}
 	}
 
 	/*
@@ -524,7 +942,7 @@
 	if (drv->operstate == 1 &&
 	    (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
 	    !(ifi->ifi_flags & IFF_RUNNING))
-		netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+		netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
 				       -1, IF_OPER_UP);
 
 	attrlen = len;
@@ -541,16 +959,13 @@
 		attr = RTA_NEXT(attr, attrlen);
 	}
 
-#ifdef HOSTAPD
 	if (ifi->ifi_family == AF_BRIDGE && brid) {
 		/* device has been added to bridge */
-		char namebuf[IFNAMSIZ];
 		if_indextoname(brid, namebuf);
 		wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
 			   brid, namebuf);
 		add_ifidx(drv, brid);
 	}
-#endif /* HOSTAPD */
 }
 
 
@@ -558,11 +973,19 @@
 						 struct ifinfomsg *ifi,
 						 u8 *buf, size_t len)
 {
-	struct wpa_driver_nl80211_data *drv = ctx;
+	struct nl80211_global *global = ctx;
+	struct wpa_driver_nl80211_data *drv;
 	int attrlen, rta_len;
 	struct rtattr *attr;
 	u32 brid = 0;
 
+	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+	if (!drv) {
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for "
+			   "foreign ifindex %d", ifi->ifi_index);
+		return;
+	}
+
 	attrlen = len;
 	attr = (struct rtattr *) buf;
 
@@ -578,7 +1001,6 @@
 		attr = RTA_NEXT(attr, attrlen);
 	}
 
-#ifdef HOSTAPD
 	if (ifi->ifi_family == AF_BRIDGE && brid) {
 		/* device has been removed from bridge */
 		char namebuf[IFNAMSIZ];
@@ -587,7 +1009,6 @@
 			   "%s", brid, namebuf);
 		del_ifidx(drv, brid);
 	}
-#endif /* HOSTAPD */
 }
 
 
@@ -629,8 +1050,7 @@
 	if (!msg)
 		goto nla_put_failure;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
-		    NL80211_CMD_GET_SCAN, 0);
+	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
 	arg.drv = drv;
@@ -656,12 +1076,12 @@
 	const struct ieee80211_mgmt *mgmt;
 	union wpa_event_data event;
 	u16 status;
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
 	struct wpa_supplicant *wpa_s = drv->ctx;
 #endif
 
 	mgmt = (const struct ieee80211_mgmt *) frame;
-#if (defined (CONFIG_AP) || defined (HOSTAPD) ) && defined (ANDROID_BRCM_P2P_PATCH)
+#if (defined (CONFIG_AP) || defined (HOSTAPD) ) && defined (ANDROID_P2P)
 	if (drv->nlmode == NL80211_IFTYPE_AP || drv->nlmode == NL80211_IFTYPE_P2P_GO) {
 		if (len < 24 + sizeof(mgmt->u.assoc_req)) {
 			wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
@@ -674,7 +1094,7 @@
 		event.assoc_info.req_ies_len = len - 24 - sizeof(mgmt->u.assoc_req);
 		event.assoc_info.addr = mgmt->sa;
 	} else {
-#endif	
+#endif
 	if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
 			   "frame");
@@ -708,7 +1128,7 @@
 	}
 
 	event.assoc_info.freq = drv->assoc_freq;
-#if (defined (CONFIG_AP) || defined(HOSTAPD)) && defined (ANDROID_BRCM_P2P_PATCH)
+#if (defined (CONFIG_AP) || defined(HOSTAPD)) && defined (ANDROID_P2P)
 	}
 #endif
 	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
@@ -765,6 +1185,29 @@
 }
 
 
+static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
+				  struct nlattr *reason, struct nlattr *addr)
+{
+	union wpa_event_data data;
+
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+		/*
+		 * Avoid reporting two disassociation events that could
+		 * confuse the core code.
+		 */
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+			   "event when using userspace SME");
+		return;
+	}
+
+	drv->associated = 0;
+	os_memset(&data, 0, sizeof(data));
+	if (reason)
+		data.disassoc_info.reason_code = nla_get_u16(reason);
+	wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
+}
+
+
 static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
 			       enum nl80211_commands cmd, struct nlattr *addr)
 {
@@ -819,7 +1262,7 @@
 		event.rx_action.data = &mgmt->u.action.category + 1;
 		event.rx_action.len = frame + len - event.rx_action.data;
 		wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
 	} else if (stype == WLAN_FC_STYPE_ASSOC_REQ) {
 		mlme_event_assoc(drv, frame, len);
 	} else if (stype == WLAN_FC_STYPE_DISASSOC) {
@@ -835,26 +1278,29 @@
 }
 
 
-static void mlme_event_action_tx_status(struct wpa_driver_nl80211_data *drv,
-					struct nlattr *cookie, const u8 *frame,
-					size_t len, struct nlattr *ack)
+static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
+				      struct nlattr *cookie, const u8 *frame,
+				      size_t len, struct nlattr *ack)
 {
 	union wpa_event_data event;
 	const struct ieee80211_hdr *hdr;
 	u16 fc;
-	u64 cookie_val;
 
-	if (!cookie)
-		return;
+	if (!is_ap_interface(drv->nlmode)) {
+		u64 cookie_val;
 
-	cookie_val = nla_get_u64(cookie);
-	wpa_printf(MSG_DEBUG, "nl80211: Action TX status: cookie=0%llx%s "
-		   "(ack=%d)",
-		   (long long unsigned int) cookie_val,
-		   cookie_val == drv->send_action_cookie ?
-		   " (match)" : " (unknown)", ack != NULL);
-	if (cookie_val != drv->send_action_cookie)
-		return;
+		if (!cookie)
+			return;
+
+		cookie_val = nla_get_u64(cookie);
+		wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
+			   " cookie=0%llx%s (ack=%d)",
+			   (long long unsigned int) cookie_val,
+			   cookie_val == drv->send_action_cookie ?
+			   " (match)" : " (unknown)", ack != NULL);
+		if (cookie_val != drv->send_action_cookie)
+			return;
+	}
 
 	hdr = (const struct ieee80211_hdr *) frame;
 	fc = le_to_host16(hdr->frame_control);
@@ -906,7 +1352,7 @@
 		reason_code = le_to_host16(mgmt->u.deauth.reason_code);
 
 	if (type == EVENT_DISASSOC) {
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
 		if (drv->nlmode == NL80211_IFTYPE_AP ||
 			drv->nlmode == NL80211_IFTYPE_P2P_GO) {
 			event.disassoc_info.addr = mgmt->sa;
@@ -920,7 +1366,7 @@
 				mgmt->u.disassoc.variable;
 		}
 	} else {
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
 		if (drv->nlmode == NL80211_IFTYPE_AP ||
 			drv->nlmode == NL80211_IFTYPE_P2P_GO) {
 		event.deauth_info.addr = mgmt->sa;
@@ -1011,8 +1457,8 @@
 		mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame));
 		break;
 	case NL80211_CMD_FRAME_TX_STATUS:
-		mlme_event_action_tx_status(drv, cookie, nla_data(frame),
-					    nla_len(frame), ack);
+		mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
+					  nla_len(frame), ack);
 		break;
 	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
 		mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
@@ -1117,7 +1563,8 @@
 	if (cookie != drv->remain_on_chan_cookie)
 		return; /* not for us */
 
-	drv->pending_remain_on_chan = !cancel_event;
+	if (cancel_event)
+		drv->pending_remain_on_chan = 0;
 
 	os_memset(&data, 0, sizeof(data));
 	data.remain_on_channel.freq = freq;
@@ -1139,6 +1586,14 @@
 	int freqs[MAX_REPORT_FREQS];
 	int num_freqs = 0;
 
+	if (drv->scan_for_auth) {
+		drv->scan_for_auth = 0;
+		wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
+			   "cfg80211 BSS entry");
+		wpa_driver_nl80211_authenticate_retry(drv);
+		return;
+	}
+
 	os_memset(&event, 0, sizeof(event));
 	info = &event.scan_info;
 	info->aborted = aborted;
@@ -1228,14 +1683,14 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_STATION, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
 
 	return send_and_recv_msgs(drv, msg, get_link_signal, sig);
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -1296,13 +1751,88 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    NLM_F_DUMP, NL80211_CMD_GET_SURVEY, 0);
+	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
 	return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
  nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+	static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+		[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+		[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+	};
+	struct wpa_scan_results *scan_results = arg;
+	struct wpa_scan_res *scan_res;
+	size_t i;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+		wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
+		return NL_SKIP;
+	}
+
+	if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+			     tb[NL80211_ATTR_SURVEY_INFO],
+			     survey_policy)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
+			   "attributes");
+		return NL_SKIP;
+	}
+
+	if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+		return NL_SKIP;
+
+	if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+		return NL_SKIP;
+
+	for (i = 0; i < scan_results->num; ++i) {
+		scan_res = scan_results->res[i];
+		if (!scan_res)
+			continue;
+		if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+		    scan_res->freq)
+			continue;
+		if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
+			continue;
+		scan_res->noise = (s8)
+			nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+		scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
+	}
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_get_noise_for_scan_results(
+	struct wpa_driver_nl80211_data *drv,
+	struct wpa_scan_results *scan_res)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
+				  scan_res);
+ nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -1385,8 +1915,7 @@
 	addr = nla_data(tb[NL80211_ATTR_MAC]);
 	wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
 
-	if (drv->nlmode == NL80211_IFTYPE_AP &&
-	    drv->no_monitor_iface_capab) {
+	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
 		u8 *ies = NULL;
 		size_t ies_len = 0;
 		if (tb[NL80211_ATTR_IE]) {
@@ -1419,8 +1948,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
 		   MAC2STR(addr));
 
-	if (drv->nlmode == NL80211_IFTYPE_AP &&
-	    drv->no_monitor_iface_capab) {
+	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
 		drv_event_disassoc(drv->ctx, addr);
 		return;
 	}
@@ -1434,38 +1962,138 @@
 }
 
 
-static int process_event(struct nl_msg *msg, void *arg)
+static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
+					struct nlattr **tb)
 {
-	struct wpa_driver_nl80211_data *drv = arg;
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
+	static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
+		[NL80211_REKEY_DATA_KEK] = {
+			.minlen = NL80211_KEK_LEN,
+			.maxlen = NL80211_KEK_LEN,
+		},
+		[NL80211_REKEY_DATA_KCK] = {
+			.minlen = NL80211_KCK_LEN,
+			.maxlen = NL80211_KCK_LEN,
+		},
+		[NL80211_REKEY_DATA_REPLAY_CTR] = {
+			.minlen = NL80211_REPLAY_CTR_LEN,
+			.maxlen = NL80211_REPLAY_CTR_LEN,
+		},
+	};
 	union wpa_event_data data;
 
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
+	if (!tb[NL80211_ATTR_MAC])
+		return;
+	if (!tb[NL80211_ATTR_REKEY_DATA])
+		return;
+	if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
+			     tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
+		return;
+	if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
+		return;
 
-	if (tb[NL80211_ATTR_IFINDEX]) {
-		int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
-		if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
-			wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
-				   " for foreign interface (ifindex %d)",
-				   gnlh->cmd, ifindex);
-			return NL_SKIP;
-		}
-	}
+	os_memset(&data, 0, sizeof(data));
+	data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
+	wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
+		   MAC2STR(data.driver_gtk_rekey.bssid));
+	data.driver_gtk_rekey.replay_ctr =
+		nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
+	wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
+		    data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
+	wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
+}
 
-	if (drv->ap_scan_as_station &&
-	    (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
-	     gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) {
+
+static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
+					  struct nlattr **tb)
+{
+	struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
+	static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
+		[NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
+		[NL80211_PMKSA_CANDIDATE_BSSID] = {
+			.minlen = ETH_ALEN,
+			.maxlen = ETH_ALEN,
+		},
+		[NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
+	};
+	union wpa_event_data data;
+
+	if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
+		return;
+	if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
+			     tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
+		return;
+	if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
+	    !cand[NL80211_PMKSA_CANDIDATE_BSSID])
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.pmkid_candidate.bssid,
+		  nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
+	data.pmkid_candidate.index =
+		nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
+	data.pmkid_candidate.preauth =
+		cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
+	wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+}
+
+
+static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
+				       struct nlattr **tb)
+{
+	union wpa_event_data data;
+
+	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.client_poll.addr,
+		  nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+	wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
+}
+
+
+static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
+				   int wds)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	union wpa_event_data event;
+
+	if (!tb[NL80211_ATTR_MAC])
+		return;
+
+	os_memset(&event, 0, sizeof(event));
+	event.rx_from_unknown.bssid = bss->addr;
+	event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
+	event.rx_from_unknown.wds = wds;
+
+	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
+				 int cmd, struct nlattr **tb)
+{
+	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
+	    (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
+	     cmd == NL80211_CMD_SCAN_ABORTED)) {
 		wpa_driver_nl80211_set_mode(&drv->first_bss,
-					    IEEE80211_MODE_AP);
-		drv->ap_scan_as_station = 0;
+					    drv->ap_scan_as_station);
+		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 	}
 
-	switch (gnlh->cmd) {
+	switch (cmd) {
 	case NL80211_CMD_TRIGGER_SCAN:
 		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
 		break;
+	case NL80211_CMD_START_SCHED_SCAN:
+		wpa_printf(MSG_DEBUG, "nl80211: Sched scan started");
+		break;
+	case NL80211_CMD_SCHED_SCAN_STOPPED:
+		wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped");
+		wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
+		break;
 	case NL80211_CMD_NEW_SCAN_RESULTS:
 		wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
 		drv->scan_complete_events = 1;
@@ -1473,6 +2101,11 @@
 				     drv->ctx);
 		send_scan_event(drv, 0, tb);
 		break;
+	case NL80211_CMD_SCHED_SCAN_RESULTS:
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: New sched scan results available");
+		send_scan_event(drv, 0, tb);
+		break;
 	case NL80211_CMD_SCAN_ABORTED:
 		wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
 		/*
@@ -1487,39 +2120,25 @@
 	case NL80211_CMD_ASSOCIATE:
 	case NL80211_CMD_DEAUTHENTICATE:
 	case NL80211_CMD_DISASSOCIATE:
-	case NL80211_CMD_FRAME:
 	case NL80211_CMD_FRAME_TX_STATUS:
 	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
 	case NL80211_CMD_UNPROT_DISASSOCIATE:
-		mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+		mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
 			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
 			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
 			   tb[NL80211_ATTR_COOKIE]);
 		break;
 	case NL80211_CMD_CONNECT:
 	case NL80211_CMD_ROAM:
-		mlme_event_connect(drv, gnlh->cmd,
+		mlme_event_connect(drv, cmd,
 				   tb[NL80211_ATTR_STATUS_CODE],
 				   tb[NL80211_ATTR_MAC],
 				   tb[NL80211_ATTR_REQ_IE],
 				   tb[NL80211_ATTR_RESP_IE]);
 		break;
 	case NL80211_CMD_DISCONNECT:
-		if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
-			/*
-			 * Avoid reporting two disassociation events that could
-			 * confuse the core code.
-			 */
-			wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
-				   "event when using userspace SME");
-			break;
-		}
-		drv->associated = 0;
-		os_memset(&data, 0, sizeof(data));
-		if (tb[NL80211_ATTR_REASON_CODE])
-			data.disassoc_info.reason_code =
-				nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
-		wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
+		mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
+				      tb[NL80211_ATTR_MAC]);
 		break;
 	case NL80211_CMD_MICHAEL_MIC_FAILURE:
 		mlme_event_michael_mic_failure(drv, tb);
@@ -1552,6 +2171,95 @@
 	case NL80211_CMD_DEL_STATION:
 		nl80211_del_station_event(drv, tb);
 		break;
+	case NL80211_CMD_SET_REKEY_OFFLOAD:
+		nl80211_rekey_offload_event(drv, tb);
+		break;
+	case NL80211_CMD_PMKSA_CANDIDATE:
+		nl80211_pmksa_candidate_event(drv, tb);
+		break;
+	case NL80211_CMD_PROBE_CLIENT:
+		nl80211_client_probe_event(drv, tb);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
+			   "(cmd=%d)", cmd);
+		break;
+	}
+}
+
+
+static int process_drv_event(struct nl_msg *msg, void *arg)
+{
+	struct wpa_driver_nl80211_data *drv = arg;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (tb[NL80211_ATTR_IFINDEX]) {
+		int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+		if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
+				   " for foreign interface (ifindex %d)",
+				   gnlh->cmd, ifindex);
+			return NL_SKIP;
+		}
+	}
+
+	do_process_drv_event(drv, gnlh->cmd, tb);
+	return NL_SKIP;
+}
+
+
+static int process_global_event(struct nl_msg *msg, void *arg)
+{
+	struct nl80211_global *global = arg;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct wpa_driver_nl80211_data *drv;
+	int ifidx = -1;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (tb[NL80211_ATTR_IFINDEX])
+		ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+	dl_list_for_each(drv, &global->interfaces,
+			 struct wpa_driver_nl80211_data, list) {
+		if (ifidx == -1 || ifidx == drv->ifindex ||
+		    have_ifidx(drv, ifidx))
+			do_process_drv_event(drv, gnlh->cmd, tb);
+	}
+
+	return NL_SKIP;
+}
+
+
+static int process_bss_event(struct nl_msg *msg, void *arg)
+{
+	struct i802_bss *bss = arg;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	switch (gnlh->cmd) {
+	case NL80211_CMD_FRAME:
+	case NL80211_CMD_FRAME_TX_STATUS:
+		mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
+			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+			   tb[NL80211_ATTR_COOKIE]);
+		break;
+	case NL80211_CMD_UNEXPECTED_FRAME:
+		nl80211_spurious_frame(bss, tb, 0);
+		break;
+	case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
+		nl80211_spurious_frame(bss, tb, 1);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
 			   "(cmd=%d)", gnlh->cmd);
@@ -1565,18 +2273,11 @@
 static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
 					     void *handle)
 {
-	struct nl_cb *cb;
-	struct wpa_driver_nl80211_data *drv = eloop_ctx;
+	struct nl_cb *cb = eloop_ctx;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Event message available");
 
-	cb = nl_cb_clone(drv->nl_cb);
-	if (!cb)
-		return;
-	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
-	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
 	nl_recvmsgs(handle, cb);
-	nl_cb_put(cb);
 }
 
 
@@ -1604,43 +2305,82 @@
 	alpha2[1] = alpha2_arg[1];
 	alpha2[2] = '\0';
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_REQ_SET_REG, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG);
 
 	NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
 	if (send_and_recv_msgs(drv, msg, NULL, NULL))
 		return -EINVAL;
 	return 0;
 nla_put_failure:
+	nlmsg_free(msg);
 	return -EINVAL;
 }
 
 
 struct wiphy_info_data {
-	int max_scan_ssids;
-	int ap_supported;
-	int p2p_supported;
-	int auth_supported;
-	int connect_supported;
-	int offchan_tx_supported;
-	int max_remain_on_chan;
+	struct wpa_driver_capa *capa;
+
+	unsigned int error:1;
+	unsigned int device_ap_sme:1;
+	unsigned int poll_command_supported:1;
+	unsigned int data_tx_status:1;
+	unsigned int monitor_supported:1;
 };
 
 
+static unsigned int probe_resp_offload_support(int supp_protocols)
+{
+	unsigned int prot = 0;
+
+	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
+		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
+	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
+		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
+	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
+		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
+	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
+		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
+
+	return prot;
+}
+
+
 static int wiphy_info_handler(struct nl_msg *msg, void *arg)
 {
 	struct nlattr *tb[NL80211_ATTR_MAX + 1];
 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
 	struct wiphy_info_data *info = arg;
 	int p2p_go_supported = 0, p2p_client_supported = 0;
+	int p2p_concurrent = 0;
+	int auth_supported = 0, connect_supported = 0;
+	struct wpa_driver_capa *capa = info->capa;
+	static struct nla_policy
+	iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
+		[NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
+		[NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
+		[NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
+		[NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
+	},
+	iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
+		[NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
+		[NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
+	};
 
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
 	if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
-		info->max_scan_ssids =
+		capa->max_scan_ssids =
 			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
 
+	if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
+		capa->max_sched_scan_ssids =
+			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
+
+	if (tb[NL80211_ATTR_MAX_MATCH_SETS])
+		capa->max_match_sets =
+			nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
+
 	if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
 		struct nlattr *nl_mode;
 		int i;
@@ -1648,7 +2388,7 @@
 				    tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
 			switch (nla_type(nl_mode)) {
 			case NL80211_IFTYPE_AP:
-				info->ap_supported = 1;
+				capa->flags |= WPA_DRIVER_FLAGS_AP;
 				break;
 			case NL80211_IFTYPE_P2P_GO:
 				p2p_go_supported = 1;
@@ -1656,11 +2396,69 @@
 			case NL80211_IFTYPE_P2P_CLIENT:
 				p2p_client_supported = 1;
 				break;
+			case NL80211_IFTYPE_MONITOR:
+				info->monitor_supported = 1;
+				break;
 			}
 		}
 	}
 
-	info->p2p_supported = p2p_go_supported && p2p_client_supported;
+	if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
+		struct nlattr *nl_combi;
+		int rem_combi;
+
+		nla_for_each_nested(nl_combi,
+				    tb[NL80211_ATTR_INTERFACE_COMBINATIONS],
+				    rem_combi) {
+			struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
+			struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
+			struct nlattr *nl_limit, *nl_mode;
+			int err, rem_limit, rem_mode;
+			int combination_has_p2p = 0, combination_has_mgd = 0;
+
+			err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
+					       nl_combi,
+					       iface_combination_policy);
+			if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
+			    !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
+			    !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
+				goto broken_combination;
+
+			nla_for_each_nested(nl_limit,
+					    tb_comb[NL80211_IFACE_COMB_LIMITS],
+					    rem_limit) {
+				err = nla_parse_nested(tb_limit,
+						       MAX_NL80211_IFACE_LIMIT,
+						       nl_limit,
+						       iface_limit_policy);
+				if (err ||
+				    !tb_limit[NL80211_IFACE_LIMIT_TYPES])
+					goto broken_combination;
+
+				nla_for_each_nested(
+					nl_mode,
+					tb_limit[NL80211_IFACE_LIMIT_TYPES],
+					rem_mode) {
+					int ift = nla_type(nl_mode);
+					if (ift == NL80211_IFTYPE_P2P_GO ||
+					    ift == NL80211_IFTYPE_P2P_CLIENT)
+						combination_has_p2p = 1;
+					if (ift == NL80211_IFTYPE_STATION)
+						combination_has_mgd = 1;
+				}
+				if (combination_has_p2p && combination_has_mgd)
+					break;
+			}
+
+			if (combination_has_p2p && combination_has_mgd) {
+				p2p_concurrent = 1;
+				break;
+			}
+
+broken_combination:
+			;
+		}
+	}
 
 	if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
 		struct nlattr *nl_cmd;
@@ -1668,21 +2466,92 @@
 
 		nla_for_each_nested(nl_cmd,
 				    tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
-			u32 cmd = nla_get_u32(nl_cmd);
-			if (cmd == NL80211_CMD_AUTHENTICATE)
-				info->auth_supported = 1;
-			else if (cmd == NL80211_CMD_CONNECT)
-				info->connect_supported = 1;
+			switch (nla_get_u32(nl_cmd)) {
+			case NL80211_CMD_AUTHENTICATE:
+				auth_supported = 1;
+				break;
+			case NL80211_CMD_CONNECT:
+				connect_supported = 1;
+				break;
+			case NL80211_CMD_START_SCHED_SCAN:
+				capa->sched_scan_supported = 1;
+				break;
+			case NL80211_CMD_PROBE_CLIENT:
+				info->poll_command_supported = 1;
+				break;
+			}
 		}
 	}
 
-	if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK])
-		info->offchan_tx_supported = 1;
+	if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
+		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
+			   "off-channel TX");
+		capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
+	}
+
+	if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
+		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
+		capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
+	}
+
+	/* default to 5000 since early versions of mac80211 don't set it */
+	capa->max_remain_on_chan = 5000;
+
+	if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
+		capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
 
 	if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
-		info->max_remain_on_chan =
+		capa->max_remain_on_chan =
 			nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
 
+	if (auth_supported)
+		capa->flags |= WPA_DRIVER_FLAGS_SME;
+	else if (!connect_supported) {
+		wpa_printf(MSG_INFO, "nl80211: Driver does not support "
+			   "authentication/association or connect commands");
+		info->error = 1;
+	}
+
+	if (p2p_go_supported && p2p_client_supported)
+		capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
+	if (p2p_concurrent) {
+		wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+			   "interface (driver advertised support)");
+		capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+		capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+	}
+
+	if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
+		wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
+		capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
+
+		if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) {
+			wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
+			capa->flags |=
+				WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
+		}
+	}
+
+	if (tb[NL80211_ATTR_DEVICE_AP_SME])
+		info->device_ap_sme = 1;
+
+	if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
+		u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
+
+		if (flags & NL80211_FEATURE_SK_TX_STATUS)
+			info->data_tx_status = 1;
+	}
+
+	if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
+		int protocols =
+			nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+		wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response "
+			   "offload in AP mode");
+		capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
+		capa->probe_resp_offloads =
+			probe_resp_offload_support(protocols);
+	}
+
 	return NL_SKIP;
 }
 
@@ -1693,16 +2562,13 @@
 	struct nl_msg *msg;
 
 	os_memset(info, 0, sizeof(*info));
-
-	/* default to 5000 since early versions of mac80211 don't set it */
-	info->max_remain_on_chan = 5000;
+	info->capa = &drv->capa;
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_WIPHY, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
 
@@ -1720,6 +2586,10 @@
 	struct wiphy_info_data info;
 	if (wpa_driver_nl80211_get_info(drv, &info))
 		return -1;
+
+	if (info.error)
+		return -1;
+
 	drv->has_capability = 1;
 	/* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
 	drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
@@ -1734,131 +2604,132 @@
 		WPA_DRIVER_AUTH_SHARED |
 		WPA_DRIVER_AUTH_LEAP;
 
-	drv->capa.max_scan_ssids = info.max_scan_ssids;
-	if (info.ap_supported)
-		drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
-
-	if (info.auth_supported)
-		drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
-	else if (!info.connect_supported) {
-		wpa_printf(MSG_INFO, "nl80211: Driver does not support "
-			   "authentication/association or connect commands");
-		return -1;
-	}
-
-	if (info.offchan_tx_supported) {
-		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
-			   "off-channel TX");
-		drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
-	}
-
 	drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
 	drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
-	if (info.p2p_supported)
-		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
 	drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
-	drv->capa.max_remain_on_chan = info.max_remain_on_chan;
+	drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+
+	drv->device_ap_sme = info.device_ap_sme;
+	drv->poll_command_supported = info.poll_command_supported;
+	drv->data_tx_status = info.data_tx_status;
+
+	/*
+	 * If poll command is supported mac80211 is new enough to
+	 * have everything we need to not need monitor interfaces.
+	 */
+	drv->use_monitor = !info.poll_command_supported;
+
+	if (drv->device_ap_sme && drv->use_monitor) {
+		/*
+		 * Non-mac80211 drivers may not support monitor interface.
+		 * Make sure we do not get stuck with incorrect capability here
+		 * by explicitly testing this.
+		 */
+		if (!info.monitor_supported) {
+			wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
+				   "with device_ap_sme since no monitor mode "
+				   "support detected");
+			drv->use_monitor = 0;
+		}
+	}
+
+	/*
+	 * If we aren't going to use monitor interfaces, but the
+	 * driver doesn't support data TX status, we won't get TX
+	 * status for EAPOL frames.
+	 */
+	if (!drv->use_monitor && !info.data_tx_status)
+		drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
 
 	return 0;
 }
 
 
-static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
+#ifdef ANDROID
+static int android_genl_ctrl_resolve(struct nl_handle *handle,
+				     const char *name)
+{
+	/*
+	 * Android ICS has very minimal genl_ctrl_resolve() implementation, so
+	 * need to work around that.
+	 */
+	struct nl_cache *cache = NULL;
+	struct genl_family *nl80211 = NULL;
+	int id = -1;
+
+	if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+			   "netlink cache");
+		goto fail;
+	}
+
+	nl80211 = genl_ctrl_search_by_name(cache, name);
+	if (nl80211 == NULL)
+		goto fail;
+
+	id = genl_family_get_id(nl80211);
+
+fail:
+	if (nl80211)
+		genl_family_put(nl80211);
+	if (cache)
+		nl_cache_free(cache);
+
+	return id;
+}
+#define genl_ctrl_resolve android_genl_ctrl_resolve
+#endif /* ANDROID */
+
+
+static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
 {
 	int ret;
 
-	/* Initialize generic netlink and nl80211 */
-
-	drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
-	if (drv->nl_cb == NULL) {
+	global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (global->nl_cb == NULL) {
 		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
 			   "callbacks");
-		goto err1;
+		return -1;
 	}
 
-	drv->nl_handle = nl80211_handle_alloc(drv->nl_cb);
-	if (drv->nl_handle == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
-			   "callbacks");
-		goto err2;
-	}
+	global->nl = nl_create_handle(global->nl_cb, "nl");
+	if (global->nl == NULL)
+		goto err;
 
-	drv->nl_handle_event = nl80211_handle_alloc(drv->nl_cb);
-	if (drv->nl_handle_event == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
-			   "callbacks (event)");
-		goto err2b;
-	}
-
-	if (genl_connect(drv->nl_handle)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
-			   "netlink");
-		goto err3;
-	}
-
-	if (genl_connect(drv->nl_handle_event)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
-			   "netlink (event)");
-		goto err3;
-	}
-
-#ifdef CONFIG_LIBNL20
-	if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache");
-		goto err3;
-	}
-	if (genl_ctrl_alloc_cache(drv->nl_handle_event, &drv->nl_cache_event) <
-	    0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache (event)");
-		goto err3b;
-	}
-#else /* CONFIG_LIBNL20 */
-	drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
-	if (drv->nl_cache == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache");
-		goto err3;
-	}
-	drv->nl_cache_event = genl_ctrl_alloc_cache(drv->nl_handle_event);
-	if (drv->nl_cache_event == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache (event)");
-		goto err3b;
-	}
-#endif /* CONFIG_LIBNL20 */
-
-	drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
-	if (drv->nl80211 == NULL) {
+	global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
+	if (global->nl80211_id < 0) {
 		wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
 			   "found");
-		goto err4;
+		goto err;
 	}
 
-	ret = nl_get_multicast_id(drv, "nl80211", "scan");
+	global->nl_event = nl_create_handle(global->nl_cb, "event");
+	if (global->nl_event == NULL)
+		goto err;
+
+	ret = nl_get_multicast_id(global, "nl80211", "scan");
 	if (ret >= 0)
-		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
+		ret = nl_socket_add_membership(global->nl_event, ret);
 	if (ret < 0) {
 		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
 			   "membership for scan events: %d (%s)",
 			   ret, strerror(-ret));
-		goto err4;
+		goto err;
 	}
 
-	ret = nl_get_multicast_id(drv, "nl80211", "mlme");
+	ret = nl_get_multicast_id(global, "nl80211", "mlme");
 	if (ret >= 0)
-		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
+		ret = nl_socket_add_membership(global->nl_event, ret);
 	if (ret < 0) {
 		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
 			   "membership for mlme events: %d (%s)",
 			   ret, strerror(-ret));
-		goto err4;
+		goto err;
 	}
 
-	ret = nl_get_multicast_id(drv, "nl80211", "regulatory");
+	ret = nl_get_multicast_id(global, "nl80211", "regulatory");
 	if (ret >= 0)
-		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
+		ret = nl_socket_add_membership(global->nl_event, ret);
 	if (ret < 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
 			   "membership for regulatory events: %d (%s)",
@@ -1866,27 +2737,43 @@
 		/* Continue without regulatory events */
 	}
 
-	eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
-				 wpa_driver_nl80211_event_receive, drv,
-				 drv->nl_handle_event);
+	nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+		  no_seq_check, NULL);
+	nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+		  process_global_event, global);
+
+	eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
+				 wpa_driver_nl80211_event_receive,
+				 global->nl_cb, global->nl_event);
 
 	return 0;
 
-err4:
-	nl_cache_free(drv->nl_cache_event);
-err3b:
-	nl_cache_free(drv->nl_cache);
-err3:
-	nl80211_handle_destroy(drv->nl_handle_event);
-err2b:
-	nl80211_handle_destroy(drv->nl_handle);
-err2:
-	nl_cb_put(drv->nl_cb);
-err1:
+err:
+	nl_destroy_handles(&global->nl_event);
+	nl_destroy_handles(&global->nl);
+	nl_cb_put(global->nl_cb);
+	global->nl_cb = NULL;
 	return -1;
 }
 
 
+static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
+{
+	drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!drv->nl_cb) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct");
+		return -1;
+	}
+
+	nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+		  no_seq_check, NULL);
+	nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+		  process_drv_event, drv);
+
+	return 0;
+}
+
+
 static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
 {
 	wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
@@ -1901,7 +2788,8 @@
 {
 	struct wpa_driver_nl80211_data *drv = ctx;
 	wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
-	if (linux_set_iface_flags(drv->ioctl_sock, drv->first_bss.ifname, 1)) {
+	if (linux_set_iface_flags(drv->global->ioctl_sock,
+				  drv->first_bss.ifname, 1)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
 			   "after rfkill unblock");
 		return;
@@ -1943,6 +2831,90 @@
 }
 
 
+static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
+						      void *eloop_ctx,
+						      void *handle)
+{
+	struct wpa_driver_nl80211_data *drv = eloop_ctx;
+	u8 data[2048];
+	struct msghdr msg;
+	struct iovec entry;
+	struct {
+		struct cmsghdr cm;
+		char control[512];
+	} control;
+	struct cmsghdr *cmsg;
+	int res, found_ee = 0, found_wifi = 0, acked = 0;
+	union wpa_event_data event;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = &entry;
+	msg.msg_iovlen = 1;
+	entry.iov_base = data;
+	entry.iov_len = sizeof(data);
+	msg.msg_control = &control;
+	msg.msg_controllen = sizeof(control);
+
+	res = recvmsg(sock, &msg, MSG_ERRQUEUE);
+	/* if error or not fitting 802.3 header, return */
+	if (res < 14)
+		return;
+
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
+	{
+		if (cmsg->cmsg_level == SOL_SOCKET &&
+		    cmsg->cmsg_type == SCM_WIFI_STATUS) {
+			int *ack;
+
+			found_wifi = 1;
+			ack = (void *)CMSG_DATA(cmsg);
+			acked = *ack;
+		}
+
+		if (cmsg->cmsg_level == SOL_PACKET &&
+		    cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
+			struct sock_extended_err *err =
+				(struct sock_extended_err *)CMSG_DATA(cmsg);
+
+			if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
+				found_ee = 1;
+		}
+	}
+
+	if (!found_ee || !found_wifi)
+		return;
+
+	memset(&event, 0, sizeof(event));
+	event.eapol_tx_status.dst = data;
+	event.eapol_tx_status.data = data + 14;
+	event.eapol_tx_status.data_len = res - 14;
+	event.eapol_tx_status.ack = acked;
+	wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
+}
+
+
+static int nl80211_init_bss(struct i802_bss *bss)
+{
+	bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!bss->nl_cb)
+		return -1;
+
+	nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+		  no_seq_check, NULL);
+	nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+		  process_bss_event, bss);
+
+	return 0;
+}
+
+
+static void nl80211_destroy_bss(struct i802_bss *bss)
+{
+	nl_cb_put(bss->nl_cb);
+	bss->nl_cb = NULL;
+}
+
+
 /**
  * wpa_driver_nl80211_init - Initialize nl80211 driver interface
  * @ctx: context to be used when calling wpa_supplicant functions,
@@ -1955,10 +2927,11 @@
 				      void *global_priv)
 {
 	struct wpa_driver_nl80211_data *drv;
-	struct netlink_config *cfg;
 	struct rfkill_config *rcfg;
 	struct i802_bss *bss;
 
+	if (global_priv == NULL)
+		return NULL;
 	drv = os_zalloc(sizeof(*drv));
 	if (drv == NULL)
 		return NULL;
@@ -1969,33 +2942,19 @@
 	os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
 	drv->monitor_ifidx = -1;
 	drv->monitor_sock = -1;
-	drv->ioctl_sock = -1;
+	drv->eapol_tx_sock = -1;
+	drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 
 	if (wpa_driver_nl80211_init_nl(drv)) {
 		os_free(drv);
 		return NULL;
 	}
 
+	if (nl80211_init_bss(bss))
+		goto failed;
+
 	nl80211_get_phy_name(drv);
 
-	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->ioctl_sock < 0) {
-		perror("socket(PF_INET,SOCK_DGRAM)");
-		goto failed;
-	}
-
-	cfg = os_zalloc(sizeof(*cfg));
-	if (cfg == NULL)
-		goto failed;
-	cfg->ctx = drv;
-	cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
-	cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
-	drv->netlink = netlink_init(cfg);
-	if (drv->netlink == NULL) {
-		os_free(cfg);
-		goto failed;
-	}
-
 	rcfg = os_zalloc(sizeof(*rcfg));
 	if (rcfg == NULL)
 		goto failed;
@@ -2012,32 +2971,46 @@
 	if (wpa_driver_nl80211_finish_drv_init(drv))
 		goto failed;
 
-	if (drv->global)
+	drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+	if (drv->eapol_tx_sock < 0)
+		goto failed;
+
+	if (drv->data_tx_status) {
+		int enabled = 1;
+
+		if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
+			       &enabled, sizeof(enabled)) < 0) {
+			wpa_printf(MSG_DEBUG,
+				"nl80211: wifi status sockopt failed\n");
+			drv->data_tx_status = 0;
+			if (!drv->use_monitor)
+				drv->capa.flags &=
+					~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+		} else {
+			eloop_register_read_sock(drv->eapol_tx_sock,
+				wpa_driver_nl80211_handle_eapol_tx_status,
+				drv, NULL);
+		}
+	}
+
+	if (drv->global) {
 		dl_list_add(&drv->global->interfaces, &drv->list);
+		drv->in_interface_list = 1;
+	}
 
 	return bss;
 
 failed:
-	rfkill_deinit(drv->rfkill);
-	netlink_deinit(drv->netlink);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-
-	genl_family_put(drv->nl80211);
-	nl_cache_free(drv->nl_cache);
-	nl80211_handle_destroy(drv->nl_handle);
-	nl_cb_put(drv->nl_cb);
-	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-
-	os_free(drv);
+	wpa_driver_nl80211_deinit(bss);
 	return NULL;
 }
 
 
-static int nl80211_register_frame(struct wpa_driver_nl80211_data *drv,
+static int nl80211_register_frame(struct i802_bss *bss,
 				  struct nl_handle *nl_handle,
 				  u16 type, const u8 *match, size_t match_len)
 {
+	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	int ret = -1;
 
@@ -2045,14 +3018,18 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_REGISTER_ACTION, 0);
+	wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p",
+		   type, nl_handle);
+	wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
+		    match, match_len);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 	NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
 	NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
 
-	ret = send_and_recv(drv, nl_handle, msg, NULL, NULL);
+	ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
@@ -2069,58 +3046,213 @@
 }
 
 
-static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv,
+static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (bss->nl_mgmt) {
+		wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
+			   "already on! (nl_mgmt=%p)", bss->nl_mgmt);
+		return -1;
+	}
+
+	bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt");
+	if (bss->nl_mgmt == NULL)
+		return -1;
+
+	eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
+				 wpa_driver_nl80211_event_receive, bss->nl_cb,
+				 bss->nl_mgmt);
+
+	return 0;
+}
+
+
+static int nl80211_register_action_frame(struct i802_bss *bss,
 					 const u8 *match, size_t match_len)
 {
 	u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
-	return nl80211_register_frame(drv, drv->nl_handle_event,
+	return nl80211_register_frame(bss, bss->nl_mgmt,
 				      type, match, match_len);
 }
 
 
-static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv)
+static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 {
-#ifdef CONFIG_P2P
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (nl80211_alloc_mgmt_handle(bss))
+		return -1;
+	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
+		   "handle %p", bss->nl_mgmt);
+
+#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
 	/* GAS Initial Request */
-	if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0a", 2) < 0)
+	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
 		return -1;
 	/* GAS Initial Response */
-	if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0b", 2) < 0)
+	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
 		return -1;
 	/* GAS Comeback Request */
-	if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0c", 2) < 0)
+	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
 		return -1;
 	/* GAS Comeback Response */
-	if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0d", 2) < 0)
+	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
 		return -1;
+#endif /* CONFIG_P2P || CONFIG_INTERWORKING */
+#ifdef CONFIG_P2P
 	/* P2P Public Action */
-	if (nl80211_register_action_frame(drv,
+	if (nl80211_register_action_frame(bss,
 					  (u8 *) "\x04\x09\x50\x6f\x9a\x09",
 					  6) < 0)
 		return -1;
 	/* P2P Action */
-	if (nl80211_register_action_frame(drv,
+	if (nl80211_register_action_frame(bss,
 					  (u8 *) "\x7f\x50\x6f\x9a\x09",
 					  5) < 0)
 		return -1;
 #endif /* CONFIG_P2P */
 #ifdef CONFIG_IEEE80211W
 	/* SA Query Response */
-	if (nl80211_register_action_frame(drv, (u8 *) "\x08\x01", 2) < 0)
+	if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
 		return -1;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_TDLS
+	if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
+		/* TDLS Discovery Response */
+		if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
+		    0)
+			return -1;
+	}
+#endif /* CONFIG_TDLS */
 
 	/* FT Action frames */
-	if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0)
+	if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
 		return -1;
 	else
 		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
 			WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
 
+	/* WNM - BSS Transition Management Request */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
+		return -1;
+
 	return 0;
 }
 
 
+static int nl80211_register_spurious_class3(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret = -1;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+	ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
+			   "failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+		goto nla_put_failure;
+	}
+	ret = 0;
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
+{
+	static const int stypes[] = {
+		WLAN_FC_STYPE_AUTH,
+		WLAN_FC_STYPE_ASSOC_REQ,
+		WLAN_FC_STYPE_REASSOC_REQ,
+		WLAN_FC_STYPE_DISASSOC,
+		WLAN_FC_STYPE_DEAUTH,
+		WLAN_FC_STYPE_ACTION,
+		WLAN_FC_STYPE_PROBE_REQ,
+/* Beacon doesn't work as mac80211 doesn't currently allow
+ * it, but it wouldn't really be the right thing anyway as
+ * it isn't per interface ... maybe just dump the scan
+ * results periodically for OLBC?
+ */
+//		WLAN_FC_STYPE_BEACON,
+	};
+	unsigned int i;
+
+	if (nl80211_alloc_mgmt_handle(bss))
+		return -1;
+	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
+		   "handle %p", bss->nl_mgmt);
+
+	for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
+		if (nl80211_register_frame(bss, bss->nl_mgmt,
+					   (WLAN_FC_TYPE_MGMT << 2) |
+					   (stypes[i] << 4),
+					   NULL, 0) < 0) {
+			goto out_err;
+		}
+	}
+
+	if (nl80211_register_spurious_class3(bss))
+		goto out_err;
+
+	if (nl80211_get_wiphy_data_ap(bss) == NULL)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+	nl_destroy_handles(&bss->nl_mgmt);
+	return -1;
+}
+
+
+static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
+{
+	if (nl80211_alloc_mgmt_handle(bss))
+		return -1;
+	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
+		   "handle %p (device SME)", bss->nl_mgmt);
+
+	if (nl80211_register_frame(bss, bss->nl_mgmt,
+				   (WLAN_FC_TYPE_MGMT << 2) |
+				   (WLAN_FC_STYPE_ACTION << 4),
+				   NULL, 0) < 0)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+	nl_destroy_handles(&bss->nl_mgmt);
+	return -1;
+}
+
+
+static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
+{
+	if (bss->nl_mgmt == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
+		   "(%s)", bss->nl_mgmt, reason);
+	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+	nl_destroy_handles(&bss->nl_mgmt);
+
+	nl80211_put_wiphy_data_ap(bss);
+}
+
+
 static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
 {
 	wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
@@ -2137,12 +3269,19 @@
 	drv->first_bss.ifindex = drv->ifindex;
 
 #ifndef HOSTAPD
-	if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) {
-		wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to "
+	/*
+	 * Make sure the interface starts up in station mode unless this is a
+	 * dynamically added interface (e.g., P2P) that was already configured
+	 * with proper iftype.
+	 */
+	if (drv->ifindex != drv->global->if_add_ifindex &&
+	    wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to "
 			   "use managed mode");
+		return -1;
 	}
 
-	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
+	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
 		if (rfkill_is_blocked(drv->rfkill)) {
 			wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
 				   "interface '%s' due to rfkill",
@@ -2156,26 +3295,17 @@
 		}
 	}
 
-	netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+	netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
 			       1, IF_OPER_DORMANT);
 #endif /* HOSTAPD */
 
 	if (wpa_driver_nl80211_capa(drv))
 		return -1;
 
-	if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, drv->addr))
+	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+			       bss->addr))
 		return -1;
 
-	if (nl80211_register_action_frames(drv) < 0) {
-		wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
-			   "frame processing - ignore for now");
-		/*
-		 * Older kernel versions did not support this, so ignore the
-		 * error for now. Some functionality may not be available
-		 * because of this.
-		 */
-	}
-
 	if (send_rfkill_event) {
 		eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
 				       drv, drv->ctx);
@@ -2193,12 +3323,12 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_DEL_BEACON, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -2215,17 +3345,22 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
-	if (drv->nl_handle_preq)
+	if (drv->data_tx_status)
+		eloop_unregister_read_sock(drv->eapol_tx_sock);
+	if (drv->eapol_tx_sock >= 0)
+		close(drv->eapol_tx_sock);
+
+	if (bss->nl_preq)
 		wpa_driver_nl80211_probe_req_report(bss, 0);
 	if (bss->added_if_into_bridge) {
-		if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname)
-		    < 0)
+		if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+				    bss->ifname) < 0)
 			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
 				   "interface %s from bridge %s: %s",
 				   bss->ifname, bss->brname, strerror(errno));
 	}
 	if (bss->added_bridge) {
-		if (linux_br_del(drv->ioctl_sock, bss->brname) < 0)
+		if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
 			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
 				   "bridge %s: %s",
 				   bss->brname, strerror(errno));
@@ -2233,7 +3368,7 @@
 
 	nl80211_remove_monitor_interface(drv);
 
-	if (drv->nlmode == NL80211_IFTYPE_AP)
+	if (is_ap_interface(drv->nlmode))
 		wpa_driver_nl80211_del_beacon(drv);
 
 #ifdef HOSTAPD
@@ -2254,32 +3389,28 @@
 		os_free(drv->if_indices);
 #endif /* HOSTAPD */
 
-	if (drv->disable_11b_rates)
+	if (drv->disabled_11b_rates)
 		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
 
-	netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
-	netlink_deinit(drv->netlink);
+	netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
+			       IF_OPER_UP);
 	rfkill_deinit(drv->rfkill);
 
 	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-	(void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0);
-	wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA);
+	(void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
+	wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
+	nl80211_mgmt_unsubscribe(bss, "deinit");
 
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-
-	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-	genl_family_put(drv->nl80211);
-	nl_cache_free(drv->nl_cache);
-	nl_cache_free(drv->nl_cache_event);
-	nl80211_handle_destroy(drv->nl_handle);
-	nl80211_handle_destroy(drv->nl_handle_event);
 	nl_cb_put(drv->nl_cb);
 
+	nl80211_destroy_bss(&drv->first_bss);
+
 	os_free(drv->filter_ssids);
 
-	if (drv->global)
+	os_free(drv->auth_ie);
+
+	if (drv->in_interface_list)
 		dl_list_del(&drv->list);
 
 	os_free(drv);
@@ -2297,10 +3428,10 @@
 static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_driver_nl80211_data *drv = eloop_ctx;
-	if (drv->ap_scan_as_station) {
+	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
 		wpa_driver_nl80211_set_mode(&drv->first_bss,
-					    IEEE80211_MODE_AP);
-		drv->ap_scan_as_station = 0;
+					    drv->ap_scan_as_station);
+		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 	}
 	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
 	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
@@ -2319,16 +3450,20 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret = 0, timeout;
-	struct nl_msg *msg, *ssids, *freqs;
+	struct nl_msg *msg, *ssids, *freqs, *rates;
 	size_t i;
 
+	drv->scan_for_auth = 0;
+
 	msg = nlmsg_alloc();
 	ssids = nlmsg_alloc();
 	freqs = nlmsg_alloc();
-	if (!msg || !ssids || !freqs) {
+	rates = nlmsg_alloc();
+	if (!msg || !ssids || !freqs || !rates) {
 		nlmsg_free(msg);
 		nlmsg_free(ssids);
 		nlmsg_free(freqs);
+		nlmsg_free(rates);
 		return -1;
 	}
 
@@ -2337,8 +3472,7 @@
 	params->filter_ssids = NULL;
 	drv->num_filter_ssids = params->num_filter_ssids;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_TRIGGER_SCAN, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
@@ -2353,8 +3487,8 @@
 		nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
 
 	if (params->extra_ies) {
-		wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan extra IEs",
-				  params->extra_ies, params->extra_ies_len);
+		wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+			    params->extra_ies, params->extra_ies_len);
 		NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
 			params->extra_ies);
 	}
@@ -2368,29 +3502,42 @@
 		nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
 	}
 
+	if (params->p2p_probe) {
+		/*
+		 * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
+		 * by masking out everything else apart from the OFDM rates 6,
+		 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
+		 * rates are left enabled.
+		 */
+		NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
+			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
+		nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates);
+
+		NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
+	}
+
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
 #ifdef HOSTAPD
-		if (drv->nlmode == NL80211_IFTYPE_AP) {
+		if (is_ap_interface(drv->nlmode)) {
 			/*
 			 * mac80211 does not allow scan requests in AP mode, so
 			 * try to do this in station mode.
 			 */
-			if (wpa_driver_nl80211_set_mode(bss,
-							IEEE80211_MODE_INFRA))
+			if (wpa_driver_nl80211_set_mode(
+				    bss, NL80211_IFTYPE_STATION))
 				goto nla_put_failure;
 
 			if (wpa_driver_nl80211_scan(drv, params)) {
-				wpa_driver_nl80211_set_mode(bss,
-							    IEEE80211_MODE_AP);
+				wpa_driver_nl80211_set_mode(bss, drv->nlmode);
 				goto nla_put_failure;
 			}
 
 			/* Restore AP mode when processing scan results */
-			drv->ap_scan_as_station = 1;
+			drv->ap_scan_as_station = drv->nlmode;
 			ret = 0;
 		} else
 			goto nla_put_failure;
@@ -2420,6 +3567,165 @@
 	nlmsg_free(ssids);
 	nlmsg_free(msg);
 	nlmsg_free(freqs);
+	nlmsg_free(rates);
+	return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * @interval: Interval between scan cycles in milliseconds
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+static int wpa_driver_nl80211_sched_scan(void *priv,
+					 struct wpa_driver_scan_params *params,
+					 u32 interval)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret = 0;
+	struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets;
+	size_t i;
+
+#ifdef ANDROID
+	if (!drv->capa.sched_scan_supported)
+		return android_pno_start(bss, params);
+#endif /* ANDROID */
+
+	msg = nlmsg_alloc();
+	ssids = nlmsg_alloc();
+	freqs = nlmsg_alloc();
+	if (!msg || !ssids || !freqs) {
+		nlmsg_free(msg);
+		nlmsg_free(ssids);
+		nlmsg_free(freqs);
+		return -1;
+	}
+
+	os_free(drv->filter_ssids);
+	drv->filter_ssids = params->filter_ssids;
+	params->filter_ssids = NULL;
+	drv->num_filter_ssids = params->num_filter_ssids;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
+
+	if (drv->num_filter_ssids &&
+	    (int) drv->num_filter_ssids <= drv->capa.max_match_sets) {
+		match_sets = nlmsg_alloc();
+
+		for (i = 0; i < drv->num_filter_ssids; i++) {
+			wpa_hexdump_ascii(MSG_MSGDUMP,
+					  "nl80211: Sched scan filter SSID",
+					  drv->filter_ssids[i].ssid,
+					  drv->filter_ssids[i].ssid_len);
+
+			match_set_ssid = nlmsg_alloc();
+			nla_put(match_set_ssid,
+				NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+				drv->filter_ssids[i].ssid_len,
+				drv->filter_ssids[i].ssid);
+
+			nla_put_nested(match_sets, i + 1, match_set_ssid);
+
+			nlmsg_free(match_set_ssid);
+		}
+
+		nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
+			       match_sets);
+		nlmsg_free(match_sets);
+	}
+
+	for (i = 0; i < params->num_ssids; i++) {
+		wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan SSID",
+				  params->ssids[i].ssid,
+				  params->ssids[i].ssid_len);
+		NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
+			params->ssids[i].ssid);
+	}
+	if (params->num_ssids)
+		nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
+
+	if (params->extra_ies) {
+		wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan extra IEs",
+				  params->extra_ies, params->extra_ies_len);
+		NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
+			params->extra_ies);
+	}
+
+	if (params->freqs) {
+		for (i = 0; params->freqs[i]; i++) {
+			wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
+				   "MHz", params->freqs[i]);
+			NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
+		}
+		nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
+	/* TODO: if we get an error here, we should fall back to normal scan */
+
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
+			   "ret=%d (%s)", ret, strerror(-ret));
+		goto nla_put_failure;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
+		   "scan interval %d msec", ret, interval);
+
+nla_put_failure:
+	nlmsg_free(ssids);
+	nlmsg_free(msg);
+	nlmsg_free(freqs);
+	return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+static int wpa_driver_nl80211_stop_sched_scan(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret = 0;
+	struct nl_msg *msg;
+
+#ifdef ANDROID
+	if (!drv->capa.sched_scan_supported)
+		return android_pno_stop(bss);
+#endif /* ANDROID */
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop failed: "
+			   "ret=%d (%s)", ret, strerror(-ret));
+		goto nla_put_failure;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop sent (ret=%d)", ret);
+
+nla_put_failure:
+	nlmsg_free(msg);
 	return ret;
 }
 
@@ -2514,6 +3820,13 @@
 			wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
 				   _arg->assoc_freq);
 		}
+		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+		    bss[NL80211_BSS_BSSID]) {
+			os_memcpy(_arg->assoc_bssid,
+				  nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
+			wpa_printf(MSG_DEBUG, "nl80211: Associated with "
+				   MACSTR, MAC2STR(_arg->assoc_bssid));
+		}
 	}
 	if (!res)
 		return NL_SKIP;
@@ -2555,7 +3868,7 @@
 		r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
 	} else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
 		r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
-		r->flags |= WPA_SCAN_LEVEL_INVALID;
+		r->flags |= WPA_SCAN_QUAL_INVALID;
 	} else
 		r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
 	if (bss[NL80211_BSS_TSF])
@@ -2657,7 +3970,7 @@
 				   "indicates BSS status with " MACSTR
 				   " as authenticated",
 				   MAC2STR(r->bssid));
-			if (drv->nlmode == NL80211_IFTYPE_STATION &&
+			if (is_sta_interface(drv->nlmode) &&
 			    os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
 			    os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
 			    0) {
@@ -2675,13 +3988,13 @@
 				   "indicate BSS status with " MACSTR
 				   " as associated",
 				   MAC2STR(r->bssid));
-			if (drv->nlmode == NL80211_IFTYPE_STATION &&
+			if (is_sta_interface(drv->nlmode) &&
 			    !drv->associated) {
 				wpa_printf(MSG_DEBUG, "nl80211: Local state "
 					   "(not associated) does not match "
 					   "with BSS state");
 				clear_state_mismatch(drv, r->bssid);
-			} else if (drv->nlmode == NL80211_IFTYPE_STATION &&
+			} else if (is_sta_interface(drv->nlmode) &&
 				   os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
 				   0) {
 				wpa_printf(MSG_DEBUG, "nl80211: Local state "
@@ -2696,20 +4009,6 @@
 }
 
 
-static void wpa_scan_results_free(struct wpa_scan_results *res)
-{
-	size_t i;
-
-	if (res == NULL)
-		return;
-
-	for (i = 0; i < res->num; i++)
-		os_free(res->res[i]);
-	os_free(res->res);
-	os_free(res);
-}
-
-
 static struct wpa_scan_results *
 nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
 {
@@ -2725,8 +4024,7 @@
 	if (!msg)
 		goto nla_put_failure;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
-		    NL80211_CMD_GET_SCAN, 0);
+	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
 	arg.drv = drv;
@@ -2734,8 +4032,9 @@
 	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
 	msg = NULL;
 	if (ret == 0) {
-		wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
-			   (unsigned long) res->num);
+		wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
+			   "BSSes)", (unsigned long) res->num);
+		nl80211_get_noise_for_scan_results(drv, res);
 		return res;
 	}
 	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
@@ -2806,17 +4105,19 @@
 		   "set_tx=%d seq_len=%lu key_len=%lu",
 		   __func__, ifindex, alg, addr, key_idx, set_tx,
 		   (unsigned long) seq_len, (unsigned long) key_len);
+#ifdef CONFIG_TDLS
+	if (key_idx == -1)
+		key_idx = 0;
+#endif /* CONFIG_TDLS */
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
 
 	if (alg == WPA_ALG_NONE) {
-		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-			    0, NL80211_CMD_DEL_KEY, 0);
+		nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY);
 	} else {
-		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-			    0, NL80211_CMD_NEW_KEY, 0);
+		nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY);
 		NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
 		switch (alg) {
 		case WPA_ALG_WEP:
@@ -2889,7 +4190,7 @@
 	 */
 	if (ret || !set_tx || alg == WPA_ALG_NONE)
 		return ret;
-	if (drv->nlmode == NL80211_IFTYPE_AP && addr &&
+	if (is_ap_interface(drv->nlmode) && addr &&
 	    !is_broadcast_ether_addr(addr))
 		return ret;
 
@@ -2897,8 +4198,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_KEY, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY);
 	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
 	if (alg == WPA_ALG_IGTK)
@@ -2940,6 +4240,7 @@
 	return ret;
 
 nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -3069,7 +4370,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0);
+	nl80211_cmd(drv, msg, 0, cmd);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
@@ -3080,8 +4381,9 @@
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
+		wpa_dbg(drv->ctx, MSG_DEBUG,
+			"nl80211: MLME command failed: reason=%u ret=%d (%s)",
+			reason_code, ret, strerror(-ret));
 		goto nla_put_failure;
 	}
 	ret = 0;
@@ -3134,6 +4436,52 @@
 }
 
 
+static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
+				     struct wpa_driver_auth_params *params)
+{
+	int i;
+
+	drv->auth_freq = params->freq;
+	drv->auth_alg = params->auth_alg;
+	drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
+	drv->auth_local_state_change = params->local_state_change;
+	drv->auth_p2p = params->p2p;
+
+	if (params->bssid)
+		os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
+	else
+		os_memset(drv->auth_bssid_, 0, ETH_ALEN);
+
+	if (params->ssid) {
+		os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
+		drv->auth_ssid_len = params->ssid_len;
+	} else
+		drv->auth_ssid_len = 0;
+
+
+	os_free(drv->auth_ie);
+	drv->auth_ie = NULL;
+	drv->auth_ie_len = 0;
+	if (params->ie) {
+		drv->auth_ie = os_malloc(params->ie_len);
+		if (drv->auth_ie) {
+			os_memcpy(drv->auth_ie, params->ie, params->ie_len);
+			drv->auth_ie_len = params->ie_len;
+		}
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (params->wep_key[i] && params->wep_key_len[i] &&
+		    params->wep_key_len[i] <= 16) {
+			os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
+				  params->wep_key_len[i]);
+			drv->auth_wep_key_len[i] = params->wep_key_len[i];
+		} else
+			drv->auth_wep_key_len[i] = 0;
+	}
+}
+
+
 static int wpa_driver_nl80211_authenticate(
 	void *priv, struct wpa_driver_auth_params *params)
 {
@@ -3142,13 +4490,20 @@
 	int ret = -1, i;
 	struct nl_msg *msg;
 	enum nl80211_auth_type type;
+	enum nl80211_iftype nlmode;
 	int count = 0;
+	int is_retry;
+
+	is_retry = drv->retry_auth;
+	drv->retry_auth = 0;
 
 	drv->associated = 0;
 	os_memset(drv->auth_bssid, 0, ETH_ALEN);
 	/* FIX: IBSS mode */
-	if (drv->nlmode != NL80211_IFTYPE_STATION &&
-	    wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0)
+	nlmode = params->p2p ?
+		NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+	if (drv->nlmode != nlmode &&
+	    wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
 		return -1;
 
 retry:
@@ -3159,8 +4514,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
 		   drv->ifindex);
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_AUTHENTICATE, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE);
 
 	for (i = 0; i < 4; i++) {
 		if (!params->wep_key[i])
@@ -3218,8 +4572,9 @@
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
+		wpa_dbg(drv->ctx, MSG_DEBUG,
+			"nl80211: MLME command failed (auth): ret=%d (%s)",
+			ret, strerror(-ret));
 		count++;
 		if (ret == -EALREADY && count == 1 && params->bssid &&
 		    !params->local_state_change) {
@@ -3236,6 +4591,49 @@
 			nlmsg_free(msg);
 			goto retry;
 		}
+
+		if (ret == -ENOENT && params->freq && !is_retry) {
+			/*
+			 * cfg80211 has likely expired the BSS entry even
+			 * though it was previously available in our internal
+			 * BSS table. To recover quickly, start a single
+			 * channel scan on the specified channel.
+			 */
+			struct wpa_driver_scan_params scan;
+			int freqs[2];
+
+			os_memset(&scan, 0, sizeof(scan));
+			scan.num_ssids = 1;
+			if (params->ssid) {
+				scan.ssids[0].ssid = params->ssid;
+				scan.ssids[0].ssid_len = params->ssid_len;
+			}
+			freqs[0] = params->freq;
+			freqs[1] = 0;
+			scan.freqs = freqs;
+			wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
+				   "channel scan to refresh cfg80211 BSS "
+				   "entry");
+			ret = wpa_driver_nl80211_scan(bss, &scan);
+			if (ret == 0) {
+				nl80211_copy_auth_params(drv, params);
+				drv->scan_for_auth = 1;
+			}
+		} else if (is_retry) {
+			/*
+			 * Need to indicate this with an event since the return
+			 * value from the retry is not delivered to core code.
+			 */
+			union wpa_event_data event;
+			wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
+				   "failed");
+			os_memset(&event, 0, sizeof(event));
+			os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
+				  ETH_ALEN);
+			wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
+					     &event);
+		}
+
 		goto nla_put_failure;
 	}
 	ret = 0;
@@ -3248,6 +4646,45 @@
 }
 
 
+static int wpa_driver_nl80211_authenticate_retry(
+	struct wpa_driver_nl80211_data *drv)
+{
+	struct wpa_driver_auth_params params;
+	struct i802_bss *bss = &drv->first_bss;
+	int i;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
+
+	os_memset(&params, 0, sizeof(params));
+	params.freq = drv->auth_freq;
+	params.auth_alg = drv->auth_alg;
+	params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
+	params.local_state_change = drv->auth_local_state_change;
+	params.p2p = drv->auth_p2p;
+
+	if (!is_zero_ether_addr(drv->auth_bssid_))
+		params.bssid = drv->auth_bssid_;
+
+	if (drv->auth_ssid_len) {
+		params.ssid = drv->auth_ssid;
+		params.ssid_len = drv->auth_ssid_len;
+	}
+
+	params.ie = drv->auth_ie;
+	params.ie_len = drv->auth_ie_len;
+
+	for (i = 0; i < 4; i++) {
+		if (drv->auth_wep_key_len[i]) {
+			params.wep_key[i] = drv->auth_wep_key[i];
+			params.wep_key_len[i] = drv->auth_wep_key_len[i];
+		}
+	}
+
+	drv->retry_auth = 1;
+	return wpa_driver_nl80211_authenticate(bss, &params);
+}
+
+
 struct phy_info_arg {
 	u16 *num_modes;
 	struct hostapd_hw_modes *modes;
@@ -3300,6 +4737,7 @@
 
 		mode = &phy_info->modes[*(phy_info->num_modes)];
 		memset(mode, 0, sizeof(*mode));
+		mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
 		*(phy_info->num_modes) += 1;
 
 		nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
@@ -3640,8 +5078,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_REG, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
 	return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
 }
 
@@ -3664,8 +5101,7 @@
 	if (!msg)
 		return NULL;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_WIPHY, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
@@ -3673,14 +5109,16 @@
 		nl80211_set_ht40_flags(drv, &result);
 		return wpa_driver_nl80211_add_11b(result.modes, num_modes);
 	}
+	msg = NULL;
  nla_put_failure:
+	nlmsg_free(msg);
 	return NULL;
 }
 
 
-static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
-					 const void *data, size_t len,
-					 int encrypt)
+static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
+					const void *data, size_t len,
+					int encrypt, int noack)
 {
 	__u8 rtap_hdr[] = {
 		0x00, 0x00, /* radiotap version */
@@ -3711,6 +5149,7 @@
 		.msg_flags = 0,
 	};
 	int res;
+	u16 txflags = 0;
 
 	if (encrypt)
 		rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
@@ -3721,6 +5160,10 @@
 		return -1;
 	}
 
+	if (noack)
+		txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
+	*(le16 *) &rtap_hdr[12] = host_to_le16(txflags);
+
 	res = sendmsg(drv->monitor_sock, &msg, 0);
 	if (res < 0) {
 		wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
@@ -3730,8 +5173,24 @@
 }
 
 
+static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
+					 const void *data, size_t len,
+					 int encrypt, int noack)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	u64 cookie;
+
+	if (drv->use_monitor)
+		return wpa_driver_nl80211_send_mntr(drv, data, len,
+						    encrypt, noack);
+
+	return nl80211_send_frame_cmd(bss, bss->freq, 0, data, len,
+				      &cookie, 0, noack, 0);
+}
+
+
 static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
-					size_t data_len)
+					size_t data_len, int noack)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -3741,7 +5200,8 @@
 
 	mgmt = (struct ieee80211_mgmt *) data;
 	fc = le_to_host16(mgmt->frame_control);
-	if (drv->nlmode == NL80211_IFTYPE_STATION &&
+
+	if (is_sta_interface(drv->nlmode) &&
 	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
 	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
 		/*
@@ -3749,19 +5209,21 @@
 		 * but it works due to the single-threaded nature
 		 * of wpa_supplicant.
 		 */
-		return nl80211_send_frame_cmd(drv, drv->last_mgmt_freq, 0,
-					      data, data_len, NULL);
+		return nl80211_send_frame_cmd(bss, drv->last_mgmt_freq, 0,
+					      data, data_len, NULL, 1, noack,
+					      1);
 	}
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if (drv->nlmode == NL80211_IFTYPE_AP) {
-		wpa_printf(MSG_DEBUG, "%s: Sending frame on ap_oper_freq %d using nl80211_send_frame_cmd", __func__, drv->ap_oper_freq);
-		return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0,
-					  data, data_len, &drv->send_action_cookie);
+#ifdef ANDROID_P2P
+	if (is_ap_interface(drv->nlmode)) {
+		return nl80211_send_frame_cmd(bss, bss->freq, 0,
+					  data, data_len, &drv->send_action_cookie, 0, noack, 1);
 	}
 #else
-	if (drv->no_monitor_iface_capab && drv->nlmode == NL80211_IFTYPE_AP ) {
-		return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0,
-					      data, data_len, NULL);
+
+	if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
+		return nl80211_send_frame_cmd(bss, bss->freq, 0,
+					      data, data_len, NULL,
+					      0, noack, 0);
 	}
 #endif
 	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
@@ -3777,15 +5239,59 @@
 		if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
 			encrypt = 0;
 	}
-	wpa_printf(MSG_DEBUG, "%s: Sending frame using monitor interface/l2 socket", __func__);
-	return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
+
+	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
+					     noack);
 }
 
 
-static int wpa_driver_nl80211_set_beacon(void *priv,
-					 const u8 *head, size_t head_len,
-					 const u8 *tail, size_t tail_len,
-					 int dtim_period, int beacon_int)
+static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
+			   int slot, int ht_opmode, int ap_isolate,
+			   int *basic_rates)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS);
+
+	if (cts >= 0)
+		NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
+	if (preamble >= 0)
+		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
+	if (slot >= 0)
+		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
+	if (ht_opmode >= 0)
+		NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
+	if (ap_isolate >= 0)
+		NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate);
+
+	if (basic_rates) {
+		u8 rates[NL80211_MAX_SUPP_RATES];
+		u8 rates_len = 0;
+		int i;
+
+		for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
+		     i++)
+			rates[rates_len++] = basic_rates[i] / 5;
+
+		NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_ap(void *priv,
+				     struct wpa_driver_ap_params *params)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -3794,6 +5300,10 @@
 	int ret;
 	int beacon_set;
 	int ifindex = if_nametoindex(bss->ifname);
+	int num_suites;
+	u32 suites[10];
+	u32 ver;
+
 	beacon_set = bss->beacon_set;
 
 	msg = nlmsg_alloc();
@@ -3805,13 +5315,112 @@
 	if (beacon_set)
 		cmd = NL80211_CMD_SET_BEACON;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, cmd, 0);
-	NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head);
-	NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail);
+	nl80211_cmd(drv, msg, 0, cmd);
+	NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
+	NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, beacon_int);
-	NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
+	NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
+	NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
+	NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
+		params->ssid);
+	if (params->proberesp && params->proberesp_len)
+		NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
+			params->proberesp);
+	switch (params->hide_ssid) {
+	case NO_SSID_HIDING:
+		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+			    NL80211_HIDDEN_SSID_NOT_IN_USE);
+		break;
+	case HIDDEN_SSID_ZERO_LEN:
+		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+			    NL80211_HIDDEN_SSID_ZERO_LEN);
+		break;
+	case HIDDEN_SSID_ZERO_CONTENTS:
+		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+			    NL80211_HIDDEN_SSID_ZERO_CONTENTS);
+		break;
+	}
+	if (params->privacy)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+	if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
+	    (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
+		/* Leave out the attribute */
+	} else if (params->auth_algs & WPA_AUTH_ALG_SHARED)
+		NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
+			    NL80211_AUTHTYPE_SHARED_KEY);
+	else
+		NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
+			    NL80211_AUTHTYPE_OPEN_SYSTEM);
+
+	ver = 0;
+	if (params->wpa_version & WPA_PROTO_WPA)
+		ver |= NL80211_WPA_VERSION_1;
+	if (params->wpa_version & WPA_PROTO_RSN)
+		ver |= NL80211_WPA_VERSION_2;
+	if (ver)
+		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+
+	num_suites = 0;
+	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
+		suites[num_suites++] = WLAN_AKM_SUITE_8021X;
+	if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
+		suites[num_suites++] = WLAN_AKM_SUITE_PSK;
+	if (num_suites) {
+		NLA_PUT(msg, NL80211_ATTR_AKM_SUITES,
+			num_suites * sizeof(u32), suites);
+	}
+
+	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
+	    params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
+		NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
+
+	num_suites = 0;
+	if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
+	if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
+	if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
+	if (params->pairwise_ciphers & WPA_CIPHER_WEP40)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
+	if (num_suites) {
+		NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+			num_suites * sizeof(u32), suites);
+	}
+
+	switch (params->group_cipher) {
+	case WPA_CIPHER_CCMP:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_CCMP);
+		break;
+	case WPA_CIPHER_TKIP:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_TKIP);
+		break;
+	case WPA_CIPHER_WEP104:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_WEP104);
+		break;
+	case WPA_CIPHER_WEP40:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_WEP40);
+		break;
+	}
+
+	if (params->beacon_ies) {
+		NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
+			wpabuf_head(params->beacon_ies));
+	}
+	if (params->proberesp_ies) {
+		NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
+			wpabuf_len(params->proberesp_ies),
+			wpabuf_head(params->proberesp_ies));
+	}
+	if (params->assocresp_ies) {
+		NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
+			wpabuf_len(params->assocresp_ies),
+			wpabuf_head(params->assocresp_ies));
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	if (ret) {
@@ -3819,29 +5428,36 @@
 			   ret, strerror(-ret));
 	} else {
 		bss->beacon_set = 1;
+		nl80211_set_bss(bss, params->cts_protect, params->preamble,
+				params->short_slot_time, params->ht_opmode,
+				params->isolate, params->basic_rates);
 	}
-#if defined(ANDROID_BRCM_P2P_PATCH) && defined(HOSTAPD)
+#if defined(ANDROID_P2P) && defined(HOSTAPD)
 	wpa_driver_nl80211_probe_req_report(priv, 1);
 #endif
 	return ret;
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
 
-static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
 				       int freq, int ht_enabled,
 				       int sec_channel_offset)
 {
+	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	int ret;
 
+	wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d "
+		   "sec_channel_offset=%d)",
+		   freq, ht_enabled, sec_channel_offset);
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_WIPHY, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
@@ -3856,7 +5472,7 @@
 				    NL80211_CHAN_HT40PLUS);
 			break;
 		default:
-#ifndef ANDROID_BRCM_P2P_PATCH
+#ifndef ANDROID_P2P
 /* Should be change to HT20 as a default value because P2P firmware does not support 11n for BCM4329 */
 			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
 				    NL80211_CHAN_HT20);
@@ -3869,50 +5485,102 @@
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (ret == 0)
+	msg = NULL;
+	if (ret == 0) {
+		bss->freq = freq;
 		return 0;
+	}
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
 		   "%d (%s)", freq, ret, strerror(-ret));
 nla_put_failure:
+	nlmsg_free(msg);
 	return -1;
 }
 
 
+static u32 sta_flags_nl80211(int flags)
+{
+	u32 f = 0;
+
+	if (flags & WPA_STA_AUTHORIZED)
+		f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
+	if (flags & WPA_STA_WMM)
+		f |= BIT(NL80211_STA_FLAG_WME);
+	if (flags & WPA_STA_SHORT_PREAMBLE)
+		f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
+	if (flags & WPA_STA_MFP)
+		f |= BIT(NL80211_STA_FLAG_MFP);
+	if (flags & WPA_STA_TDLS_PEER)
+		f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+
+	return f;
+}
+
+
 static int wpa_driver_nl80211_sta_add(void *priv,
 				      struct hostapd_sta_add_params *params)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
+	struct nl_msg *msg, *wme = NULL;
+	struct nl80211_sta_flag_update upd;
 	int ret = -ENOBUFS;
 
+	if ((params->flags & WPA_STA_TDLS_PEER) &&
+	    !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+		return -EOPNOTSUPP;
+
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_NEW_STATION, 0);
+	nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
+		    NL80211_CMD_NEW_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
-	NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
 	NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
 		params->supp_rates);
-	NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
-		    params->listen_interval);
+	if (!params->set) {
+		NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+		NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+			    params->listen_interval);
+	}
 	if (params->ht_capabilities) {
 		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
 			sizeof(*params->ht_capabilities),
 			params->ht_capabilities);
 	}
 
+	os_memset(&upd, 0, sizeof(upd));
+	upd.mask = sta_flags_nl80211(params->flags);
+	upd.set = upd.mask;
+	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+
+	if (params->flags & WPA_STA_WMM) {
+		wme = nlmsg_alloc();
+		if (!wme)
+			goto nla_put_failure;
+
+		NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+				params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
+		NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
+				(params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
+				WMM_QOSINFO_STA_SP_MASK);
+		nla_put_nested(msg, NL80211_ATTR_STA_WME, wme);
+	}
+
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
 	if (ret)
-		wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION "
-			   "result: %d (%s)", ret, strerror(-ret));
+		wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
+			   "result: %d (%s)", params->set ? "SET" : "NEW", ret,
+			   strerror(-ret));
 	if (ret == -EEXIST)
 		ret = 0;
  nla_put_failure:
+	nlmsg_free(wme);
+	nlmsg_free(msg);
 	return ret;
 }
 
@@ -3928,8 +5596,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_DEL_STATION, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
 		    if_nametoindex(bss->ifname));
@@ -3940,6 +5607,7 @@
 		return 0;
 	return ret;
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -3951,26 +5619,46 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
 
-#ifdef HOSTAPD
 	/* stop listening for EAPOL on this interface */
 	del_ifidx(drv, ifidx);
-#endif /* HOSTAPD */
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		goto nla_put_failure;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_DEL_INTERFACE, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
 
 	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
 		return;
+	msg = NULL;
  nla_put_failure:
+	nlmsg_free(msg);
 	wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
 }
 
 
+static const char * nl80211_iftype_str(enum nl80211_iftype mode)
+{
+	switch (mode) {
+	case NL80211_IFTYPE_ADHOC:
+		return "ADHOC";
+	case NL80211_IFTYPE_STATION:
+		return "STATION";
+	case NL80211_IFTYPE_AP:
+		return "AP";
+	case NL80211_IFTYPE_MONITOR:
+		return "MONITOR";
+	case NL80211_IFTYPE_P2P_CLIENT:
+		return "P2P_CLIENT";
+	case NL80211_IFTYPE_P2P_GO:
+		return "P2P_GO";
+	default:
+		return "unknown";
+	}
+}
+
+
 static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
 				     const char *ifname,
 				     enum nl80211_iftype iftype,
@@ -3980,12 +5668,14 @@
 	int ifidx;
 	int ret = -ENOBUFS;
 
+	wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
+		   iftype, nl80211_iftype_str(iftype));
+
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_NEW_INTERFACE, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
@@ -4010,8 +5700,10 @@
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
 	if (ret) {
  nla_put_failure:
+		nlmsg_free(msg);
 		wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
 			   ifname, ret, strerror(-ret));
 		return ret;
@@ -4024,13 +5716,11 @@
 	if (ifidx <= 0)
 		return -1;
 
-#ifdef HOSTAPD
 	/* start listening for EAPOL on this interface */
 	add_ifidx(drv, ifidx);
-#endif /* HOSTAPD */
 
 	if (addr && iftype != NL80211_IFTYPE_MONITOR &&
-	    linux_set_ifhwaddr(drv->ioctl_sock, ifname, addr)) {
+	    linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
 		nl80211_remove_iface(drv, ifidx);
 		return -1;
 	}
@@ -4047,7 +5737,7 @@
 
 	ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
 
-	/* if error occured and interface exists already */
+	/* if error occurred and interface exists already */
 	if (ret == -ENFILE && if_nametoindex(ifname)) {
 		wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
 
@@ -4059,7 +5749,7 @@
 						wds);
 	}
 
-	if (ret >= 0 && drv->disable_11b_rates)
+	if (ret >= 0 && is_p2p_interface(iftype))
 		nl80211_disable_11b_rates(drv, ret, 1);
 
 	return ret;
@@ -4089,10 +5779,20 @@
 static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
 			     u8 *buf, size_t len)
 {
+	struct ieee80211_hdr *hdr = (void *)buf;
+	u16 fc;
 	union wpa_event_data event;
+
+	if (len < sizeof(*hdr))
+		return;
+
+	fc = le_to_host16(hdr->frame_control);
+
 	os_memset(&event, 0, sizeof(event));
-	event.rx_from_unknown.frame = buf;
-	event.rx_from_unknown.len = len;
+	event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
+	event.rx_from_unknown.addr = hdr->addr2;
+	event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
+		(WLAN_FC_FROMDS | WLAN_FC_TODS);
 	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
 }
 
@@ -4350,6 +6050,10 @@
 static void nl80211_remove_monitor_interface(
 	struct wpa_driver_nl80211_data *drv)
 {
+	drv->monitor_refcount--;
+	if (drv->monitor_refcount > 0)
+		return;
+
 	if (drv->monitor_ifidx >= 0) {
 		nl80211_remove_iface(drv, drv->monitor_ifidx);
 		drv->monitor_ifidx = -1;
@@ -4369,11 +6073,25 @@
 	struct sockaddr_ll ll;
 	int optval;
 	socklen_t optlen;
-#ifdef ANDROID_BRCM_P2P_PATCH
-	snprintf(buf, IFNAMSIZ, "%s%s", WPA_MONITOR_IFNAME_PREFIX, drv->first_bss.ifname);
-#else
-	snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
-#endif
+
+	if (drv->monitor_ifidx >= 0) {
+		drv->monitor_refcount++;
+		return 0;
+	}
+
+	if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
+		/*
+		 * P2P interface name is of the format p2p-%s-%d. For monitor
+		 * interface name corresponding to P2P GO, replace "p2p-" with
+		 * "mon-" to retain the same interface name length and to
+		 * indicate that it is a monitor interface.
+		 */
+		snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4);
+	} else {
+		/* Non-P2P interface with AP functionality. */
+		snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
+	}
+
 	buf[IFNAMSIZ - 1] = '\0';
 
 	drv->monitor_ifidx =
@@ -4381,15 +6099,21 @@
 				     0);
 
 	if (drv->monitor_ifidx == -EOPNOTSUPP) {
+		/*
+		 * This is backward compatibility for a few versions of
+		 * the kernel only that didn't advertise the right
+		 * attributes for the only driver that then supported
+		 * AP mode w/o monitor -- ath6kl.
+		 */
 		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
 			   "monitor interface type - try to run without it");
-		drv->no_monitor_iface_capab = 1;
+		drv->device_ap_sme = 1;
 	}
 
 	if (drv->monitor_ifidx < 0)
 		return -1;
 
-	if (linux_set_iface_flags(drv->ioctl_sock, buf, 1))
+	if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
 		goto error;
 
 	memset(&ll, 0, sizeof(ll));
@@ -4433,6 +6157,98 @@
 }
 
 
+static int nl80211_setup_ap(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d "
+		   "use_monitor=%d", drv->device_ap_sme, drv->use_monitor);
+
+	/*
+	 * Disable Probe Request reporting unless we need it in this way for
+	 * devices that include the AP SME, in the other case (unless using
+	 * monitor iface) we'll get it through the nl_mgmt socket instead.
+	 */
+	if (!drv->device_ap_sme)
+		wpa_driver_nl80211_probe_req_report(bss, 0);
+
+	if (!drv->device_ap_sme && !drv->use_monitor)
+		if (nl80211_mgmt_subscribe_ap(bss))
+			return -1;
+
+	if (drv->device_ap_sme && !drv->use_monitor)
+		if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
+			return -1;
+
+	if (!drv->device_ap_sme && drv->use_monitor &&
+	    nl80211_create_monitor_interface(drv) &&
+	    !drv->device_ap_sme)
+		return -1;
+
+	if (drv->device_ap_sme &&
+	    wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
+			   "Probe Request frame reporting in AP mode");
+		/* Try to survive without this */
+	}
+
+#ifdef ANDROID_P2P
+	/* For AP mode, enable probe req report even if device_ap_sme
+	 * is not enabled
+	 */
+	wpa_printf(MSG_DEBUG, "nl80211: Enabling probe req report");
+	wpa_driver_nl80211_probe_req_report(bss, 1);
+#endif
+
+	return 0;
+}
+
+
+static void nl80211_teardown_ap(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (drv->device_ap_sme) {
+		wpa_driver_nl80211_probe_req_report(bss, 0);
+		if (!drv->use_monitor)
+			nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
+	} else if (drv->use_monitor)
+		nl80211_remove_monitor_interface(drv);
+	else
+		nl80211_mgmt_unsubscribe(bss, "AP teardown");
+
+	bss->beacon_set = 0;
+}
+
+
+static int nl80211_send_eapol_data(struct i802_bss *bss,
+				   const u8 *addr, const u8 *data,
+				   size_t data_len)
+{
+	struct sockaddr_ll ll;
+	int ret;
+
+	if (bss->drv->eapol_tx_sock < 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
+		return -1;
+	}
+
+	os_memset(&ll, 0, sizeof(ll));
+	ll.sll_family = AF_PACKET;
+	ll.sll_ifindex = bss->ifindex;
+	ll.sll_protocol = htons(ETH_P_PAE);
+	ll.sll_halen = ETH_ALEN;
+	os_memcpy(ll.sll_addr, addr, ETH_ALEN);
+	ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
+		     (struct sockaddr *) &ll, sizeof(ll));
+	if (ret < 0)
+		wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
+			   strerror(errno));
+
+	return ret;
+}
+
+
 static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
 
 static int wpa_driver_nl80211_hapd_send_eapol(
@@ -4447,6 +6263,9 @@
 	int res;
 	int qos = flags & WPA_STA_WMM;
 
+	if (drv->device_ap_sme || !drv->use_monitor)
+		return nl80211_send_eapol_data(bss, addr, data, data_len);
+
 	len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
 		data_len;
 	hdr = os_zalloc(len);
@@ -4484,7 +6303,7 @@
 	pos += 2;
 	memcpy(pos, data, data_len);
 
-	res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt);
+	res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0);
 	if (res < 0) {
 		wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
 			   "failed: %d (%s)",
@@ -4496,23 +6315,6 @@
 }
 
 
-static u32 sta_flags_nl80211(int flags)
-{
-	u32 f = 0;
-
-	if (flags & WPA_STA_AUTHORIZED)
-		f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
-	if (flags & WPA_STA_WMM)
-		f |= BIT(NL80211_STA_FLAG_WME);
-	if (flags & WPA_STA_SHORT_PREAMBLE)
-		f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
-	if (flags & WPA_STA_MFP)
-		f |= BIT(NL80211_STA_FLAG_MFP);
-
-	return f;
-}
-
-
 static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
 					    int total_flags,
 					    int flags_or, int flags_and)
@@ -4532,8 +6334,7 @@
 		return -ENOMEM;
 	}
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_STATION, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
 		    if_nametoindex(bss->ifname));
@@ -4555,6 +6356,9 @@
 	if (total_flags & WPA_STA_MFP)
 		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
 
+	if (total_flags & WPA_STA_TDLS_PEER)
+		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+
 	if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
 		goto nla_put_failure;
 
@@ -4567,6 +6371,7 @@
 
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+	nlmsg_free(msg);
 	nlmsg_free(flags);
 	return -ENOBUFS;
 }
@@ -4575,20 +6380,21 @@
 static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
 				 struct wpa_driver_associate_params *params)
 {
-	if (params->p2p)
+	enum nl80211_iftype nlmode;
+
+	if (params->p2p) {
 		wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
 			   "group (GO)");
-	if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) ||
-	    wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) {
+		nlmode = NL80211_IFTYPE_P2P_GO;
+	} else
+		nlmode = NL80211_IFTYPE_AP;
+
+	if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode) ||
+	    wpa_driver_nl80211_set_freq(&drv->first_bss, params->freq, 0, 0)) {
 		nl80211_remove_monitor_interface(drv);
 		return -1;
 	}
 
-	/* TODO: setup monitor interface (and add code somewhere to remove this
-	 * when AP mode is stopped; associate with mode != 2 or drv_deinit) */
-	wpa_printf(MSG_DEBUG, "nl80211: Update ap_oper_freq with params->freq %d", params->freq);
-	drv->ap_oper_freq = params->freq;
-
 	return 0;
 }
 
@@ -4602,8 +6408,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_LEAVE_IBSS, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
@@ -4631,7 +6436,8 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
 
-	if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) {
+	if (wpa_driver_nl80211_set_mode(&drv->first_bss,
+					NL80211_IFTYPE_ADHOC)) {
 		wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
 			   "IBSS mode");
 		return -1;
@@ -4642,8 +6448,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_JOIN_IBSS, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
 	if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
@@ -4696,6 +6501,55 @@
 }
 
 
+static unsigned int nl80211_get_assoc_bssid(struct wpa_driver_nl80211_data *drv,
+					    u8 *bssid)
+{
+	struct nl_msg *msg;
+	int ret;
+	struct nl80211_bss_info_arg arg;
+
+	os_memset(&arg, 0, sizeof(arg));
+	msg = nlmsg_alloc();
+	if (!msg)
+		goto nla_put_failure;
+
+	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	arg.drv = drv;
+	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+	msg = NULL;
+	if (ret == 0) {
+		if (is_zero_ether_addr(arg.assoc_bssid))
+			return -ENOTCONN;
+		os_memcpy(bssid, arg.assoc_bssid, ETH_ALEN);
+		return 0;
+	}
+	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
+		   "(%s)", ret, strerror(-ret));
+nla_put_failure:
+	nlmsg_free(msg);
+	return drv->assoc_freq;
+}
+
+
+static int nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
+			      const u8 *bssid)
+{
+	u8 addr[ETH_ALEN];
+
+	if (bssid == NULL) {
+		int res = nl80211_get_assoc_bssid(drv, addr);
+		if (res)
+			return res;
+		bssid = addr;
+	}
+
+	return wpa_driver_nl80211_disconnect(drv, bssid,
+					     WLAN_REASON_PREV_AUTH_NOT_VALID);
+}
+
+
 static int wpa_driver_nl80211_connect(
 	struct wpa_driver_nl80211_data *drv,
 	struct wpa_driver_associate_params *params)
@@ -4710,8 +6564,7 @@
 		return -1;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_CONNECT, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	if (params->bssid) {
@@ -4766,15 +6619,15 @@
 	NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
 
 skip_auth_type:
-	if (params->wpa_ie && params->wpa_ie_len) {
-		enum nl80211_wpa_versions ver;
+	if (params->wpa_proto) {
+		enum nl80211_wpa_versions ver = 0;
 
-		if (params->wpa_ie[0] == WLAN_EID_RSN)
-			ver = NL80211_WPA_VERSION_2;
-		else
-			ver = NL80211_WPA_VERSION_1;
+		if (params->wpa_proto & WPA_PROTO_WPA)
+			ver |= NL80211_WPA_VERSION_1;
+		if (params->wpa_proto & WPA_PROTO_RSN)
+			ver |= NL80211_WPA_VERSION_2;
 
-		wpa_printf(MSG_DEBUG, "  * WPA Version %d", ver);
+		wpa_printf(MSG_DEBUG, "  * WPA Versions 0x%x", ver);
 		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
 	}
 
@@ -4845,6 +6698,14 @@
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
+		/*
+		 * cfg80211 does not currently accept new connection if we are
+		 * already connected. As a workaround, force disconnection and
+		 * try again once the driver indicates it completed
+		 * disconnection.
+		 */
+		if (ret == -EALREADY)
+			nl80211_disconnect(drv, params->bssid);
 		goto nla_put_failure;
 	}
 	ret = 0;
@@ -4872,7 +6733,10 @@
 		return wpa_driver_nl80211_ibss(drv, params);
 
 	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
-		if (wpa_driver_nl80211_set_mode(priv, params->mode) < 0)
+		enum nl80211_iftype nlmode = params->p2p ?
+			NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+
+		if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
 			return -1;
 		return wpa_driver_nl80211_connect(drv, params);
 	}
@@ -4885,8 +6749,7 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
 		   drv->ifindex);
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_ASSOCIATE, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	if (params->bssid) {
@@ -4979,8 +6842,9 @@
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
+		wpa_dbg(drv->ctx, MSG_DEBUG,
+			"nl80211: MLME command failed (assoc): ret=%d (%s)",
+			ret, strerror(-ret));
 		nl80211_dump_scan(drv);
 		goto nla_put_failure;
 	}
@@ -4995,58 +6859,53 @@
 
 
 static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
-			    int ifindex, int mode)
+			    int ifindex, enum nl80211_iftype mode)
 {
 	struct nl_msg *msg;
 	int ret = -ENOBUFS;
 
+	wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
+		   ifindex, mode, nl80211_iftype_str(mode));
+
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_INTERFACE, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
 	if (!ret)
 		return 0;
 nla_put_failure:
+	nlmsg_free(msg);
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
 		   " %d (%s)", ifindex, mode, ret, strerror(-ret));
 	return ret;
 }
 
 
-static int wpa_driver_nl80211_set_mode(void *priv, int mode)
+static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+				       enum nl80211_iftype nlmode)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret = -1;
-	int nlmode;
 	int i;
+	int was_ap = is_ap_interface(drv->nlmode);
+	int res;
 
-	switch (mode) {
-	case 0:
-		nlmode = NL80211_IFTYPE_STATION;
-		break;
-	case 1:
-		nlmode = NL80211_IFTYPE_ADHOC;
-		break;
-	case 2:
-		nlmode = NL80211_IFTYPE_AP;
-		break;
-	default:
-		return -1;
-	}
-
-	if (nl80211_set_mode(drv, drv->ifindex, nlmode) == 0) {
+	res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+	if (res == 0) {
 		drv->nlmode = nlmode;
 		ret = 0;
 		goto done;
 	}
 
+	if (res == -ENODEV)
+		return -1;
+
 	if (nlmode == drv->nlmode) {
 		wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
 			   "requested mode - ignore error");
@@ -5061,15 +6920,21 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
 		   "interface down");
 	for (i = 0; i < 10; i++) {
-		if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0) ==
-		    0) {
+		res = linux_set_iface_flags(drv->global->ioctl_sock,
+					    bss->ifname, 0);
+		if (res == -EACCES || res == -ENODEV)
+			break;
+		if (res == 0) {
 			/* Try to set the mode again while the interface is
 			 * down */
 			ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
-			if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname,
-						  1))
+			if (ret == -EACCES)
+				break;
+			res = linux_set_iface_flags(drv->global->ioctl_sock,
+						    bss->ifname, 1);
+			if (res && !ret)
 				ret = -1;
-			if (!ret)
+			else if (ret != -EBUSY)
 				break;
 		} else
 			wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
@@ -5081,26 +6946,34 @@
 		wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
 			   "interface is down");
 		drv->nlmode = nlmode;
+		drv->ignore_if_down_event = 1;
 	}
 
 done:
-	if (!ret && nlmode == NL80211_IFTYPE_AP) {
-		/* Setup additional AP mode functionality if needed */
-		if (!drv->no_monitor_iface_capab && drv->monitor_ifidx < 0 &&
-		    nl80211_create_monitor_interface(drv) &&
-		    !drv->no_monitor_iface_capab)
-			return -1;
-	} else if (!ret && nlmode != NL80211_IFTYPE_AP) {
-		/* Remove additional AP mode functionality */
-		nl80211_remove_monitor_interface(drv);
-		bss->beacon_set = 0;
-	}
-
-	if (ret)
+	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
 			   "from %d failed", nlmode, drv->nlmode);
+		return ret;
+	}
 
-	return ret;
+	if (is_ap_interface(nlmode)) {
+		nl80211_mgmt_unsubscribe(bss, "start AP");
+		/* Setup additional AP mode functionality if needed */
+		if (nl80211_setup_ap(bss))
+			return -1;
+	} else if (was_ap) {
+		/* Remove additional AP mode functionality */
+		nl80211_teardown_ap(bss);
+	} else {
+		nl80211_mgmt_unsubscribe(bss, "mode change");
+	}
+
+	if (!is_ap_interface(nlmode) &&
+	    nl80211_mgmt_subscribe_non_ap(bss) < 0)
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
+			   "frame processing - ignore for now");
+
+	return 0;
 }
 
 
@@ -5124,7 +6997,7 @@
 	wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
 		   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
 	drv->operstate = state;
-	return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
+	return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
 				      state ? IF_OPER_UP : IF_OPER_DORMANT);
 }
 
@@ -5140,8 +7013,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_STATION, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
 		    if_nametoindex(bss->ifname));
@@ -5155,6 +7027,7 @@
 
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -5163,8 +7036,7 @@
 static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
 {
 	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
+	return wpa_driver_nl80211_set_freq(bss, freq->freq, freq->ht_enabled,
 					   freq->sec_channel_offset);
 }
 
@@ -5211,8 +7083,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_KEY, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY);
 
 	if (addr)
 		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
@@ -5223,36 +7094,7 @@
 
 	return send_and_recv_msgs(drv, msg, get_key_handler, seq);
  nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,
-			      int mode)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	u8 rates[NL80211_MAX_SUPP_RATES];
-	u8 rates_len = 0;
-	int i;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_BSS, 0);
-
-	for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
-		rates[rates_len++] = basic_rates[i] / 5;
-
-	NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -5274,15 +7116,16 @@
 	else
 		val = rts;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_WIPHY, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
 	if (!ret)
 		return 0;
 nla_put_failure:
+	nlmsg_free(msg);
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
 		   "%d (%s)", rts, ret, strerror(-ret));
 	return ret;
@@ -5306,15 +7149,16 @@
 	else
 		val = frag;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_WIPHY, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
 	if (!ret)
 		return 0;
 nla_put_failure:
+	nlmsg_free(msg);
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
 		   "%d: %d (%s)", frag, ret, strerror(-ret));
 	return ret;
@@ -5326,13 +7170,13 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
+	int res;
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_DEL_STATION, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
 
 	/*
 	 * XXX: FIX! this needs to flush all VLANs too
@@ -5340,8 +7184,14 @@
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
 		    if_nametoindex(bss->ifname));
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
+	res = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (res) {
+		wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
+			   "(%s)", res, strerror(-res));
+	}
+	return res;
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -5409,14 +7259,14 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_STATION, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
 
 	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 
 	return send_and_recv_msgs(drv, msg, get_sta_handler, data);
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -5433,8 +7283,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_WIPHY, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 
@@ -5474,59 +7323,13 @@
 
 	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
 		return 0;
+	msg = NULL;
  nla_put_failure:
+	nlmsg_free(msg);
 	return -1;
 }
 
 
-static int i802_set_bss(void *priv, int cts, int preamble, int slot,
-			int ht_opmode)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_BSS, 0);
-
-	if (cts >= 0)
-		NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
-	if (preamble >= 0)
-		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
-	if (slot >= 0)
-		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
-	if (ht_opmode >= 0)
-		NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-static int i802_set_cts_protect(void *priv, int value)
-{
-	return i802_set_bss(priv, value, -1, -1, -1);
-}
-
-
-static int i802_set_preamble(void *priv, int value)
-{
-	return i802_set_bss(priv, -1, value, -1, -1);
-}
-
-
-static int i802_set_short_slot_time(void *priv, int value)
-{
-	return i802_set_bss(priv, -1, -1, value, -1);
-}
-
-
 static int i802_set_sta_vlan(void *priv, const u8 *addr,
 			     const char *ifname, int vlan_id)
 {
@@ -5539,8 +7342,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_STATION, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
 		    if_nametoindex(bss->ifname));
@@ -5549,6 +7351,7 @@
 		    if_nametoindex(ifname));
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
 	if (ret < 0) {
 		wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
 			   MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
@@ -5556,23 +7359,11 @@
 			   strerror(-ret));
 	}
  nla_put_failure:
+	nlmsg_free(msg);
 	return ret;
 }
 
 
-static int i802_set_ht_params(void *priv, const u8 *ht_capab,
-			      size_t ht_capab_len, const u8 *ht_oper,
-			      size_t ht_oper_len)
-{
-	if (ht_oper_len >= 6) {
-		/* ht opmode uses 16bit in octet 5 & 6 */
-		u16 ht_opmode = le_to_host16(((u16 *) ht_oper)[2]);
-		return i802_set_bss(priv, -1, -1, -1, ht_opmode);
-	} else
-		return -1;
-}
-
-
 static int i802_get_inact_sec(void *priv, const u8 *addr)
 {
 	struct hostap_sta_driver_data data;
@@ -5610,7 +7401,7 @@
 	mgmt.u.deauth.reason_code = host_to_le16(reason);
 	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
 					    IEEE80211_HDRLEN +
-					    sizeof(mgmt.u.deauth));
+					    sizeof(mgmt.u.deauth), 0);
 }
 
 
@@ -5629,7 +7420,7 @@
 	mgmt.u.disassoc.reason_code = host_to_le16(reason);
 	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
 					    IEEE80211_HDRLEN +
-					    sizeof(mgmt.u.disassoc));
+					    sizeof(mgmt.u.disassoc), 0);
 }
 
 #endif /* HOSTAPD || CONFIG_AP */
@@ -5716,11 +7507,11 @@
 						 NULL, 1) < 0)
 				return -1;
 			if (bridge_ifname &&
-			    linux_br_add_if(drv->ioctl_sock, bridge_ifname,
-					    name) < 0)
+			    linux_br_add_if(drv->global->ioctl_sock,
+					    bridge_ifname, name) < 0)
 				return -1;
 		}
-		linux_set_iface_flags(drv->ioctl_sock, name, 1);
+		linux_set_iface_flags(drv->global->ioctl_sock, name, 1);
 		return i802_set_sta_vlan(priv, addr, name, 0);
 	} else {
 		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
@@ -5764,7 +7555,7 @@
 		 * Bridge was configured, but the bridge device does
 		 * not exist. Try to add it now.
 		 */
-		if (linux_br_add(drv->ioctl_sock, brname) < 0) {
+		if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
 			wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
 				   "bridge interface %s: %s",
 				   brname, strerror(errno));
@@ -5780,7 +7571,8 @@
 
 		wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
 			   "bridge %s", ifname, in_br);
-		if (linux_br_del_if(drv->ioctl_sock, in_br, ifname) < 0) {
+		if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
+		    0) {
 			wpa_printf(MSG_ERROR, "nl80211: Failed to "
 				   "remove interface %s from bridge "
 				   "%s: %s",
@@ -5791,7 +7583,7 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
 		   ifname, brname);
-	if (linux_br_add_if(drv->ioctl_sock, brname, ifname) < 0) {
+	if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
 		wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
 			   "into bridge %s: %s",
 			   ifname, brname, strerror(errno));
@@ -5813,12 +7605,15 @@
 	int ifindex, br_ifindex;
 	int br_added = 0;
 
-	bss = wpa_driver_nl80211_init(hapd, params->ifname, NULL);
+	bss = wpa_driver_nl80211_init(hapd, params->ifname,
+				      params->global_priv);
 	if (bss == NULL)
 		return NULL;
 
 	drv = bss->drv;
 	drv->nlmode = NL80211_IFTYPE_AP;
+	drv->eapol_sock = -1;
+
 	if (linux_br_get(brname, params->ifname) == 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
 			   params->ifname, brname);
@@ -5846,16 +7641,16 @@
 	/* start listening for EAPOL on the default AP interface */
 	add_ifidx(drv, drv->ifindex);
 
-	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0))
+	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
 		goto failed;
 
 	if (params->bssid) {
-		if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname,
+		if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
 				       params->bssid))
 			goto failed;
 	}
 
-	if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) {
+	if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
 		wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
 			   "into AP mode", bss->ifname);
 		goto failed;
@@ -5865,7 +7660,7 @@
 	    i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
 		goto failed;
 
-	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
+	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
 		goto failed;
 
 	drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
@@ -5880,25 +7675,16 @@
 		goto failed;
 	}
 
-	if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr))
+	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+			       params->own_addr))
 		goto failed;
 
+	memcpy(bss->addr, params->own_addr, ETH_ALEN);
+
 	return bss;
 
 failed:
-	nl80211_remove_monitor_interface(drv);
-	rfkill_deinit(drv->rfkill);
-	netlink_deinit(drv->netlink);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-
-	genl_family_put(drv->nl80211);
-	nl_cache_free(drv->nl_cache);
-	nl80211_handle_destroy(drv->nl_handle);
-	nl_cb_put(drv->nl_cb);
-	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-
-	os_free(drv);
+	wpa_driver_nl80211_deinit(bss);
 	return NULL;
 }
 
@@ -5938,7 +7724,7 @@
 	struct wpa_driver_nl80211_data *drv;
 	dl_list_for_each(drv, &global->interfaces,
 			 struct wpa_driver_nl80211_data, list) {
-		if (os_memcmp(addr, drv->addr, ETH_ALEN) == 0)
+		if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
 			return 1;
 	}
 	return 0;
@@ -5953,9 +7739,9 @@
 	if (!drv->global)
 		return -1;
 
-	os_memcpy(new_addr, drv->addr, ETH_ALEN);
+	os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
 	for (idx = 0; idx < 64; idx++) {
-		new_addr[0] = drv->addr[0] | 0x02;
+		new_addr[0] = drv->first_bss.addr[0] | 0x02;
 		new_addr[0] ^= idx << 2;
 		if (!nl80211_addr_in_use(drv->global, new_addr))
 			break;
@@ -6004,7 +7790,8 @@
 	}
 
 	if (!addr &&
-	    linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, if_addr) < 0) {
+	    linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+			       if_addr) < 0) {
 		nl80211_remove_iface(drv, ifidx);
 		return -1;
 	}
@@ -6016,10 +7803,10 @@
 		/* Enforce unique P2P Interface Address */
 		u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
 
-		if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr)
-		    < 0 ||
-		    linux_get_ifhwaddr(drv->ioctl_sock, ifname, new_addr) < 0)
-		{
+		if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+				       own_addr) < 0 ||
+		    linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
+				       new_addr) < 0) {
 			nl80211_remove_iface(drv, ifidx);
 			return -1;
 		}
@@ -6030,7 +7817,7 @@
 				nl80211_remove_iface(drv, ifidx);
 				return -1;
 			}
-			if (linux_set_ifhwaddr(drv->ioctl_sock, ifname,
+			if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
 					       new_addr) < 0) {
 				nl80211_remove_iface(drv, ifidx);
 				return -1;
@@ -6051,21 +7838,27 @@
 	}
 
 	if (type == WPA_IF_AP_BSS) {
-		if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) {
+		if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
+		{
 			nl80211_remove_iface(drv, ifidx);
 			os_free(new_bss);
 			return -1;
 		}
 		os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
+		os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
 		new_bss->ifindex = ifidx;
 		new_bss->drv = drv;
 		new_bss->next = drv->first_bss.next;
 		drv->first_bss.next = new_bss;
 		if (drv_priv)
 			*drv_priv = new_bss;
+		nl80211_init_bss(new_bss);
 	}
 #endif /* HOSTAPD */
 
+	if (drv->global)
+		drv->global->if_add_ifindex = ifidx;
+
 	return 0;
 }
 
@@ -6085,14 +7878,14 @@
 
 #ifdef HOSTAPD
 	if (bss->added_if_into_bridge) {
-		if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname)
-		    < 0)
+		if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+				    bss->ifname) < 0)
 			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
 				   "interface %s from bridge %s: %s",
 				   bss->ifname, bss->brname, strerror(errno));
 	}
 	if (bss->added_bridge) {
-		if (linux_br_del(drv->ioctl_sock, bss->brname) < 0)
+		if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
 			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
 				   "bridge %s: %s",
 				   bss->brname, strerror(errno));
@@ -6111,6 +7904,7 @@
 		for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
 			if (tbss->next == bss) {
 				tbss->next = bss->next;
+				nl80211_destroy_bss(bss);
 				os_free(bss);
 				bss = NULL;
 				break;
@@ -6139,11 +7933,13 @@
 }
 
 
-static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
+static int nl80211_send_frame_cmd(struct i802_bss *bss,
 				  unsigned int freq, unsigned int wait,
 				  const u8 *buf, size_t buf_len,
-				  u64 *cookie_out)
+				  u64 *cookie_out, int no_cck, int no_ack,
+				  int offchanok)
 {
+	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	u64 cookie;
 	int ret = -1;
@@ -6152,16 +7948,21 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_FRAME, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
-#ifndef ANDROID_BRCM_P2P_PATCH
+#ifndef ANDROID_P2P
 	if (wait)
 		NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
 #endif
-	NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
+	if (offchanok)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
+	if (no_cck)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
+	if (no_ack)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK);
+
 	NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
 
 	cookie = 0;
@@ -6173,11 +7974,12 @@
 			   freq, wait);
 		goto nla_put_failure;
 	}
-	wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted; "
-		   "cookie 0x%llx", (long long unsigned int) cookie);
+	wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; "
+		   "cookie 0x%llx", no_ack ? " (no ACK)" : "",
+		   (long long unsigned int) cookie);
 
 	if (cookie_out)
-		*cookie_out = cookie;
+		*cookie_out = no_ack ? (u64) -1 : cookie;
 
 nla_put_failure:
 	nlmsg_free(msg);
@@ -6189,7 +7991,8 @@
 					  unsigned int wait_time,
 					  const u8 *dst, const u8 *src,
 					  const u8 *bssid,
-					  const u8 *data, size_t data_len)
+					  const u8 *data, size_t data_len,
+					  int no_cck)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -6198,7 +8001,7 @@
 	struct ieee80211_hdr *hdr;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
-		   "wait=%d ms)", drv->ifindex, wait_time);
+		   "wait=%d ms no_cck=%d)", drv->ifindex, wait_time, no_cck);
 
 	buf = os_zalloc(24 + data_len);
 	if (buf == NULL)
@@ -6211,12 +8014,14 @@
 	os_memcpy(hdr->addr2, src, ETH_ALEN);
 	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
-	if (drv->nlmode == NL80211_IFTYPE_AP)
-		ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len);
+	if (is_ap_interface(drv->nlmode))
+		ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len,
+						   0);
 	else
-		ret = nl80211_send_frame_cmd(drv, freq, wait_time, buf,
+		ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
 					     24 + data_len,
-					     &drv->send_action_cookie);
+					     &drv->send_action_cookie,
+					     no_cck, 0, 1);
 
 	os_free(buf);
 	return ret;
@@ -6234,8 +8039,7 @@
 	if (!msg)
 		return;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_FRAME_WAIT_CANCEL, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
@@ -6264,8 +8068,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_REMAIN_ON_CHANNEL, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
@@ -6273,17 +8076,20 @@
 
 	cookie = 0;
 	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+	msg = NULL;
 	if (ret == 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
 			   "0x%llx for freq=%u MHz duration=%u",
 			   (long long unsigned int) cookie, freq, duration);
 		drv->remain_on_chan_cookie = cookie;
+		drv->pending_remain_on_chan = 1;
 		return 0;
 	}
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
 		   "(freq=%d duration=%u): %d (%s)",
 		   freq, duration, ret, strerror(-ret));
 nla_put_failure:
+	nlmsg_free(msg);
 	return -1;
 }
 
@@ -6309,18 +8115,19 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
 	if (ret == 0)
 		return 0;
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
 		   "%d (%s)", ret, strerror(-ret));
 nla_put_failure:
+	nlmsg_free(msg);
 	return -1;
 }
 
@@ -6331,60 +8138,43 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
 	if (!report) {
-		if (drv->nl_handle_preq) {
+		if (bss->nl_preq && drv->device_ap_sme &&
+		    is_ap_interface(drv->nlmode)) {
+			/*
+			 * Do not disable Probe Request reporting that was
+			 * enabled in nl80211_setup_ap().
+			 */
+			wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
+				   "Probe Request reporting nl_preq=%p while "
+				   "in AP mode", bss->nl_preq);
+		} else if (bss->nl_preq) {
+			wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
+				   "reporting nl_preq=%p", bss->nl_preq);
 			eloop_unregister_read_sock(
-				nl_socket_get_fd(drv->nl_handle_preq));
-			nl_cache_free(drv->nl_cache_preq);
-			nl80211_handle_destroy(drv->nl_handle_preq);
-			drv->nl_handle_preq = NULL;
+				nl_socket_get_fd(bss->nl_preq));
+			nl_destroy_handles(&bss->nl_preq);
 		}
 		return 0;
 	}
 
-	if (drv->nl_handle_preq) {
+	if (bss->nl_preq) {
 		wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
-			   "already on!");
+			   "already on! nl_preq=%p", bss->nl_preq);
 		return 0;
 	}
 
-	drv->nl_handle_preq = nl80211_handle_alloc(drv->nl_cb);
-	if (drv->nl_handle_preq == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate "
-			   "netlink callbacks (preq)");
-		goto out_err1;
-	}
-
-	if (genl_connect(drv->nl_handle_preq)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to "
-			   "generic netlink (preq)");
-		goto out_err2;
+	bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
+	if (bss->nl_preq == NULL)
 		return -1;
-	}
+	wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
+		   "reporting nl_preq=%p", bss->nl_preq);
 
-#ifdef CONFIG_LIBNL20
-	if (genl_ctrl_alloc_cache(drv->nl_handle_preq,
-				  &drv->nl_cache_preq) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache (preq)");
-		goto out_err2;
-	}
-#else /* CONFIG_LIBNL20 */
-	drv->nl_cache_preq = genl_ctrl_alloc_cache(drv->nl_handle_preq);
-	if (drv->nl_cache_preq == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache (preq)");
-		goto out_err2;
-	}
-#endif /* CONFIG_LIBNL20 */
-
-	if (nl80211_register_frame(drv, drv->nl_handle_preq,
+	if (nl80211_register_frame(bss, bss->nl_preq,
 				   (WLAN_FC_TYPE_MGMT << 2) |
 				   (WLAN_FC_STYPE_PROBE_REQ << 4),
-				   NULL, 0) < 0) {
-		goto out_err3;
-	}
-
-#ifdef ANDROID_BRCM_P2P_PATCH
+				   NULL, 0) < 0)
+		goto out_err;
+#ifdef ANDROID_P2P
 	if (drv->nlmode != NL80211_IFTYPE_AP &&
 		drv->nlmode != NL80211_IFTYPE_P2P_GO) {
 		wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only "
@@ -6392,49 +8182,51 @@
 			   drv->nlmode);
 		goto done;
 	}
-	
-	if (nl80211_register_frame(drv, drv->nl_handle_preq,
+	if (nl80211_register_frame(bss, bss->nl_preq,
 			   (WLAN_FC_TYPE_MGMT << 2) |
 			   (WLAN_FC_STYPE_ASSOC_REQ << 4),
 			   NULL, 0) < 0) {
-		goto out_err3;
+		goto out_err;
 	}
 
-	if (nl80211_register_frame(drv, drv->nl_handle_preq,
+	if (nl80211_register_frame(bss, bss->nl_preq,
 			   (WLAN_FC_TYPE_MGMT << 2) |
 			   (WLAN_FC_STYPE_REASSOC_REQ << 4),
 			   NULL, 0) < 0) {
-		goto out_err3;
+		goto out_err;
 	}
 
-	if (nl80211_register_frame(drv, drv->nl_handle_preq,
+	if (nl80211_register_frame(bss, bss->nl_preq,
 			   (WLAN_FC_TYPE_MGMT << 2) |
 			   (WLAN_FC_STYPE_DISASSOC << 4),
 			   NULL, 0) < 0) {
-		goto out_err3;
+		goto out_err;
 	}
-	
-	if (nl80211_register_frame(drv, drv->nl_handle_preq,
+
+	if (nl80211_register_frame(bss, bss->nl_preq,
 					   (WLAN_FC_TYPE_MGMT << 2) |
 					   (WLAN_FC_STYPE_DEAUTH << 4),
 					   NULL, 0) < 0) {
-		goto out_err3;
+		goto out_err;
+	}
+
+	if (nl80211_register_frame(bss, bss->nl_preq,
+			   (WLAN_FC_TYPE_MGMT << 2) |
+			   (WLAN_FC_STYPE_ACTION << 4),
+			   NULL, 0) < 0) {
+		goto out_err;
 	}
 
 done:
-#endif
-	eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_preq),
-				 wpa_driver_nl80211_event_receive, drv,
-				 drv->nl_handle_preq);
+#endif /* ANDROID_P2P */
+	eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
+				 wpa_driver_nl80211_event_receive, bss->nl_cb,
+				 bss->nl_preq);
 
 	return 0;
 
- out_err3:
-	nl_cache_free(drv->nl_cache_preq);
- out_err2:
-	nl80211_handle_destroy(drv->nl_handle_preq);
-	drv->nl_handle_preq = NULL;
- out_err1:
+ out_err:
+	nl_destroy_handles(&bss->nl_preq);
 	return -1;
 }
 
@@ -6450,8 +8242,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_TX_BITRATE_MASK, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
 
 	bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
@@ -6466,8 +8257,10 @@
 	band = nla_nest_start(msg, NL80211_BAND_2GHZ);
 	if (!band)
 		goto nla_put_failure;
-	NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
-		"\x0c\x12\x18\x24\x30\x48\x60\x6c");
+	if (disabled) {
+		NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
+			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
+	}
 	nla_nest_end(msg, band);
 
 	nla_nest_end(msg, bands);
@@ -6487,23 +8280,14 @@
 }
 
 
-static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	drv->disable_11b_rates = disabled;
-	return nl80211_disable_11b_rates(drv, drv->ifindex, disabled);
-}
-
-
 static int wpa_driver_nl80211_deinit_ap(void *priv)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	if (drv->nlmode != NL80211_IFTYPE_AP)
+	if (!is_ap_interface(drv->nlmode))
 		return -1;
 	wpa_driver_nl80211_del_beacon(drv);
-	return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA);
+	return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
 }
 
 
@@ -6511,7 +8295,7 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
+	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
 			   "resume event");
 	}
@@ -6526,10 +8310,7 @@
 	int ret;
 	u8 *data, *pos;
 	size_t data_len;
-	u8 own_addr[ETH_ALEN];
-
-	if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) < 0)
-		return -1;
+	const u8 *own_addr = bss->addr;
 
 	if (action != 1) {
 		wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
@@ -6561,7 +8342,7 @@
 
 	ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
 					     drv->bssid, own_addr, drv->bssid,
-					     data, data_len);
+					     data, data_len, 0);
 	os_free(data);
 
 	return ret;
@@ -6581,8 +8362,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_CQM, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 
@@ -6599,8 +8379,7 @@
 	msg = NULL;
 
 nla_put_failure:
-	if (cqm)
-		nlmsg_free(cqm);
+	nlmsg_free(cqm);
 	nlmsg_free(msg);
 	return -1;
 }
@@ -6621,34 +8400,58 @@
 }
 
 
+static int wpa_driver_nl80211_shared_freq(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct wpa_driver_nl80211_data *driver;
+	int freq = 0;
+
+	/*
+	 * If the same PHY is in connected state with some other interface,
+	 * then retrieve the assoc freq.
+	 */
+	wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
+		   drv->phyname);
+
+	dl_list_for_each(driver, &drv->global->interfaces,
+			 struct wpa_driver_nl80211_data, list) {
+		if (drv == driver ||
+		    os_strcmp(drv->phyname, driver->phyname) != 0 ||
+#ifdef ANDROID_P2P
+		    (!driver->associated && !is_ap_interface(driver->nlmode)))
+#else
+		    !driver->associated)
+#endif
+			continue;
+
+		wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
+			   MACSTR,
+			   driver->phyname, driver->first_bss.ifname,
+			   MAC2STR(driver->first_bss.addr));
+#ifdef ANDROID_P2P
+		if(is_ap_interface(driver->nlmode))
+			freq = driver->first_bss.freq;
+		else
+#endif
+			freq = nl80211_get_assoc_freq(driver);
+		wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
+			   drv->phyname, freq);
+	}
+
+	if (!freq)
+		wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
+			   "PHY (%s) in associated state", drv->phyname);
+
+	return freq;
+}
+
+
 static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
 			      int encrypt)
 {
 	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
-}
-
-
-static int nl80211_set_intra_bss(void *priv, int enabled)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_BSS, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-	NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, !enabled);
-
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-	return -ENOBUFS;
+	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0);
 }
 
 
@@ -6668,6 +8471,15 @@
 		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
 		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
 	}
+#ifdef ANDROID_P2P
+	if(os_strstr(param, "use_multi_chan_concurrent=1")) {
+		struct i802_bss *bss = priv;
+		struct wpa_driver_nl80211_data *drv = bss->drv;
+		wpa_printf(MSG_DEBUG, "nl80211: Use Multi channel "
+			   "concurrency");
+		drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+	}
+#endif
 #endif /* CONFIG_P2P */
 
 	return 0;
@@ -6677,11 +8489,42 @@
 static void * nl80211_global_init(void)
 {
 	struct nl80211_global *global;
+	struct netlink_config *cfg;
+
 	global = os_zalloc(sizeof(*global));
 	if (global == NULL)
 		return NULL;
+	global->ioctl_sock = -1;
 	dl_list_init(&global->interfaces);
+	global->if_add_ifindex = -1;
+
+	cfg = os_zalloc(sizeof(*cfg));
+	if (cfg == NULL)
+		goto err;
+
+	cfg->ctx = global;
+	cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
+	cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
+	global->netlink = netlink_init(cfg);
+	if (global->netlink == NULL) {
+		os_free(cfg);
+		goto err;
+	}
+
+	if (wpa_driver_nl80211_init_nl_global(global) < 0)
+		goto err;
+
+	global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (global->ioctl_sock < 0) {
+		perror("socket(PF_INET,SOCK_DGRAM)");
+		goto err;
+	}
+
 	return global;
+
+err:
+	nl80211_global_deinit(global);
+	return NULL;
 }
 
 
@@ -6695,6 +8538,23 @@
 			   "nl80211_global_deinit",
 			   dl_list_len(&global->interfaces));
 	}
+
+	if (global->netlink)
+		netlink_deinit(global->netlink);
+
+	nl_destroy_handles(&global->nl);
+
+	if (global->nl_event) {
+		eloop_unregister_read_sock(
+			nl_socket_get_fd(global->nl_event));
+		nl_destroy_handles(&global->nl_event);
+	}
+
+	nl_cb_put(global->nl_cb);
+
+	if (global->ioctl_sock >= 0)
+		close(global->ioctl_sock);
+
 	os_free(global);
 }
 
@@ -6716,8 +8576,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(bss->drv->nl80211), 0, 0,
-		    cmd, 0);
+	nl80211_cmd(bss->drv, msg, 0, cmd);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 	if (pmkid)
@@ -6727,6 +8586,7 @@
 
 	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -6756,6 +8616,366 @@
 }
 
 
+static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
+				   const u8 *replay_ctr)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nlattr *replay_nested;
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+	replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
+	if (!replay_nested)
+		goto nla_put_failure;
+
+	NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
+	NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
+	NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
+		replay_ctr);
+
+	nla_nest_end(msg, replay_nested);
+
+	send_and_recv_msgs(drv, msg, NULL, NULL);
+	return;
+ nla_put_failure:
+	nlmsg_free(msg);
+}
+
+
+static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
+				    const u8 *addr, int qos)
+{
+	/* send data frame to poll STA and check whether
+	 * this frame is ACKed */
+	struct {
+		struct ieee80211_hdr hdr;
+		u16 qos_ctl;
+	} STRUCT_PACKED nulldata;
+	size_t size;
+
+	/* Send data frame to poll STA and check whether this frame is ACKed */
+
+	os_memset(&nulldata, 0, sizeof(nulldata));
+
+	if (qos) {
+		nulldata.hdr.frame_control =
+			IEEE80211_FC(WLAN_FC_TYPE_DATA,
+				     WLAN_FC_STYPE_QOS_NULL);
+		size = sizeof(nulldata);
+	} else {
+		nulldata.hdr.frame_control =
+			IEEE80211_FC(WLAN_FC_TYPE_DATA,
+				     WLAN_FC_STYPE_NULLFUNC);
+		size = sizeof(struct ieee80211_hdr);
+	}
+
+	nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
+	os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+	os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+	os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+	if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
+		wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
+			   "send poll frame");
+}
+
+static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
+				int qos)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+
+	if (!drv->poll_command_supported) {
+		nl80211_send_null_frame(bss, own_addr, addr, qos);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+	send_and_recv_msgs(drv, msg, NULL, NULL);
+	return;
+ nla_put_failure:
+	nlmsg_free(msg);
+}
+
+
+static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE,
+		    enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED);
+	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
+				     int ctwindow)
+{
+	struct i802_bss *bss = priv;
+
+	wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
+		   "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
+
+	if (opp_ps != -1 || ctwindow != -1)
+		return -1; /* Not yet supported */
+
+	if (legacy_ps == -1)
+		return 0;
+	if (legacy_ps != 0 && legacy_ps != 1)
+		return -1; /* Not yet supported */
+
+	return nl80211_set_power_save(bss, legacy_ps);
+}
+
+
+#ifdef CONFIG_TDLS
+
+static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
+				  u8 dialog_token, u16 status_code,
+				  const u8 *buf, size_t len)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+		return -EOPNOTSUPP;
+
+	if (!dst)
+		return -EINVAL;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
+	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
+	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
+	NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
+	NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	enum nl80211_tdls_operation nl80211_oper;
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+		return -EOPNOTSUPP;
+
+	switch (oper) {
+	case TDLS_DISCOVERY_REQ:
+		nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
+		break;
+	case TDLS_SETUP:
+		nl80211_oper = NL80211_TDLS_SETUP;
+		break;
+	case TDLS_TEARDOWN:
+		nl80211_oper = NL80211_TDLS_TEARDOWN;
+		break;
+	case TDLS_ENABLE_LINK:
+		nl80211_oper = NL80211_TDLS_ENABLE_LINK;
+		break;
+	case TDLS_DISABLE_LINK:
+		nl80211_oper = NL80211_TDLS_DISABLE_LINK;
+		break;
+	case TDLS_ENABLE:
+		return 0;
+	case TDLS_DISABLE:
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER);
+	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+#endif /* CONFIG TDLS */
+
+
+#ifdef ANDROID
+
+typedef struct android_wifi_priv_cmd {
+	char *buf;
+	int used_len;
+	int total_len;
+} android_wifi_priv_cmd;
+
+static int drv_errors = 0;
+
+static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
+{
+	drv_errors++;
+	if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+		drv_errors = 0;
+		wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+	}
+}
+
+
+static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct ifreq ifr;
+	android_wifi_priv_cmd priv_cmd;
+	char buf[MAX_DRV_CMD_SIZE];
+	int ret;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_memset(&priv_cmd, 0, sizeof(priv_cmd));
+	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+	os_memset(buf, 0, sizeof(buf));
+	os_strlcpy(buf, cmd, sizeof(buf));
+
+	priv_cmd.buf = buf;
+	priv_cmd.used_len = sizeof(buf);
+	priv_cmd.total_len = sizeof(buf);
+	ifr.ifr_data = &priv_cmd;
+
+	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
+			   __func__);
+		wpa_driver_send_hang_msg(drv);
+		return ret;
+	}
+
+	drv_errors = 0;
+	return 0;
+}
+
+
+static int android_pno_start(struct i802_bss *bss,
+			     struct wpa_driver_scan_params *params)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct ifreq ifr;
+	android_wifi_priv_cmd priv_cmd;
+	int ret = 0, i = 0, bp;
+	char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+	bp = WEXT_PNOSETUP_HEADER_SIZE;
+	os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+	buf[bp++] = WEXT_PNO_TLV_PREFIX;
+	buf[bp++] = WEXT_PNO_TLV_VERSION;
+	buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+	buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+	while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+		/* Check that there is enough space needed for 1 more SSID, the
+		 * other sections and null termination */
+		if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
+		     WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+			break;
+		wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+				  params->ssids[i].ssid,
+				  params->ssids[i].ssid_len);
+		buf[bp++] = WEXT_PNO_SSID_SECTION;
+		buf[bp++] = params->ssids[i].ssid_len;
+		os_memcpy(&buf[bp], params->ssids[i].ssid,
+			  params->ssids[i].ssid_len);
+		bp += params->ssids[i].ssid_len;
+		i++;
+	}
+
+	buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+		    WEXT_PNO_SCAN_INTERVAL);
+	bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+	buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+		    WEXT_PNO_REPEAT);
+	bp += WEXT_PNO_REPEAT_LENGTH;
+
+	buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+		    WEXT_PNO_MAX_REPEAT);
+	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+	memset(&ifr, 0, sizeof(ifr));
+	memset(&priv_cmd, 0, sizeof(priv_cmd));
+	os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+	priv_cmd.buf = buf;
+	priv_cmd.used_len = bp;
+	priv_cmd.total_len = bp;
+	ifr.ifr_data = &priv_cmd;
+
+	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+			   ret);
+		wpa_driver_send_hang_msg(drv);
+		return ret;
+	}
+
+	drv_errors = 0;
+
+	return android_priv_cmd(bss, "PNOFORCE 1");
+}
+
+
+static int android_pno_stop(struct i802_bss *bss)
+{
+	return android_priv_cmd(bss, "PNOFORCE 0");
+}
+
+#endif /* ANDROID */
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -6763,6 +8983,8 @@
 	.get_ssid = wpa_driver_nl80211_get_ssid,
 	.set_key = wpa_driver_nl80211_set_key,
 	.scan2 = wpa_driver_nl80211_scan,
+	.sched_scan = wpa_driver_nl80211_sched_scan,
+	.stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
 	.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
 	.deauthenticate = wpa_driver_nl80211_deauthenticate,
 	.disassociate = wpa_driver_nl80211_disassociate,
@@ -6776,7 +8998,7 @@
 	.set_operstate = wpa_driver_nl80211_set_operstate,
 	.set_supp_port = wpa_driver_nl80211_set_supp_port,
 	.set_country = wpa_driver_nl80211_set_country,
-	.set_beacon = wpa_driver_nl80211_set_beacon,
+	.set_ap = wpa_driver_nl80211_set_ap,
 	.if_add = wpa_driver_nl80211_if_add,
 	.if_remove = wpa_driver_nl80211_if_remove,
 	.send_mlme = wpa_driver_nl80211_send_mlme,
@@ -6798,13 +9020,8 @@
 	.sta_clear_stats = i802_sta_clear_stats,
 	.set_rts = i802_set_rts,
 	.set_frag = i802_set_frag,
-	.set_cts_protect = i802_set_cts_protect,
-	.set_preamble = i802_set_preamble,
-	.set_short_slot_time = i802_set_short_slot_time,
 	.set_tx_queue_params = i802_set_tx_queue_params,
 	.set_sta_vlan = i802_set_sta_vlan,
-	.set_ht_params = i802_set_ht_params,
-	.set_rate_sets = i802_set_rate_sets,
 	.sta_deauth = i802_sta_deauth,
 	.sta_disassoc = i802_sta_disassoc,
 #endif /* HOSTAPD || CONFIG_AP */
@@ -6815,22 +9032,30 @@
 	.cancel_remain_on_channel =
 	wpa_driver_nl80211_cancel_remain_on_channel,
 	.probe_req_report = wpa_driver_nl80211_probe_req_report,
-	.disable_11b_rates = wpa_driver_nl80211_disable_11b_rates,
 	.deinit_ap = wpa_driver_nl80211_deinit_ap,
 	.resume = wpa_driver_nl80211_resume,
 	.send_ft_action = nl80211_send_ft_action,
 	.signal_monitor = nl80211_signal_monitor,
 	.signal_poll = nl80211_signal_poll,
 	.send_frame = nl80211_send_frame,
-	.set_intra_bss = nl80211_set_intra_bss,
+	.shared_freq = wpa_driver_nl80211_shared_freq,
 	.set_param = nl80211_set_param,
 	.get_radio_name = nl80211_get_radio_name,
 	.add_pmkid = nl80211_add_pmkid,
 	.remove_pmkid = nl80211_remove_pmkid,
 	.flush_pmkid = nl80211_flush_pmkid,
-#ifdef ANDROID_BRCM_P2P_PATCH
-	.get_noa = wpa_driver_get_p2p_noa,
+	.set_rekey_info = nl80211_set_rekey_info,
+	.poll_client = nl80211_poll_client,
+#ifndef ANDROID_P2P
+	.set_p2p_powersave = nl80211_set_p2p_powersave,
+#endif
+#ifdef CONFIG_TDLS
+	.send_tdls_mgmt = nl80211_send_tdls_mgmt,
+	.tdls_oper = nl80211_tdls_oper,
+#endif /* CONFIG_TDLS */
+#ifdef ANDROID_P2P
 	.set_noa = wpa_driver_set_p2p_noa,
+	.get_noa = wpa_driver_get_p2p_noa,
 	.set_p2p_powersave = wpa_driver_set_p2p_ps,
 	.set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
 #endif
diff --git a/src/drivers/driver_osx.m b/src/drivers/driver_osx.m
deleted file mode 100644
index 69ca4b5..0000000
--- a/src/drivers/driver_osx.m
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * WPA Supplicant - Mac OS X Apple80211 driver interface
- * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#define Boolean __DummyBoolean
-#include <CoreFoundation/CoreFoundation.h>
-#undef Boolean
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-
-#include "Apple80211.h"
-
-struct wpa_driver_osx_data {
-	void *ctx;
-	WirelessRef wireless_ctx;
-	CFArrayRef scan_results;
-};
-
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-extern int wpa_debug_level;
-
-static void dump_dict_cb(const void *key, const void *value, void *context)
-{
-        if (MSG_DEBUG < wpa_debug_level)
-                return;
-
-	wpa_printf(MSG_DEBUG, "Key:");
-	CFShow(key);
-	wpa_printf(MSG_DEBUG, "Value:");
-	CFShow(value);
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-
-static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
-	wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries",
-		   title, (unsigned int) CFDictionaryGetCount(dict));
-	CFDictionaryApplyFunction(dict, dump_dict_cb, NULL);
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-}
-
-
-static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-	WirelessInfo info;
-	int len;
-
-	err = WirelessGetInfo(drv->wireless_ctx, &info);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
-			   (int) err);
-		return -1;
-	}
-	if (!info.power) {
-		wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
-		return -1;
-	}
-
-	for (len = 0; len < 32; len++)
-		if (info.ssid[len] == 0)
-			break;
-
-	os_memcpy(ssid, info.ssid, len);
-	return len;
-}
-
-
-static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-	WirelessInfo info;
-
-	err = WirelessGetInfo(drv->wireless_ctx, &info);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
-			   (int) err);
-		return -1;
-	}
-	if (!info.power) {
-		wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
-		return -1;
-	}
-
-	os_memcpy(bssid, info.bssID, ETH_ALEN);
-	return 0;
-}
-
-
-static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static int wpa_driver_osx_scan(void *priv, struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	if (drv->scan_results) {
-		CFRelease(drv->scan_results);
-		drv->scan_results = NULL;
-	}
-
-	if (ssid) {
-		CFStringRef data;
-		data = CFStringCreateWithBytes(kCFAllocatorDefault,
-					       ssid, ssid_len,
-					       kCFStringEncodingISOLatin1,
-					       FALSE);
-		if (data == NULL) {
-			wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes "
-				   "failed");
-			return -1;
-		}
-
-		err = WirelessDirectedScan(drv->wireless_ctx,
-					   &drv->scan_results, 0, data);
-		CFRelease(data);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan "
-				   "failed: 0x%08x", (unsigned int) err);
-			return -1;
-		}
-	} else {
-		err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: "
-				   "0x%08x", (unsigned int) err);
-			return -1;
-		}
-	}
-
-	eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv,
-			       drv->ctx);
-	return 0;
-}
-
-
-static void wpa_driver_osx_add_scan_entry(struct wpa_scan_results *res,
-					  WirelessNetworkInfo *info)
-{
-	struct wpa_scan_res *result, **tmp;
-	size_t extra_len;
-	u8 *pos;
-
-	extra_len = 2 + info->ssid_len;
-
-	result = os_zalloc(sizeof(*result) + extra_len);
-	if (result == NULL)
-		return;
-	os_memcpy(result->bssid, info->bssid, ETH_ALEN);
-	result->freq = 2407 + info->channel * 5;
-	//result->beacon_int =;
-	result->caps = info->capability;
-	//result->qual = info->signal;
-	result->noise = info->noise;
-
-	pos = (u8 *)(result + 1);
-
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = info->ssid_len;
-	os_memcpy(pos, info->ssid, info->ssid_len);
-	pos += info->ssid_len;
-
-	result->ie_len = pos - (u8 *)(result + 1);
-
-	tmp = os_realloc(res->res,
-			 (res->num + 1) * sizeof(struct wpa_scan_res *));
-	if (tmp == NULL) {
-		os_free(result);
-		return;
-	}
-	tmp[res->num++] = result;
-	res->res = tmp;
-}
-
-
-static struct wpa_scan_results * wpa_driver_osx_get_scan_results(void *priv)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	struct wpa_scan_results *res;
-	size_t i, num;
-
-	if (drv->scan_results == NULL)
-		return 0;
-
-	num = CFArrayGetCount(drv->scan_results);
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL)
-		return NULL;
-
-	for (i = 0; i < num; i++)
-		wpa_driver_osx_add_scan_entry(res, (WirelessNetworkInfo *)
-			CFDataGetBytePtr(CFArrayGetValueAtIndex(
-				drv->scan_results, i)));
-
-	return res;
-}
-
-
-static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_osx_data *drv = eloop_ctx;
-	u8 bssid[ETH_ALEN];
-	CFDictionaryRef ai;
-
-	if (wpa_driver_osx_get_bssid(drv, bssid) != 0) {
-		eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout,
-				       drv, drv->ctx);
-		return;
-	}
-
-	ai = WirelessGetAssociationInfo(drv->wireless_ctx);
-	if (ai) {
-		wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo");
-		CFRelease(ai);
-	} else {
-		wpa_printf(MSG_DEBUG, "OSX: Failed to get association info");
-	}
-
-	wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
-}
-
-
-static int wpa_driver_osx_associate(void *priv,
-				    struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-	CFDataRef ssid;
-	CFStringRef key;
-	int assoc_type;
-
-	ssid = CFDataCreate(kCFAllocatorDefault, params->ssid,
-			    params->ssid_len);
-	if (ssid == NULL)
-		return -1;
-
-	/* TODO: support for WEP */
-	if (params->key_mgmt_suite == KEY_MGMT_PSK) {
-		if (params->passphrase == NULL)
-			return -1;
-		key = CFStringCreateWithCString(kCFAllocatorDefault,
-						params->passphrase,
-						kCFStringEncodingISOLatin1);
-		if (key == NULL) {
-			CFRelease(ssid);
-			return -1;
-		}
-	} else
-		key = NULL;
-
-	if (params->key_mgmt_suite == KEY_MGMT_NONE)
-		assoc_type = 0;
-	else
-		assoc_type = 4;
-
-	wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)",
-		   assoc_type, key);
-	err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key);
-	CFRelease(ssid);
-	if (key)
-		CFRelease(key);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x",
-			   (unsigned int) err);
-		return -1;
-	}
-
-	/*
-	 * Driver is actually already associated; report association from an
-	 * eloop callback.
-	 */
-	eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
-	eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv,
-			       drv->ctx);
-
-	return 0;
-}
-
-
-static int wpa_driver_osx_set_key(const char *ifname, void *priv,
-				  enum wpa_alg alg, const u8 *addr,
-				  int key_idx, int set_tx, const u8 *seq,
-				  size_t seq_len, const u8 *key,
-				  size_t key_len)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-
-	if (alg == WPA_ALG_WEP) {
-		err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len,
-				     key);
-		if (err != 0) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: "
-				   "0x%08x", (unsigned int) err);
-			return -1;
-		}
-
-		return 0;
-	}
-
-	if (alg == WPA_ALG_PMK) {
-		err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key);
-		if (err != 0) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: "
-				   "0x%08x", (unsigned int) err);
-			return -1;
-		}
-		return 0;
-	}
-
-	wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg);
-	return -1;
-}
-
-
-static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-	os_memset(capa, 0, sizeof(*capa));
-
-	capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-	capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
-		WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
-	capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
-		WPA_DRIVER_AUTH_LEAP;
-	capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
-
-	return 0;
-}
-
-
-static void * wpa_driver_osx_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_osx_data *drv;
-	WirelessError err;
-	u8 enabled, power;
-
-	if (!WirelessIsAvailable()) {
-		wpa_printf(MSG_ERROR, "OSX: No wireless interface available");
-		return NULL;
-	}
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->ctx = ctx;
-	err = WirelessAttach(&drv->wireless_ctx, 0);
-	if (err) {
-		wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d",
-			   (int) err);
-		os_free(drv);
-		return NULL;
-	}
-
-	err = WirelessGetEnabled(drv->wireless_ctx, &enabled);
-	if (err)
-		wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x",
-			   (unsigned int) err);
-	err = WirelessGetPower(drv->wireless_ctx, &power);
-	if (err)
-		wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x",
-			   (unsigned int) err);
-
-	wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power);
-
-	if (!enabled) {
-		err = WirelessSetEnabled(drv->wireless_ctx, 1);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:"
-				   " 0x%08x", (unsigned int) err);
-			WirelessDetach(drv->wireless_ctx);
-			os_free(drv);
-			return NULL;
-		}
-	}
-
-	if (!power) {
-		err = WirelessSetPower(drv->wireless_ctx, 1);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: "
-				   "0x%08x", (unsigned int) err);
-			WirelessDetach(drv->wireless_ctx);
-			os_free(drv);
-			return NULL;
-		}
-	}
-
-	return drv;
-}
-
-
-static void wpa_driver_osx_deinit(void *priv)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-
-	eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx);
-	eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
-
-	err = WirelessSetPower(drv->wireless_ctx, 0);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: "
-			   "0x%08x", (unsigned int) err);
-	}
-
-	err = WirelessDetach(drv->wireless_ctx);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x",
-			   (unsigned int) err);
-	}
-
-	if (drv->scan_results)
-		CFRelease(drv->scan_results);
-
-	os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_osx_ops = {
-	.name = "osx",
-	.desc = "Mac OS X Apple80211 driver",
-	.get_ssid = wpa_driver_osx_get_ssid,
-	.get_bssid = wpa_driver_osx_get_bssid,
-	.init = wpa_driver_osx_init,
-	.deinit = wpa_driver_osx_deinit,
-	.scan2 = wpa_driver_osx_scan,
-	.get_scan_results2 = wpa_driver_osx_get_scan_results,
-	.associate = wpa_driver_osx_associate,
-	.set_key = wpa_driver_osx_set_key,
-	.get_capa = wpa_driver_osx_get_capa,
-};
diff --git a/src/drivers/driver_ralink.c b/src/drivers/driver_ralink.c
deleted file mode 100644
index a1e27be..0000000
--- a/src/drivers/driver_ralink.c
+++ /dev/null
@@ -1,1498 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with Ralink Wireless Client
- * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "driver.h"
-#include "l2_packet/l2_packet.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "priv_netlink.h"
-#include "netlink.h"
-#include "linux_ioctl.h"
-#include "driver_ralink.h"
-
-static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx);
-
-#define MAX_SSID_LEN 32
-
-struct wpa_driver_ralink_data {
-	void *ctx;
-	int ioctl_sock;
-	struct netlink_data *netlink;
-	char ifname[IFNAMSIZ + 1];
-	u8 *assoc_req_ies;
-	size_t assoc_req_ies_len;
-	u8 *assoc_resp_ies;
-	size_t assoc_resp_ies_len;
-	int no_of_pmkid;
-	struct ndis_pmkid_entry *pmkid;
-	int we_version_compiled;
-	int ap_scan;
-	int scanning_done;
-	u8 g_driver_down;
-	BOOLEAN	bAddWepKey;
-};
-
-static int ralink_set_oid(struct wpa_driver_ralink_data *drv,
-			  unsigned short oid, char *data, int len)
-{
-	char *buf;
-	struct iwreq iwr;
-
-	buf = os_zalloc(len);
-	if (buf == NULL)
-		return -1;
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.flags = oid;
-	iwr.u.data.flags |= OID_GET_SET_TOGGLE;
-
-	if (data)
-		os_memcpy(buf, data, len);
-
-	iwr.u.data.pointer = (caddr_t) buf;
-	iwr.u.data.length = len;
-
-	if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
-			   __func__, oid, len);
-		os_free(buf);
-		return -1;
-	}
-	os_free(buf);
-	return 0;
-}
-
-static int
-ralink_get_new_driver_flag(struct wpa_driver_ralink_data *drv)
-{
-	struct iwreq iwr;
-	UCHAR enabled = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (UCHAR*) &enabled;
-	iwr.u.data.flags = RT_OID_NEW_DRIVER;
-
-	if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed", __func__);
-		return 0;
-	}
-
-	return (enabled == 1) ? 1 : 0;
-}
-
-static int wpa_driver_ralink_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
-		perror("ioctl[SIOCGIWAP]");
-		ret = -1;
-	}
-	os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
-
-	return ret;
-}
-
-static int wpa_driver_ralink_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-#if 0
-	struct wpa_supplicant *wpa_s = drv->ctx;
-	struct wpa_ssid *entry;
-#endif
-	int ssid_len;
-	u8 bssid[ETH_ALEN];
-	u8 ssid_str[MAX_SSID_LEN];
-	struct iwreq iwr;
-#if 0
-	int result = 0;
-#endif
-	int ret = 0;
-#if 0
-	BOOLEAN	ieee8021x_mode = FALSE;
-	BOOLEAN ieee8021x_required_key = FALSE;
-#endif
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.essid.pointer = (caddr_t) ssid;
-	iwr.u.essid.length = 32;
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCGIWESSID]");
-		ret = -1;
-	} else
-		ret = iwr.u.essid.length;
-
-	if (ret <= 0)
-		return ret;
-
-	ssid_len = ret;
-	os_memset(ssid_str, 0, MAX_SSID_LEN);
-	os_memcpy(ssid_str, ssid, ssid_len);
-
-	if (drv->ap_scan == 0) {
-		/* Read BSSID form driver */
-		if (wpa_driver_ralink_get_bssid(priv, bssid) < 0) {
-			wpa_printf(MSG_WARNING, "Could not read BSSID from "
-				   "driver.");
-			return ret;
-		}
-
-#if 0
-		entry = wpa_s->conf->ssid;
-		while (entry) {
-			if (!entry->disabled && ssid_len == entry->ssid_len &&
-			    os_memcmp(ssid_str, entry->ssid, ssid_len) == 0 &&
-			    (!entry->bssid_set ||
-			     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) {
-				/* match the config of driver */
-				result = 1;
-				break;
-			}
-			entry = entry->next;
-		}
-
-		if (result) {
-			wpa_printf(MSG_DEBUG, "Ready to set 802.1x mode and "
-				   "ieee_required_keys parameters to driver");
-
-			/* set 802.1x mode and ieee_required_keys parameter */
-			if (entry->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-				if ((entry->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST)))
-						ieee8021x_required_key = TRUE;
-				ieee8021x_mode = TRUE;
-			}
-
-			if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, (char *) &ieee8021x_mode, sizeof(BOOLEAN)) < 0)
-			{
-				wpa_printf(MSG_DEBUG, "RALINK: Failed to set OID_802_11_SET_IEEE8021X(%d)", (int) ieee8021x_mode);
-			}
-			else
-			{
-				wpa_printf(MSG_DEBUG, "ieee8021x_mode is %s", ieee8021x_mode ? "TRUE" : "FALSE");
-			}
-
-			if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0)
-			{
-				wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", (int) ieee8021x_required_key);
-			}
-			else
-			{
-				wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d)", ieee8021x_required_key ? "TRUE" : "FALSE",
-																								entry->eapol_flags);
-			}
-		}
-#endif
-	}
-
-	return ret;
-}
-
-static int wpa_driver_ralink_set_ssid(struct wpa_driver_ralink_data *drv,
-				      const u8 *ssid, size_t ssid_len)
-{
-	NDIS_802_11_SSID *buf;
-	int ret = 0;
-	struct iwreq iwr;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	buf = os_zalloc(sizeof(NDIS_802_11_SSID));
-	if (buf == NULL)
-		return -1;
-	os_memset(buf, 0, sizeof(buf));
-	buf->SsidLength = ssid_len;
-	os_memcpy(buf->Ssid, ssid, ssid_len);
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	iwr.u.data.flags = OID_802_11_SSID;
-	iwr.u.data.flags |= OID_GET_SET_TOGGLE;
-	iwr.u.data.pointer = (caddr_t) buf;
-	iwr.u.data.length = sizeof(NDIS_802_11_SSID);
-
-	if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-		perror("ioctl[RT_PRIV_IOCTL] -- OID_802_11_SSID");
-		ret = -1;
-	}
-	os_free(buf);
-	return ret;
-}
-
-static void wpa_driver_ralink_event_pmkid(struct wpa_driver_ralink_data *drv,
-					  const u8 *data, size_t data_len)
-{
-	NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
-	size_t i;
-	union wpa_event_data event;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (data_len < 8) {
-		wpa_printf(MSG_DEBUG, "RALINK: Too short PMKID Candidate List "
-			   "Event (len=%lu)", (unsigned long) data_len);
-		return;
-	}
-	pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
-	wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List Event - Version %d"
-		   " NumCandidates %d",
-		   (int) pmkid->Version, (int) pmkid->NumCandidates);
-
-	if (pmkid->Version != 1) {
-		wpa_printf(MSG_DEBUG, "RALINK: Unsupported PMKID Candidate "
-			   "List Version %d", (int) pmkid->Version);
-		return;
-	}
-
-	if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) {
-		wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List "
-			   "underflow");
-
-		return;
-	}
-
-
-
-	os_memset(&event, 0, sizeof(event));
-	for (i = 0; i < pmkid->NumCandidates; i++) {
-		PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
-		wpa_printf(MSG_DEBUG, "RALINK: %lu: " MACSTR " Flags 0x%x",
-			   (unsigned long) i, MAC2STR(p->BSSID),
-			   (int) p->Flags);
-		os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
-		event.pmkid_candidate.index = i;
-		event.pmkid_candidate.preauth =
-			p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
-		wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE,
-				     &event);
-	}
-}
-
-static int wpa_driver_ralink_set_pmkid(struct wpa_driver_ralink_data *drv)
-{
-	int len, count, i, ret;
-	struct ndis_pmkid_entry *entry;
-	NDIS_802_11_PMKID *p;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	count = 0;
-	entry = drv->pmkid;
-	while (entry) {
-		count++;
-		if (count >= drv->no_of_pmkid)
-			break;
-		entry = entry->next;
-	}
-	len = 8 + count * sizeof(BSSID_INFO);
-	p = os_zalloc(len);
-	if (p == NULL)
-		return -1;
-	p->Length = len;
-	p->BSSIDInfoCount = count;
-	entry = drv->pmkid;
-	for (i = 0; i < count; i++) {
-		os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
-		os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
-		entry = entry->next;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID",
-		    (const u8 *) p, len);
-	ret = ralink_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
-	os_free(p);
-	return ret;
-}
-
-static int wpa_driver_ralink_add_pmkid(void *priv, const u8 *bssid,
-				       const u8 *pmkid)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct ndis_pmkid_entry *entry, *prev;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (drv->no_of_pmkid == 0)
-		return 0;
-
-	prev = NULL;
-	entry = drv->pmkid;
-	while (entry) {
-		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
-			break;
-		prev = entry;
-		entry = entry->next;
-	}
-
-	if (entry) {
-		/* Replace existing entry for this BSSID and move it into the
-		 * beginning of the list. */
-		os_memcpy(entry->pmkid, pmkid, 16);
-		if (prev) {
-			prev->next = entry->next;
-			entry->next = drv->pmkid;
-			drv->pmkid = entry;
-		}
-	} else {
-		entry = os_malloc(sizeof(*entry));
-		if (entry) {
-			os_memcpy(entry->bssid, bssid, ETH_ALEN);
-			os_memcpy(entry->pmkid, pmkid, 16);
-			entry->next = drv->pmkid;
-			drv->pmkid = entry;
-		}
-	}
-
-	return wpa_driver_ralink_set_pmkid(drv);
-}
-
-
-static int wpa_driver_ralink_remove_pmkid(void *priv, const u8 *bssid,
-					  const u8 *pmkid)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct ndis_pmkid_entry *entry, *prev;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (drv->no_of_pmkid == 0)
-		return 0;
-
-	entry = drv->pmkid;
-	prev = NULL;
-	drv->pmkid = NULL;
-	while (entry) {
-		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
-		    os_memcmp(entry->pmkid, pmkid, 16) == 0) {
-			if (prev)
-				prev->next = entry->next;
-			else
-				drv->pmkid = entry->next;
-			os_free(entry);
-			break;
-		}
-		prev = entry;
-		entry = entry->next;
-	}
-	return wpa_driver_ralink_set_pmkid(drv);
-}
-
-
-static int wpa_driver_ralink_flush_pmkid(void *priv)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	NDIS_802_11_PMKID p;
-	struct ndis_pmkid_entry *pmkid, *prev;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (drv->no_of_pmkid == 0)
-		return 0;
-
-	pmkid = drv->pmkid;
-	drv->pmkid = NULL;
-	while (pmkid) {
-		prev = pmkid;
-		pmkid = pmkid->next;
-		os_free(prev);
-	}
-
-	os_memset(&p, 0, sizeof(p));
-	p.Length = 8;
-	p.BSSIDInfoCount = 0;
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
-		    (const u8 *) &p, 8);
-	return ralink_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
-}
-
-static void
-wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv,
-					void *ctx, char *custom)
-{
-	union wpa_event_data data;
-	u8 *req_ies = NULL, *resp_ies = NULL;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
-
-	os_memset(&data, 0, sizeof(data));
-	/* Host AP driver */
-	if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
-		/* receive a MICFAILURE report */
-		data.michael_mic_failure.unicast =
-			os_strstr(custom, " unicast") != NULL;
-		/* TODO: parse parameters(?) */
-		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-	} else if (os_strncmp(custom, "ASSOCINFO_ReqIEs=", 17) == 0) {
-		/* receive assoc. req. IEs */
-		char *spos;
-		int bytes;
-
-		spos = custom + 17;
-		/*get IE's length */
-		/*
-		 * bytes = strlen(spos); ==> bug, bytes may less than original
-		 * size by using this way to get size. snowpin 20070312
-		 * if (!bytes)
-		 *	return;
-		 */
-		bytes = drv->assoc_req_ies_len;
-
-		req_ies = os_malloc(bytes);
-		if (req_ies == NULL)
-			return;
-		os_memcpy(req_ies, spos, bytes);
-		data.assoc_info.req_ies = req_ies;
-		data.assoc_info.req_ies_len = bytes;
-
-		/* skip the '\0' byte */
-		spos += bytes + 1;
-
-		data.assoc_info.resp_ies = NULL;
-		data.assoc_info.resp_ies_len = 0;
-
-		if (os_strncmp(spos, " RespIEs=", 9) == 0) {
-			/* receive assoc. resp. IEs */
-			spos += 9;
-			/* get IE's length */
-			bytes = os_strlen(spos);
-			if (!bytes)
-				goto done;
-
-			resp_ies = os_malloc(bytes);
-			if (resp_ies == NULL)
-				goto done;
-			os_memcpy(resp_ies, spos, bytes);
-			data.assoc_info.resp_ies = resp_ies;
-			data.assoc_info.resp_ies_len = bytes;
-		}
-
-		wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
-
-	done:
-		/* free allocated memory */
-		os_free(resp_ies);
-		os_free(req_ies);
-	}
-}
-
-static void ralink_interface_up(struct wpa_driver_ralink_data *drv)
-{
-	union wpa_event_data event;
-	int enable_wpa_supplicant = 0;
-	drv->g_driver_down = 0;
-	os_memset(&event, 0, sizeof(event));
-	os_snprintf(event.interface_status.ifname,
-		    sizeof(event.interface_status.ifname), "%s", drv->ifname);
-
-	event.interface_status.ievent = EVENT_INTERFACE_ADDED;
-	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
-
-	if (drv->ap_scan == 1)
-		enable_wpa_supplicant = 1;
-	else
-		enable_wpa_supplicant = 2;
-	/* trigger driver support wpa_supplicant */
-	if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-			   (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0)
-	{
-		wpa_printf(MSG_INFO, "RALINK: Failed to set "
-			   "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
-			   (int) enable_wpa_supplicant);
-		wpa_printf(MSG_ERROR, "ralink. Driver does not support "
-			   "wpa_supplicant");
-	}
-}
-
-static void
-wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
-				 void *ctx, char *data, int len)
-{
-	struct iw_event iwe_buf, *iwe = &iwe_buf;
-	char *pos, *end, *custom, *buf, *assoc_info_buf, *info_pos;
-#if 0
-	BOOLEAN ieee8021x_required_key = FALSE;
-#endif
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	assoc_info_buf = info_pos = NULL;
-	pos = data;
-	end = data + len;
-
-	while (pos + IW_EV_LCP_LEN <= end) {
-		/* Event data may be unaligned, so make a local, aligned copy
-		 * before processing. */
-		os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
-		wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
-			   iwe->cmd, iwe->len);
-		if (iwe->len <= IW_EV_LCP_LEN)
-			return;
-
-		custom = pos + IW_EV_POINT_LEN;
-
-		if (drv->we_version_compiled > 18 && iwe->cmd == IWEVCUSTOM) {
-			/* WE-19 removed the pointer from struct iw_point */
-			char *dpos = (char *) &iwe_buf.u.data.length;
-			int dlen = dpos - (char *) &iwe_buf;
-			os_memcpy(dpos, pos + IW_EV_LCP_LEN,
-				  sizeof(struct iw_event) - dlen);
-		} else {
-			os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
-			custom += IW_EV_POINT_OFF;
-		}
-
-		switch (iwe->cmd) {
-		case IWEVCUSTOM:
-			if (custom + iwe->u.data.length > end)
-				return;
-			buf = os_malloc(iwe->u.data.length + 1);
-			if (buf == NULL)
-				return;
-			os_memcpy(buf, custom, iwe->u.data.length);
-			buf[iwe->u.data.length] = '\0';
-
-			if (drv->ap_scan == 1) {
-				if ((iwe->u.data.flags == RT_ASSOC_EVENT_FLAG)
-				    || (iwe->u.data.flags ==
-					RT_REQIE_EVENT_FLAG) ||
-				    (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG)
-				    || (iwe->u.data.flags ==
-					RT_ASSOCINFO_EVENT_FLAG)) {
-					if (drv->scanning_done == 0) {
-						os_free(buf);
-						return;
-					}
-				}
-			}
-
-			if (iwe->u.data.flags == RT_ASSOC_EVENT_FLAG) {
-				wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive ASSOCIATED_EVENT !!!");
-			} else if (iwe->u.data.flags == RT_REQIE_EVENT_FLAG) {
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive ReqIEs !!!");
-				drv->assoc_req_ies =
-					os_malloc(iwe->u.data.length);
-				if (drv->assoc_req_ies == NULL) {
-					os_free(buf);
-					return;
-				}
-
-				drv->assoc_req_ies_len = iwe->u.data.length;
-				os_memcpy(drv->assoc_req_ies, custom,
-					  iwe->u.data.length);
-			} else if (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG) {
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive RespIEs !!!");
-				drv->assoc_resp_ies =
-					os_malloc(iwe->u.data.length);
-				if (drv->assoc_resp_ies == NULL) {
-					os_free(drv->assoc_req_ies);
-					drv->assoc_req_ies = NULL;
-					os_free(buf);
-					return;
-				}
-
-				drv->assoc_resp_ies_len = iwe->u.data.length;
-				os_memcpy(drv->assoc_resp_ies, custom,
-					  iwe->u.data.length);
-			} else if (iwe->u.data.flags ==
-				   RT_ASSOCINFO_EVENT_FLAG) {
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive ASSOCINFO_EVENT !!!");
-
-				assoc_info_buf =
-					os_zalloc(drv->assoc_req_ies_len +
-						  drv->assoc_resp_ies_len + 1);
-
-				if (assoc_info_buf == NULL) {
-					os_free(drv->assoc_req_ies);
-					drv->assoc_req_ies = NULL;
-					os_free(drv->assoc_resp_ies);
-					drv->assoc_resp_ies = NULL;
-					os_free(buf);
-					return;
-				}
-
-				if (drv->assoc_req_ies) {
-					os_memcpy(assoc_info_buf,
-						  drv->assoc_req_ies,
-						  drv->assoc_req_ies_len);
-				}
-				info_pos = assoc_info_buf +
-					drv->assoc_req_ies_len;
-				if (drv->assoc_resp_ies) {
-					os_memcpy(info_pos,
-						  drv->assoc_resp_ies,
-						  drv->assoc_resp_ies_len);
-				}
-				assoc_info_buf[drv->assoc_req_ies_len +
-					       drv->assoc_resp_ies_len] = '\0';
-				wpa_driver_ralink_event_wireless_custom(
-					drv, ctx, assoc_info_buf);
-				os_free(drv->assoc_req_ies);
-				drv->assoc_req_ies = NULL;
-				os_free(drv->assoc_resp_ies);
-				drv->assoc_resp_ies = NULL;
-				os_free(assoc_info_buf);
-			} else if (iwe->u.data.flags == RT_DISASSOC_EVENT_FLAG)
-			{
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive DISASSOCIATED_EVENT !!!");
-				wpa_supplicant_event(ctx, EVENT_DISASSOC,
-						     NULL);
-			} else if (iwe->u.data.flags == RT_PMKIDCAND_FLAG) {
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive PMKIDCAND_EVENT !!!");
-				wpa_driver_ralink_event_pmkid(
-					drv, (const u8 *) custom,
-					iwe->u.data.length);
-			} else if (iwe->u.data.flags == RT_INTERFACE_DOWN) {
-				drv->g_driver_down = 1;
-				eloop_terminate();
-			} else if (iwe->u.data.flags == RT_INTERFACE_UP) {
-				ralink_interface_up(drv);
-			} else {
-				wpa_driver_ralink_event_wireless_custom(
-					drv, ctx, buf);
-			}
-			os_free(buf);
-			break;
-		}
-
-		pos += iwe->len;
-	}
-}
-
-static void
-wpa_driver_ralink_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, 
-				    u8 *buf, size_t len)
-{
-	struct wpa_driver_ralink_data *drv = ctx;
-	int attrlen, rta_len;
-	struct rtattr *attr;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	wpa_hexdump(MSG_DEBUG, "ifi: ", (u8 *) ifi, sizeof(struct ifinfomsg));
-
-	attrlen = len;
-	wpa_printf(MSG_DEBUG, "attrlen=%d", attrlen);
-	attr = (struct rtattr *) buf;
-	wpa_hexdump(MSG_DEBUG, "attr1: ", (u8 *) attr, sizeof(struct rtattr));
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	wpa_hexdump(MSG_DEBUG, "attr2: ", (u8 *)attr,rta_len);
-	while (RTA_OK(attr, attrlen)) {
-		wpa_printf(MSG_DEBUG, "rta_type=%02x\n", attr->rta_type);
-		if (attr->rta_type == IFLA_WIRELESS) {
-			wpa_driver_ralink_event_wireless(
-				drv, ctx,
-				((char *) attr) + rta_len,
-				attr->rta_len - rta_len);
-		}
-		attr = RTA_NEXT(attr, attrlen);
-		wpa_hexdump(MSG_DEBUG, "attr3: ",
-			    (u8 *) attr, sizeof(struct rtattr));
-	}
-}
-
-static int
-ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv)
-{
-	struct iwreq iwr;
-	UINT we_version_compiled = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) &we_version_compiled;
-	iwr.u.data.flags = RT_OID_WE_VERSION_COMPILED;
-
-	if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed", __func__);
-		return -1;
-	}
-
-	drv->we_version_compiled = we_version_compiled;
-
-	return 0;
-}
-
-static void * wpa_driver_ralink_init(void *ctx, const char *ifname)
-{
-	int s;
-	struct wpa_driver_ralink_data *drv;
-	struct ifreq ifr;
-	UCHAR enable_wpa_supplicant = 0;
-	struct netlink_config *cfg;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	/* open socket to kernel */
-	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-		perror("socket");
-		return NULL;
-	}
-	/* do it */
-	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-
-	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
-		perror(ifr.ifr_name);
-		return NULL;
-	}
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-
-	drv->scanning_done = 1;
-	drv->ap_scan = 1; /* for now - let's assume ap_scan=1 is used */
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->ioctl_sock = s;
-	drv->g_driver_down = 0;
-
-	cfg = os_zalloc(sizeof(*cfg));
-	if (cfg == NULL) {
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-	cfg->ctx = drv;
-	cfg->newlink_cb = wpa_driver_ralink_event_rtm_newlink;
-	drv->netlink = netlink_init(cfg);
-	if (drv->netlink == NULL) {
-		os_free(cfg);
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-
-	drv->no_of_pmkid = 4; /* Number of PMKID saved supported */
-
-	linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
-	ralink_get_we_version_compiled(drv);
-	wpa_driver_ralink_flush_pmkid(drv);
-
-	if (drv->ap_scan == 1)
-		enable_wpa_supplicant = 1;
-	else
-		enable_wpa_supplicant = 2;
-	/* trigger driver support wpa_supplicant */
-	if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-			   (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0)
-	{
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
-			   (int) enable_wpa_supplicant);
-		wpa_printf(MSG_ERROR, "RALINK: Driver does not support "
-			   "wpa_supplicant");
-		close(s);
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-
-	if (drv->ap_scan == 1)
-		drv->scanning_done = 0;
-
-	return drv;
-}
-
-static void wpa_driver_ralink_deinit(void *priv)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	UCHAR enable_wpa_supplicant;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	enable_wpa_supplicant = 0;
-
-	if (drv->g_driver_down == 0) {
-		/* trigger driver disable wpa_supplicant support */
-		if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-				   (char *) &enable_wpa_supplicant,
-				   sizeof(BOOLEAN)) < 0) {
-			wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-				   "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
-				   (int) enable_wpa_supplicant);
-		}
-
-		wpa_driver_ralink_flush_pmkid(drv);
-
-		sleep(1);
-		/* linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); */
-	}
-
-	eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
-	netlink_deinit(drv->netlink);
-	close(drv->ioctl_sock);
-	os_free(drv);
-}
-
-static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_ralink_data *drv = eloop_ctx;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-
-	drv->scanning_done = 1;
-
-}
-
-static int wpa_driver_ralink_scan(void *priv,
-				  struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-#if 0
-	if (ssid_len > IW_ESSID_MAX_SIZE) {
-		wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
-			   __FUNCTION__, (unsigned long) ssid_len);
-		return -1;
-	}
-
-	/* wpa_driver_ralink_set_ssid(drv, ssid, ssid_len); */
-#endif
-
-	if (ralink_set_oid(drv, RT_OID_WPS_PROBE_REQ_IE,
-			   (char *) params->extra_ies, params->extra_ies_len) <
-	    0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "RT_OID_WPS_PROBE_REQ_IE");
-	}
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
-		perror("ioctl[SIOCSIWSCAN]");
-		ret = -1;
-	}
-
-	/* Not all drivers generate "scan completed" wireless event, so try to
-	 * read results after a timeout. */
-	eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
-	eloop_register_timeout(4, 0, wpa_driver_ralink_scan_timeout, drv,
-			       drv->ctx);
-
-	drv->scanning_done = 0;
-
-	return ret;
-}
-
-static struct wpa_scan_results *
-wpa_driver_ralink_get_scan_results(void *priv)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	UCHAR *buf = NULL;
-	size_t buf_len;
-	NDIS_802_11_BSSID_LIST_EX *wsr;
-	NDIS_WLAN_BSSID_EX *wbi;
-	struct iwreq iwr;
-	size_t ap_num;
-	u8 *pos;
-	struct wpa_scan_results *res;
-
-	if (drv->g_driver_down == 1)
-		return NULL;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (drv->we_version_compiled >= 17)
-		buf_len = 8192;
-	else
-		buf_len = 4096;
-
-	for (;;) {
-		buf = os_zalloc(buf_len);
-		iwr.u.data.length = buf_len;
-		if (buf == NULL)
-			return NULL;
-
-		wsr = (NDIS_802_11_BSSID_LIST_EX *) buf;
-
-		wsr->NumberOfItems = 0;
-		os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-		iwr.u.data.pointer = (void *) buf;
-		iwr.u.data.flags = OID_802_11_BSSID_LIST;
-
-		if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) == 0)
-			break;
-
-		if (errno == E2BIG && buf_len < 65535) {
-			os_free(buf);
-			buf = NULL;
-			buf_len *= 2;
-			if (buf_len > 65535)
-				buf_len = 65535; /* 16-bit length field */
-			wpa_printf(MSG_DEBUG, "Scan results did not fit - "
-				   "trying larger buffer (%lu bytes)",
-				   (unsigned long) buf_len);
-		} else {
-			perror("ioctl[RT_PRIV_IOCTL]");
-			os_free(buf);
-			return NULL;
-		}
-	}
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL) {
-		os_free(buf);
-		return NULL;
-	}
-
-	res->res = os_zalloc(wsr->NumberOfItems *
-			     sizeof(struct wpa_scan_res *));
-	if (res->res == NULL) {
-		os_free(res);
-		os_free(buf);
-		return NULL;
-	}
-
-	for (ap_num = 0, wbi = wsr->Bssid; ap_num < wsr->NumberOfItems;
-	     ++ap_num) {
-		struct wpa_scan_res *r = NULL;
-		size_t extra_len = 0, var_ie_len = 0;
-		u8 *pos2;
-
-		/* SSID data element */
-		extra_len += 2 + wbi->Ssid.SsidLength;
-		var_ie_len = wbi->IELength - sizeof(NDIS_802_11_FIXED_IEs);
-		r = os_zalloc(sizeof(*r) + extra_len + var_ie_len);
-		if (r == NULL)
-			break;
-		res->res[res->num++] = r;
-
-		wpa_printf(MSG_DEBUG, "SSID - %s", wbi->Ssid.Ssid);
-		/* get ie's */
-		wpa_hexdump(MSG_DEBUG, "RALINK: AP IEs",
-			    (u8 *) &wbi->IEs[0], wbi->IELength);
-
-		os_memcpy(r->bssid, wbi->MacAddress, ETH_ALEN);
-
-		extra_len += (2 + wbi->Ssid.SsidLength);
-		r->ie_len = extra_len + var_ie_len;
-		pos2 = (u8 *) (r + 1);
-
-		/*
-		 * Generate a fake SSID IE since the driver did not report
-		 * a full IE list.
-		 */
-		*pos2++ = WLAN_EID_SSID;
-		*pos2++ = wbi->Ssid.SsidLength;
-		os_memcpy(pos2, wbi->Ssid.Ssid, wbi->Ssid.SsidLength);
-		pos2 += wbi->Ssid.SsidLength;
-
-		r->freq = (wbi->Configuration.DSConfig / 1000);
-
-		pos = (u8 *) wbi + sizeof(*wbi) - 1;
-
-		pos += sizeof(NDIS_802_11_FIXED_IEs) - 2;
-		os_memcpy(&(r->caps), pos, 2);
-		pos += 2;
-
-		if (wbi->IELength > sizeof(NDIS_802_11_FIXED_IEs))
-			os_memcpy(pos2, pos, var_ie_len);
-
-		wbi = (NDIS_WLAN_BSSID_EX *) ((u8 *) wbi + wbi->Length);
-	}
-
-	os_free(buf);
-	return res;
-}
-
-static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv,
-				NDIS_802_11_AUTHENTICATION_MODE mode)
-{
-	NDIS_802_11_AUTHENTICATION_MODE auth_mode = mode;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (ralink_set_oid(drv, OID_802_11_AUTHENTICATION_MODE,
-			   (char *) &auth_mode, sizeof(auth_mode)) < 0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "OID_802_11_AUTHENTICATION_MODE (%d)",
-			   (int) auth_mode);
-		return -1;
-	}
-	return 0;
-}
-
-static int ralink_set_encr_type(struct wpa_driver_ralink_data *drv,
-				NDIS_802_11_WEP_STATUS encr_type)
-{
-	NDIS_802_11_WEP_STATUS wep_status = encr_type;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (ralink_set_oid(drv, OID_802_11_WEP_STATUS,
-			   (char *) &wep_status, sizeof(wep_status)) < 0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "OID_802_11_WEP_STATUS (%d)",
-			   (int) wep_status);
-		return -1;
-	}
-	return 0;
-}
-
-
-static int wpa_driver_ralink_remove_key(struct wpa_driver_ralink_data *drv,
-					int key_idx, const u8 *addr,
-					const u8 *bssid, int pairwise)
-{
-	NDIS_802_11_REMOVE_KEY rkey;
-	NDIS_802_11_KEY_INDEX _index;
-	int res, res2;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	os_memset(&rkey, 0, sizeof(rkey));
-
-	rkey.Length = sizeof(rkey);
-	rkey.KeyIndex = key_idx;
-
-	if (pairwise)
-		rkey.KeyIndex |= 1 << 30;
-
-	os_memcpy(rkey.BSSID, bssid, ETH_ALEN);
-
-	res = ralink_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey,
-			     sizeof(rkey));
-
-	/* AlbertY@20060210 removed it */
-	if (0 /* !pairwise */) {
-		res2 = ralink_set_oid(drv, OID_802_11_REMOVE_WEP,
-				      (char *) &_index, sizeof(_index));
-	} else
-		res2 = 0;
-
-	if (res < 0 && res2 < 0)
-		return res;
-	return 0;
-}
-
-static int wpa_driver_ralink_add_wep(struct wpa_driver_ralink_data *drv,
-				     int pairwise, int key_idx, int set_tx,
-				     const u8 *key, size_t key_len)
-{
-	NDIS_802_11_WEP *wep;
-	size_t len;
-	int res;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	len = 12 + key_len;
-	wep = os_zalloc(len);
-	if (wep == NULL)
-		return -1;
-
-	wep->Length = len;
-	wep->KeyIndex = key_idx;
-
-	if (set_tx)
-		wep->KeyIndex |= 0x80000000;
-
-	wep->KeyLength = key_len;
-	os_memcpy(wep->KeyMaterial, key, key_len);
-
-	wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_WEP",
-			(const u8 *) wep, len);
-	res = ralink_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
-
-	os_free(wep);
-
-	return res;
-}
-
-static int wpa_driver_ralink_set_key(const char *ifname, void *priv,
-				     enum wpa_alg alg, const u8 *addr,
-				     int key_idx, int set_tx,
-				     const u8 *seq, size_t seq_len,
-				     const u8 *key, size_t key_len)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	size_t len, i;
-	NDIS_802_11_KEY *nkey;
-	int res, pairwise;
-	u8 bssid[ETH_ALEN];
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	drv->bAddWepKey = FALSE;
-
-	if (addr == NULL || is_broadcast_ether_addr(addr)) {
-		/* Group Key */
-		pairwise = 0;
-		wpa_driver_ralink_get_bssid(drv, bssid);
-	} else {
-		/* Pairwise Key */
-		pairwise = 1;
-		os_memcpy(bssid, addr, ETH_ALEN);
-	}
-
-	if (alg == WPA_ALG_NONE || key_len == 0) {
-		return wpa_driver_ralink_remove_key(drv, key_idx, addr, bssid,
-						    pairwise);
-	}
-
-	if (alg == WPA_ALG_WEP) {
-		drv->bAddWepKey = TRUE;
-		return wpa_driver_ralink_add_wep(drv, pairwise, key_idx,
-						 set_tx, key, key_len);
-	}
-
-	len = 12 + 6 + 6 + 8 + key_len;
-
-	nkey = os_zalloc(len);
-	if (nkey == NULL)
-		return -1;
-
-	nkey->Length = len;
-	nkey->KeyIndex = key_idx;
-
-	if (set_tx)
-		nkey->KeyIndex |= 1 << 31;
-
-	if (pairwise)
-		nkey->KeyIndex |= 1 << 30;
-
-	if (seq && seq_len)
-		nkey->KeyIndex |= 1 << 29;
-
-	nkey->KeyLength = key_len;
-	os_memcpy(nkey->BSSID, bssid, ETH_ALEN);
-
-	if (seq && seq_len) {
-		for (i = 0; i < seq_len; i++)
-			nkey->KeyRSC |= seq[i] << (i * 8);
-	}
-	if (alg == WPA_ALG_TKIP && key_len == 32) {
-		os_memcpy(nkey->KeyMaterial, key, 16);
-		os_memcpy(nkey->KeyMaterial + 16, key + 24, 8);
-		os_memcpy(nkey->KeyMaterial + 24, key + 16, 8);
-	} else {
-		os_memcpy(nkey->KeyMaterial, key, key_len);
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
-		   "key_len=%lu", __FUNCTION__, alg, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-
-	wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_KEY",
-			(const u8 *) nkey, len);
-	res = ralink_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
-	os_free(nkey);
-
-	return res;
-}
-
-static int wpa_driver_ralink_disassociate(void *priv, const u8 *addr,
-					int reason_code)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	if (ralink_set_oid(drv, OID_802_11_DISASSOCIATE, "    ", 4) < 0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "OID_802_11_DISASSOCIATE");
-	}
-
-	return 0;
-}
-
-static int wpa_driver_ralink_deauthenticate(void *priv, const u8 *addr,
-					  int reason_code)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-
-	wpa_printf(MSG_DEBUG, "g_driver_down = %d", drv->g_driver_down);
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	if (ralink_get_new_driver_flag(drv) == 0) {
-		return wpa_driver_ralink_disassociate(priv, addr, reason_code);
-	} else {
-		MLME_DEAUTH_REQ_STRUCT mlme;
-		os_memset(&mlme, 0, sizeof(MLME_DEAUTH_REQ_STRUCT));
-		mlme.Reason = reason_code;
-		os_memcpy(mlme.Addr, addr, MAC_ADDR_LEN);
-		return ralink_set_oid(drv, OID_802_11_DEAUTHENTICATION,
-				      (char *) &mlme,
-				      sizeof(MLME_DEAUTH_REQ_STRUCT));
-	}
-}
-
-static int wpa_driver_ralink_set_gen_ie(void *priv, const u8 *ie,
-					size_t ie_len)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) ie;
-	iwr.u.data.length = ie_len;
-
-	wpa_hexdump(MSG_DEBUG, "wpa_driver_ralink_set_gen_ie: ",
-		    (u8 *) ie, ie_len);
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
-		perror("ioctl[SIOCSIWGENIE]");
-		ret = -1;
-	}
-
-	return ret;
-}
-
-static int
-wpa_driver_ralink_associate(void *priv,
-			    struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-
-	NDIS_802_11_NETWORK_INFRASTRUCTURE mode;
-	NDIS_802_11_AUTHENTICATION_MODE auth_mode;
-	NDIS_802_11_WEP_STATUS encr;
-	BOOLEAN		ieee8021xMode;
-	BOOLEAN 	ieee8021x_required_key = TRUE;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (params->mode == IEEE80211_MODE_IBSS)
-		mode = Ndis802_11IBSS;
-	else
-		mode = Ndis802_11Infrastructure;
-
-	if (ralink_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
-			 (char *) &mode, sizeof(mode)) < 0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "OID_802_11_INFRASTRUCTURE_MODE (%d)",
-			   (int) mode);
-		/* Try to continue anyway */
-	}
-
-	if (params->key_mgmt_suite == KEY_MGMT_WPS) {
-		UCHAR enable_wps = 0x80;
-		/* trigger driver support wpa_supplicant */
-		if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-				   (PCHAR) &enable_wps, sizeof(UCHAR)) < 0) {
-			wpa_printf(MSG_INFO, "RALINK: Failed to set "
-				   "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)",
-				   (int) enable_wps);
-		}
-
-		wpa_driver_ralink_set_gen_ie(priv, params->wpa_ie,
-					     params->wpa_ie_len);
-
-		ralink_set_auth_mode(drv, Ndis802_11AuthModeOpen);
-
-		ralink_set_encr_type(drv, Ndis802_11EncryptionDisabled);
-	} else {
-#ifdef CONFIG_WPS
-		UCHAR enable_wpa_supplicant;
-
-		if (drv->ap_scan == 1)
-			enable_wpa_supplicant = 0x01;
-		else
-			enable_wpa_supplicant = 0x02;
-
-		/* trigger driver support wpa_supplicant */
-		if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-				   (PCHAR) &enable_wpa_supplicant,
-				   sizeof(UCHAR)) < 0) {
-			wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-				   "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)",
-				   (int) enable_wpa_supplicant);
-		}
-
-		wpa_driver_ralink_set_gen_ie(priv, (u8 *) "", 0);
-#endif /* CONFIG_WPS */
-
-		if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
-			if (params->auth_alg & WPA_AUTH_ALG_SHARED) {
-				if (params->auth_alg & WPA_AUTH_ALG_OPEN)
-					auth_mode = Ndis802_11AuthModeAutoSwitch;
-				else
-					auth_mode = Ndis802_11AuthModeShared;
-			} else
-				auth_mode = Ndis802_11AuthModeOpen;
-		} else if (params->wpa_ie[0] == WLAN_EID_RSN) {
-			if (params->key_mgmt_suite == KEY_MGMT_PSK)
-				auth_mode = Ndis802_11AuthModeWPA2PSK;
-			else
-				auth_mode = Ndis802_11AuthModeWPA2;
-		} else {
-			if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
-				auth_mode = Ndis802_11AuthModeWPANone;
-			else if (params->key_mgmt_suite == KEY_MGMT_PSK)
-				auth_mode = Ndis802_11AuthModeWPAPSK;
-			else
-				auth_mode = Ndis802_11AuthModeWPA;
-		}
-
-		switch (params->pairwise_suite) {
-		case CIPHER_CCMP:
-			encr = Ndis802_11Encryption3Enabled;
-			break;
-		case CIPHER_TKIP:
-			encr = Ndis802_11Encryption2Enabled;
-			break;
-		case CIPHER_WEP40:
-		case CIPHER_WEP104:
-			encr = Ndis802_11Encryption1Enabled;
-			break;
-		case CIPHER_NONE:
-			if (params->group_suite == CIPHER_CCMP)
-				encr = Ndis802_11Encryption3Enabled;
-			else if (params->group_suite == CIPHER_TKIP)
-				encr = Ndis802_11Encryption2Enabled;
-			else
-				encr = Ndis802_11EncryptionDisabled;
-			break;
-		default:
-			encr = Ndis802_11EncryptionDisabled;
-			break;
-		}
-
-		ralink_set_auth_mode(drv, auth_mode);
-
-		/* notify driver that IEEE8021x mode is enabled */
-		if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
-			ieee8021xMode = TRUE;
-			if (drv->bAddWepKey)
-				ieee8021x_required_key = FALSE;
-		} else
-			ieee8021xMode = FALSE;
-
-		if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY,
-				   (char *) &ieee8021x_required_key,
-				   sizeof(BOOLEAN)) < 0) {
-			wpa_printf(MSG_DEBUG, "ERROR: Failed to set "
-				   "OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)",
-				   (int) ieee8021x_required_key);
-		} else {
-			wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s",
-				   ieee8021x_required_key ? "TRUE" : "FALSE");
-		}
-
-		if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X,
-				   (char *) &ieee8021xMode, sizeof(BOOLEAN)) <
-		    0) {
-			wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-				   "OID_802_11_SET_IEEE8021X(%d)",
-				   (int) ieee8021xMode);
-		}
-
-		ralink_set_encr_type(drv, encr);
-
-		if ((ieee8021xMode == FALSE) &&
-		    (encr == Ndis802_11Encryption1Enabled)) {
-			/* static WEP */
-			int enabled = 0;
-			if (ralink_set_oid(drv, OID_802_11_DROP_UNENCRYPTED,
-					   (char *) &enabled, sizeof(enabled))
-			    < 0) {
-				wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-					   "OID_802_11_DROP_UNENCRYPTED(%d)",
-					   (int) encr);
-			}
-		}
-	}
-
-	return wpa_driver_ralink_set_ssid(drv, params->ssid, params->ssid_len);
-}
-
-static int
-wpa_driver_ralink_set_countermeasures(void *priv, int enabled)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	if (drv->g_driver_down == 1)
-		return -1;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return ralink_set_oid(drv, OID_SET_COUNTERMEASURES, (char *) &enabled,
-			      sizeof(int));
-}
-
-const struct wpa_driver_ops wpa_driver_ralink_ops = {
-	.name = "ralink",
-	.desc = "Ralink Wireless Client driver",
-	.get_bssid = wpa_driver_ralink_get_bssid,
-	.get_ssid = wpa_driver_ralink_get_ssid,
-	.set_key = wpa_driver_ralink_set_key,
-	.init = wpa_driver_ralink_init,
-	.deinit = wpa_driver_ralink_deinit,
-	.set_countermeasures	= wpa_driver_ralink_set_countermeasures,
-	.scan2 = wpa_driver_ralink_scan,
-	.get_scan_results2 = wpa_driver_ralink_get_scan_results,
-	.deauthenticate = wpa_driver_ralink_deauthenticate,
-	.disassociate = wpa_driver_ralink_disassociate,
-	.associate = wpa_driver_ralink_associate,
-	.add_pmkid = wpa_driver_ralink_add_pmkid,
-	.remove_pmkid = wpa_driver_ralink_remove_pmkid,
-	.flush_pmkid = wpa_driver_ralink_flush_pmkid,
-};
diff --git a/src/drivers/driver_ralink.h b/src/drivers/driver_ralink.h
deleted file mode 100644
index d13df28..0000000
--- a/src/drivers/driver_ralink.h
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * WPA Supplicant - driver_ralink exported functions
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-// Ralink defined OIDs
-#if WIRELESS_EXT <= 11
-#ifndef SIOCDEVPRIVATE
-#define SIOCDEVPRIVATE                              0x8BE0
-#endif
-#define SIOCIWFIRSTPRIV								SIOCDEVPRIVATE
-#endif
-
-#define RT_PRIV_IOCTL								(SIOCIWFIRSTPRIV + 0x0E)  
-#define RTPRIV_IOCTL_SET							(SIOCIWFIRSTPRIV + 0x02)
-
-// IEEE 802.11 OIDs  &  Ralink defined OIDs  ******
-
-// (RaConfig Set/QueryInform) ==>
-#define OID_GET_SET_TOGGLE							0x8000
-
-#define OID_802_11_ADD_WEP                          0x0112
-#define OID_802_11_REMOVE_WEP                       0x0113
-#define OID_802_11_DISASSOCIATE                     0x0114
-#define OID_802_11_PRIVACY_FILTER                   0x0118
-#define OID_802_11_ASSOCIATION_INFORMATION          0x011E
-#define OID_802_11_BSSID_LIST_SCAN                  0x0508
-#define OID_802_11_SSID                             0x0509
-#define OID_802_11_BSSID                            0x050A
-#define OID_802_11_WEP_STATUS                       0x0510
-#define OID_802_11_AUTHENTICATION_MODE              0x0511
-#define OID_802_11_INFRASTRUCTURE_MODE              0x0512
-#define OID_802_11_TX_POWER_LEVEL                   0x0517
-#define OID_802_11_REMOVE_KEY                       0x0519
-#define OID_802_11_ADD_KEY                          0x0520
-#define OID_802_11_DEAUTHENTICATION                 0x0526
-#define OID_802_11_DROP_UNENCRYPTED                 0x0527
-#define OID_802_11_BSSID_LIST                       0x0609
-#define OID_802_3_CURRENT_ADDRESS                   0x060A
-#define OID_SET_COUNTERMEASURES                     0x0616
-#define OID_802_11_SET_IEEE8021X                    0x0617	// For IEEE8021x mode 
-#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY        0x0618  // For DynamicWEP in IEEE802.1x mode
-#define OID_802_11_PMKID                            0x0620
-#define RT_OID_WPA_SUPPLICANT_SUPPORT               0x0621  // for trigger driver enable/disable wpa_supplicant support 
-#define RT_OID_WE_VERSION_COMPILED                  0x0622
-#define RT_OID_NEW_DRIVER                           0x0623
-#define RT_OID_WPS_PROBE_REQ_IE						0x0625
-
-#define PACKED  __attribute__ ((packed))
-
-//wpa_supplicant event flags
-#define	RT_ASSOC_EVENT_FLAG                         0x0101
-#define	RT_DISASSOC_EVENT_FLAG                      0x0102
-#define	RT_REQIE_EVENT_FLAG                         0x0103
-#define	RT_RESPIE_EVENT_FLAG                        0x0104
-#define	RT_ASSOCINFO_EVENT_FLAG                     0x0105
-#define RT_PMKIDCAND_FLAG                           0x0106
-#define RT_INTERFACE_DOWN                           0x0107
-#define RT_INTERFACE_UP                           	0x0108
-
-//
-// IEEE 802.11 Structures and definitions
-//
-// new types for Media Specific Indications
-
-#ifndef ULONG
-#define CHAR            char
-#define INT             int
-#define SHORT           int
-#define UINT            u32
-#undef  ULONG           
-//#define ULONG           u32
-#define ULONG           unsigned long /* 32-bit in 32-bit CPU or 64-bit in 64-bit CPU */
-#define USHORT          unsigned short
-#define UCHAR           unsigned char
-
-#define uint32		u32
-#define uint8		u8
-
-
-#define BOOLEAN         u8
-//#define LARGE_INTEGER s64
-#define VOID            void
-#define LONG            long
-#define LONGLONG        s64
-#define ULONGLONG       u64
-typedef VOID            *PVOID;
-typedef CHAR            *PCHAR;
-typedef UCHAR           *PUCHAR;
-typedef USHORT          *PUSHORT;
-typedef LONG            *PLONG;
-typedef ULONG           *PULONG;
-
-typedef union _LARGE_INTEGER {
-    struct {
-        ULONG LowPart;
-        LONG HighPart;
-    }vv;
-    struct {
-        ULONG LowPart;
-        LONG HighPart;
-    } u;
-    s64 QuadPart;
-} LARGE_INTEGER;
-
-#endif
-
-#define NDIS_802_11_LENGTH_SSID         32
-#define NDIS_802_11_LENGTH_RATES        8
-#define NDIS_802_11_LENGTH_RATES_EX     16
-#define MAX_LEN_OF_SSID                 32
-#define MAC_ADDR_LEN                    6
-
-typedef UCHAR   NDIS_802_11_MAC_ADDRESS[6];
-
-// mask for authentication/integrity fields
-#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS        0x0f
-
-#define NDIS_802_11_AUTH_REQUEST_REAUTH             0x01
-#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE          0x02
-#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR     0x06
-#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR        0x0E
-
-// Added new types for OFDM 5G and 2.4G
-typedef enum _NDIS_802_11_NETWORK_TYPE
-{
-    Ndis802_11FH, 
-    Ndis802_11DS, 
-    Ndis802_11OFDM5,
-    Ndis802_11OFDM24,
-    Ndis802_11Automode,
-    Ndis802_11NetworkTypeMax    // not a real type, defined as an upper bound
-} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE;
-
-//
-// Received Signal Strength Indication
-//
-typedef LONG    NDIS_802_11_RSSI;           // in dBm
-
-typedef struct _NDIS_802_11_CONFIGURATION_FH
-{
-   ULONG           Length;            // Length of structure
-   ULONG           HopPattern;        // As defined by 802.11, MSB set 
-   ULONG           HopSet;            // to one if non-802.11
-   ULONG           DwellTime;         // units are Kusec
-} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH;
-
-typedef struct _NDIS_802_11_CONFIGURATION
-{
-   ULONG                           Length;             // Length of structure
-   ULONG                           BeaconPeriod;       // units are Kusec
-   ULONG                           ATIMWindow;         // units are Kusec
-   ULONG                           DSConfig;           // Frequency, units are kHz
-   NDIS_802_11_CONFIGURATION_FH    FHConfig;
-} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION;
-
-typedef  ULONG  NDIS_802_11_KEY_INDEX;
-typedef ULONGLONG   NDIS_802_11_KEY_RSC;
-
-// Key mapping keys require a BSSID
-typedef struct _NDIS_802_11_KEY
-{
-    UINT           Length;             // Length of this structure
-    UINT           KeyIndex;           
-    UINT           KeyLength;          // length of key in bytes
-    NDIS_802_11_MAC_ADDRESS BSSID;
-    NDIS_802_11_KEY_RSC KeyRSC;
-    UCHAR           KeyMaterial[1];     // variable length depending on above field
-} NDIS_802_11_KEY, *PNDIS_802_11_KEY;
-
-typedef struct _NDIS_802_11_REMOVE_KEY
-{
-    UINT                   Length;        // Length of this structure
-    UINT                   KeyIndex;           
-    NDIS_802_11_MAC_ADDRESS BSSID;      
-} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY;
-
-typedef struct PACKED _NDIS_802_11_WEP
-{
-   UINT     Length;        // Length of this structure
-   UINT           KeyIndex;           // 0 is the per-client key, 1-N are the
-                                        // global keys
-   UINT     KeyLength;     // length of key in bytes
-   UCHAR     KeyMaterial[1];// variable length depending on above field
-} NDIS_802_11_WEP, *PNDIS_802_11_WEP;
-
-
-typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE
-{
-   Ndis802_11IBSS,
-   Ndis802_11Infrastructure,
-   Ndis802_11AutoUnknown,
-   Ndis802_11InfrastructureMax     // Not a real value, defined as upper bound
-} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE;
-
-// PMKID Structures
-typedef UCHAR   NDIS_802_11_PMKID_VALUE[16];
-
-typedef struct _BSSID_INFO
-{
-	NDIS_802_11_MAC_ADDRESS BSSID;
-	NDIS_802_11_PMKID_VALUE PMKID;
-} BSSID_INFO, *PBSSID_INFO;
-
-typedef struct _NDIS_802_11_PMKID
-{
-	ULONG Length;
-	ULONG BSSIDInfoCount;
-	BSSID_INFO BSSIDInfo[1];
-} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID;
-
-//Added new types for PMKID Candidate lists.
-typedef struct _PMKID_CANDIDATE {
-	NDIS_802_11_MAC_ADDRESS BSSID;
-	ULONG Flags;
-} PMKID_CANDIDATE, *PPMKID_CANDIDATE;
-
-typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST
-{
-	ULONG Version;       // Version of the structure
-	ULONG NumCandidates; // No. of pmkid candidates
-	PMKID_CANDIDATE CandidateList[1];
-} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST;
-
-//Flags for PMKID Candidate list structure
-#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED	0x01
-
-// Add new authentication modes
-typedef enum _NDIS_802_11_AUTHENTICATION_MODE
-{
-   Ndis802_11AuthModeOpen,
-   Ndis802_11AuthModeShared,
-   Ndis802_11AuthModeAutoSwitch,
-   Ndis802_11AuthModeWPA,
-   Ndis802_11AuthModeWPAPSK,
-   Ndis802_11AuthModeWPANone,
-   Ndis802_11AuthModeWPA2,
-   Ndis802_11AuthModeWPA2PSK,    
-   Ndis802_11AuthModeMax           // Not a real mode, defined as upper bound
-} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE;
-
-typedef UCHAR  NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES];        // Set of 8 data rates
-typedef UCHAR  NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX];  // Set of 16 data rates
-
-typedef struct PACKED _NDIS_802_11_SSID 
-{
-    INT   SsidLength;         // length of SSID field below, in bytes;
-                                // this can be zero.
-    UCHAR   Ssid[NDIS_802_11_LENGTH_SSID];           // SSID information field
-} NDIS_802_11_SSID, *PNDIS_802_11_SSID;
-
-
-typedef struct PACKED _NDIS_WLAN_BSSID
-{
-   ULONG                               Length;     // Length of this structure
-   NDIS_802_11_MAC_ADDRESS             MacAddress; // BSSID
-   UCHAR                               Reserved[2];
-   NDIS_802_11_SSID                    Ssid;       // SSID
-   ULONG                               Privacy;    // WEP encryption requirement
-    NDIS_802_11_RSSI                    Rssi;               // receive signal
-                                                            // strength in dBm
-   NDIS_802_11_NETWORK_TYPE            NetworkTypeInUse;
-   NDIS_802_11_CONFIGURATION           Configuration;
-   NDIS_802_11_NETWORK_INFRASTRUCTURE  InfrastructureMode;
-   NDIS_802_11_RATES                   SupportedRates;
-} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID;
-
-typedef struct PACKED _NDIS_802_11_BSSID_LIST
-{
-   UINT             NumberOfItems;      // in list below, at least 1
-   NDIS_WLAN_BSSID Bssid[1];
-} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST;
-
-// Added Capabilities, IELength and IEs for each BSSID
-typedef struct PACKED _NDIS_WLAN_BSSID_EX
-{
-    ULONG                               Length;             // Length of this structure
-    NDIS_802_11_MAC_ADDRESS             MacAddress;         // BSSID
-    UCHAR                               Reserved[2];
-    NDIS_802_11_SSID                    Ssid;               // SSID
-    UINT                                Privacy;            // WEP encryption requirement
-    NDIS_802_11_RSSI                    Rssi;               // receive signal
-                                                            // strength in dBm
-    NDIS_802_11_NETWORK_TYPE            NetworkTypeInUse;
-    NDIS_802_11_CONFIGURATION           Configuration;
-    NDIS_802_11_NETWORK_INFRASTRUCTURE  InfrastructureMode;
-    NDIS_802_11_RATES_EX                SupportedRates;
-    ULONG                               IELength;
-    UCHAR                               IEs[1];
-} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX;
-
-typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX
-{
-    UINT                   NumberOfItems;      // in list below, at least 1
-    NDIS_WLAN_BSSID_EX      Bssid[1];
-} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX;
-
-typedef struct PACKED _NDIS_802_11_FIXED_IEs 
-{
-    UCHAR Timestamp[8];
-    USHORT BeaconInterval;
-    USHORT Capabilities;
-} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs;
-
-// Added new encryption types
-// Also aliased typedef to new name
-typedef enum _NDIS_802_11_WEP_STATUS
-{
-   Ndis802_11WEPEnabled,
-   Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
-   Ndis802_11WEPDisabled,
-   Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
-   Ndis802_11WEPKeyAbsent,
-   Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
-   Ndis802_11WEPNotSupported,
-   Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
-   Ndis802_11Encryption2Enabled,
-   Ndis802_11Encryption2KeyAbsent,
-   Ndis802_11Encryption3Enabled,
-   Ndis802_11Encryption3KeyAbsent
-} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS,
-  NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS;
-
-typedef enum _NDIS_802_11_RELOAD_DEFAULTS
-{
-   Ndis802_11ReloadWEPKeys
-} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS;
-
-#define NDIS_802_11_AI_REQFI_CAPABILITIES      1
-#define NDIS_802_11_AI_REQFI_LISTENINTERVAL    2
-#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS  4
-
-#define NDIS_802_11_AI_RESFI_CAPABILITIES      1
-#define NDIS_802_11_AI_RESFI_STATUSCODE        2
-#define NDIS_802_11_AI_RESFI_ASSOCIATIONID     4
-
-typedef struct _NDIS_802_11_AI_REQFI
-{
-    USHORT Capabilities;
-    USHORT ListenInterval;
-    NDIS_802_11_MAC_ADDRESS  CurrentAPAddress;
-} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI;
-
-typedef struct _NDIS_802_11_AI_RESFI
-{
-    USHORT Capabilities;
-    USHORT StatusCode;
-    USHORT AssociationId;
-} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI;
-
-typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION
-{
-    ULONG                   Length;
-    USHORT                  AvailableRequestFixedIEs;
-    NDIS_802_11_AI_REQFI    RequestFixedIEs;
-    ULONG                   RequestIELength;
-    ULONG                   OffsetRequestIEs;
-    USHORT                  AvailableResponseFixedIEs;
-    NDIS_802_11_AI_RESFI    ResponseFixedIEs;
-    ULONG                   ResponseIELength;
-    ULONG                   OffsetResponseIEs;
-} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION;
-
-struct ndis_pmkid_entry {
-	struct ndis_pmkid_entry *next;
-	u8 bssid[ETH_ALEN];
-	u8 pmkid[16];
-};
-
-typedef struct _MLME_DEAUTH_REQ_STRUCT {
-    UCHAR        Addr[MAC_ADDR_LEN];
-    USHORT       Reason;
-} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT;
diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c
index c014b96..61b75b1 100644
--- a/src/drivers/driver_roboswitch.c
+++ b/src/drivers/driver_roboswitch.c
@@ -364,7 +364,7 @@
 	/* copy ifname and take a pointer to the second to last character */
 	sep = drv->ifname +
 	      os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)) - 2;
-	/* find the '.' seperating <interface> and <vlan> */
+	/* find the '.' separating <interface> and <vlan> */
 	while (sep > drv->ifname && *sep != '.') sep--;
 	if (sep <= drv->ifname) {
 		wpa_printf(MSG_INFO, "%s: No <interface>.<vlan> pair in "
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index 6bfa46d..f8e314b 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -89,7 +89,6 @@
 	int use_associnfo;
 	u8 assoc_wpa_ie[80];
 	size_t assoc_wpa_ie_len;
-	int use_mlme;
 	int associated;
 	u8 *probe_req_ie;
 	size_t probe_req_ie_len;
@@ -117,6 +116,7 @@
 	u8 pending_action_dst[ETH_ALEN];
 	u8 pending_action_bssid[ETH_ALEN];
 	unsigned int pending_action_freq;
+	unsigned int pending_action_no_cck;
 	unsigned int pending_listen_freq;
 	unsigned int pending_listen_duration;
 	int pending_p2p_scan;
@@ -309,7 +309,7 @@
 
 
 static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
-				     size_t data_len)
+				     size_t data_len, int noack)
 {
 	struct test_driver_bss *dbss = priv;
 	struct wpa_driver_test_data *drv = dbss->drv;
@@ -561,7 +561,7 @@
 		wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event);
 #ifdef CONFIG_P2P
 		if (drv->p2p)
-			p2p_probe_req_rx(drv->p2p, sa, ie, ielen);
+			p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen);
 #endif /* CONFIG_P2P */
 	}
 
@@ -1102,13 +1102,6 @@
 }
 
 
-static int test_driver_valid_bss_mask(void *priv, const u8 *addr,
-				      const u8 *mask)
-{
-	return 0;
-}
-
-
 static int test_driver_set_ssid(void *priv, const u8 *buf, int len)
 {
 	struct test_driver_bss *bss = priv;
@@ -1232,6 +1225,7 @@
 		return NULL;
 	drv->ap = 1;
 	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+	drv->global = params->global_priv;
 
 	bss->bss_ctx = hapd;
 	os_memcpy(bss->bssid, drv->own_addr, ETH_ALEN);
@@ -1966,6 +1960,8 @@
 		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) {
 			os_memset(&event, 0, sizeof(event));
 			event.rx_probe_req.sa = mgmt->sa;
+			event.rx_probe_req.da = mgmt->da;
+			event.rx_probe_req.bssid = mgmt->bssid;
 			event.rx_probe_req.ie = mgmt->u.probe_req.variable;
 			event.rx_probe_req.ie_len =
 				data_len - (mgmt->u.probe_req.variable - data);
@@ -1974,6 +1970,7 @@
 #ifdef CONFIG_P2P
 			if (drv->p2p)
 				p2p_probe_req_rx(drv->p2p, mgmt->sa,
+						 mgmt->da, mgmt->bssid,
 						 event.rx_probe_req.ie,
 						 event.rx_probe_req.ie_len);
 #endif /* CONFIG_P2P */
@@ -2028,7 +2025,7 @@
 			ielen = 0;
 		drv->probe_from = from;
 		drv->probe_from_len = fromlen;
-		p2p_probe_req_rx(drv->p2p, sa, ie, ielen);
+		p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen);
 		drv->probe_from = NULL;
 	}
 #endif /* CONFIG_P2P */
@@ -2390,13 +2387,6 @@
 		drv->use_associnfo = 1;
 	}
 
-#ifdef CONFIG_CLIENT_MLME
-	if (os_strstr(param, "use_mlme=1")) {
-		wpa_printf(MSG_DEBUG, "test_driver: Use internal MLME");
-		drv->use_mlme = 1;
-	}
-#endif /* CONFIG_CLIENT_MLME */
-
 	if (os_strstr(param, "p2p_mgmt=1")) {
 		wpa_printf(MSG_DEBUG, "test_driver: Use internal P2P "
 			   "management");
@@ -2510,8 +2500,6 @@
 	capa->auth = WPA_DRIVER_AUTH_OPEN |
 		WPA_DRIVER_AUTH_SHARED |
 		WPA_DRIVER_AUTH_LEAP;
-	if (drv->use_mlme)
-		capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
 	if (drv->p2p)
 		capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT;
 	capa->flags |= WPA_DRIVER_FLAGS_AP;
@@ -2541,50 +2529,6 @@
 }
 
 
-static int wpa_driver_test_set_channel(void *priv,
-				       enum hostapd_hw_mode phymode,
-				       int chan, int freq)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d",
-		   __func__, phymode, chan, freq);
-	drv->current_freq = freq;
-	return 0;
-}
-
-
-static int wpa_driver_test_mlme_add_sta(void *priv, const u8 *addr,
-					const u8 *supp_rates,
-					size_t supp_rates_len)
-{
-	wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
-	return 0;
-}
-
-
-static int wpa_driver_test_mlme_remove_sta(void *priv, const u8 *addr)
-{
-	wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
-	return 0;
-}
-
-
-static int wpa_driver_test_set_ssid(void *priv, const u8 *ssid,
-				    size_t ssid_len)
-{
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	return 0;
-}
-
-
-static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
-{
-	wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid));
-	return 0;
-}
-
-
 static void * wpa_driver_test_global_init(void)
 {
 	struct wpa_driver_test_global *global;
@@ -2727,7 +2671,8 @@
 				       unsigned int wait,
 				       const u8 *dst, const u8 *src,
 				       const u8 *bssid,
-				       const u8 *data, size_t data_len)
+				       const u8 *data, size_t data_len,
+				       int no_cck)
 {
 	struct test_driver_bss *dbss = priv;
 	struct wpa_driver_test_data *drv = dbss->drv;
@@ -2760,7 +2705,7 @@
 	os_memcpy(hdr->addr2, src, ETH_ALEN);
 	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
-	ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len);
+	ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len, 0);
 	os_free(buf);
 	return ret;
 }
@@ -2770,7 +2715,6 @@
 static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_driver_test_data *drv = eloop_ctx;
-	int res;
 
 	if (drv->pending_action_tx == NULL)
 		return;
@@ -2783,12 +2727,13 @@
 	}
 	wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to "
 		   MACSTR, MAC2STR(drv->pending_action_dst));
-	res = wpa_driver_test_send_action(drv, drv->pending_action_freq, 0,
-					  drv->pending_action_dst,
-					  drv->pending_action_src,
-					  drv->pending_action_bssid,
-					  wpabuf_head(drv->pending_action_tx),
-					  wpabuf_len(drv->pending_action_tx));
+	wpa_driver_test_send_action(drv, drv->pending_action_freq, 0,
+				    drv->pending_action_dst,
+				    drv->pending_action_src,
+				    drv->pending_action_bssid,
+				    wpabuf_head(drv->pending_action_tx),
+				    wpabuf_len(drv->pending_action_tx),
+				    drv->pending_action_no_cck);
 }
 #endif /* CONFIG_P2P */
 
@@ -2980,6 +2925,7 @@
 	int ret;
 	struct wpabuf *wps_ie, *ies;
 	int social_channels[] = { 2412, 2437, 2462, 0, 0 };
+	size_t ielen;
 
 	wpa_printf(MSG_DEBUG, "%s(type=%d freq=%d)",
 		   __func__, type, freq);
@@ -3001,7 +2947,8 @@
 	if (wps_ie == NULL)
 		return -1;
 
-	ies = wpabuf_alloc(wpabuf_len(wps_ie) + 100);
+	ielen = p2p_scan_ie_buf_len(drv->p2p);
+	ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
 	if (ies == NULL) {
 		wpabuf_free(wps_ie);
 		return -1;
@@ -3069,6 +3016,7 @@
 	os_memcpy(drv->pending_action_dst, dst, ETH_ALEN);
 	os_memcpy(drv->pending_action_bssid, bssid, ETH_ALEN);
 	drv->pending_action_freq = freq;
+	drv->pending_action_no_cck = 1;
 
 	if (drv->off_channel_freq == freq) {
 		/* Already on requested channel; send immediately */
@@ -3248,7 +3196,8 @@
 static void test_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
 			       const u8 *dev_addr, const u8 *pri_dev_type,
 			       const char *dev_name, u16 supp_config_methods,
-			       u8 dev_capab, u8 group_capab)
+			       u8 dev_capab, u8 group_capab,
+			       const u8 *group_id, size_t group_id_len)
 {
 	wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)",
 		   __func__, MAC2STR(peer), config_methods);
@@ -3343,7 +3292,6 @@
 	.get_hw_feature_data = wpa_driver_test_get_hw_feature_data,
 	.if_add = test_driver_if_add,
 	.if_remove = test_driver_if_remove,
-	.valid_bss_mask = test_driver_valid_bss_mask,
 	.hapd_set_ssid = test_driver_set_ssid,
 	.set_privacy = test_driver_set_privacy,
 	.set_sta_vlan = test_driver_set_sta_vlan,
@@ -3362,11 +3310,6 @@
 	.get_mac_addr = wpa_driver_test_get_mac_addr,
 	.send_eapol = wpa_driver_test_send_eapol,
 	.mlme_setprotection = wpa_driver_test_mlme_setprotection,
-	.set_channel = wpa_driver_test_set_channel,
-	.set_ssid = wpa_driver_test_set_ssid,
-	.set_bssid = wpa_driver_test_set_bssid,
-	.mlme_add_sta = wpa_driver_test_mlme_add_sta,
-	.mlme_remove_sta = wpa_driver_test_mlme_remove_sta,
 	.get_scan_results2 = wpa_driver_test_get_scan_results2,
 	.global_init = wpa_driver_test_global_init,
 	.global_deinit = wpa_driver_test_global_deinit,
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 001716e..381cb3e 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -25,7 +25,7 @@
 #include <fcntl.h>
 #include <net/if_arp.h>
 
-#include "wireless_copy.h"
+#include "linux_wext.h"
 #include "common.h"
 #include "eloop.h"
 #include "common/ieee802_11_defs.h"
@@ -37,6 +37,9 @@
 #include "driver.h"
 #include "driver_wext.h"
 
+#ifdef ANDROID
+#include "android_drv.h"
+#endif /* ANDROID */
 
 static int wpa_driver_wext_flush_pmkid(void *priv);
 static int wpa_driver_wext_get_range(void *priv);
@@ -842,12 +845,13 @@
 	}
 
 	drv->mlme_sock = -1;
+
 #ifdef ANDROID
 	drv->errors = 0;
 	drv->driver_is_started = TRUE;
 	drv->skip_disconnect = 0;
 	drv->bgscan_enabled = 0;
-#endif
+#endif /* ANDROID */
 
 	if (wpa_driver_wext_finish_drv_init(drv) < 0)
 		goto err3;
@@ -1416,7 +1420,7 @@
 	tmp[res->num++] = r;
 	res->res = tmp;
 }
-				      
+
 
 /**
  * wpa_driver_wext_get_scan_results - Fetch the latest scan results
@@ -1426,7 +1430,7 @@
 struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
 {
 	struct wpa_driver_wext_data *drv = priv;
-	size_t ap_num = 0, len;
+	size_t len;
 	int first;
 	u8 *res_buf;
 	struct iw_event iwe_buf, *iwe = &iwe_buf;
@@ -1438,7 +1442,6 @@
 	if (res_buf == NULL)
 		return NULL;
 
-	ap_num = 0;
 	first = 1;
 
 	res = os_zalloc(sizeof(*res));
@@ -1868,8 +1871,10 @@
 {
 	struct iwreq iwr;
 	const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+#ifndef ANDROID
 	u8 ssid[32];
 	int i;
+#endif /* ANDROID */
 
 	/*
 	 * Only force-disconnect when the card is in infrastructure mode,
@@ -1884,40 +1889,39 @@
 	}
 
 	if (iwr.u.mode == IW_MODE_INFRA) {
+		/* Clear the BSSID selection */
+		if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) {
+			wpa_printf(MSG_DEBUG, "WEXT: Failed to clear BSSID "
+				   "selection on disconnect");
+		}
+
+#ifndef ANDROID
 		if (drv->cfg80211) {
 			/*
 			 * cfg80211 supports SIOCSIWMLME commands, so there is
 			 * no need for the random SSID hack, but clear the
-			 * BSSID and SSID.
+			 * SSID.
 			 */
-			if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
-#ifdef ANDROID
-			    0) {
-#else
-			    wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
-#endif
+			if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
 				wpa_printf(MSG_DEBUG, "WEXT: Failed to clear "
-					   "to disconnect");
+					   "SSID on disconnect");
 			}
 			return;
 		}
+
 		/*
-		 * Clear the BSSID selection and set a random SSID to make sure
-		 * the driver will not be trying to associate with something
-		 * even if it does not understand SIOCSIWMLME commands (or
-		 * tries to associate automatically after deauth/disassoc).
+		 * Set a random SSID to make sure the driver will not be trying
+		 * to associate with something even if it does not understand
+		 * SIOCSIWMLME commands (or tries to associate automatically
+		 * after deauth/disassoc).
 		 */
 		for (i = 0; i < 32; i++)
 			ssid[i] = rand() & 0xFF;
-		if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
-#ifdef ANDROID
-		    0) {
-#else
-		    wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
-#endif
+		if (wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
 			wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
-				   "BSSID/SSID to disconnect");
+				   "SSID to disconnect");
 		}
+#endif /* ANDROID */
 	}
 }
 
@@ -2350,6 +2354,129 @@
 }
 
 
+#ifdef ANDROID
+
+static int android_wext_cmd(struct wpa_driver_wext_data *drv, const char *cmd)
+{
+	struct iwreq iwr;
+	char buf[MAX_DRV_CMD_SIZE];
+	int ret;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+	os_memset(buf, 0, sizeof(buf));
+	os_strlcpy(buf, cmd, sizeof(buf));
+
+	iwr.u.data.pointer = buf;
+	iwr.u.data.length = sizeof(buf);
+
+	ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
+
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret,
+			   cmd);
+		drv->errors++;
+		if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+			drv->errors = 0;
+			wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE
+				"HANGED");
+		}
+		return ret;
+	}
+
+	drv->errors = 0;
+	return 0;
+}
+
+
+static int wext_sched_scan(void *priv, struct wpa_driver_scan_params *params,
+			   u32 interval)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0, i = 0, bp;
+	char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+	bp = WEXT_PNOSETUP_HEADER_SIZE;
+	os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+	buf[bp++] = WEXT_PNO_TLV_PREFIX;
+	buf[bp++] = WEXT_PNO_TLV_VERSION;
+	buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+	buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+	while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+		/*
+		 * Check that there is enough space needed for 1 more SSID, the
+		 * other sections and null termination.
+		 */
+		if ((bp + WEXT_PNO_SSID_HEADER_SIZE + IW_ESSID_MAX_SIZE +
+		     WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+			break;
+
+		wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+				  params->ssids[i].ssid,
+				  params->ssids[i].ssid_len);
+		buf[bp++] = WEXT_PNO_SSID_SECTION;
+		buf[bp++] = params->ssids[i].ssid_len;
+		os_memcpy(&buf[bp], params->ssids[i].ssid,
+			  params->ssids[i].ssid_len);
+		bp += params->ssids[i].ssid_len;
+		i++;
+	}
+
+	buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+	/* TODO: consider using interval parameter (interval in msec) instead
+	 * of hardcoded value here */
+	os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+		    WEXT_PNO_SCAN_INTERVAL);
+	bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+	buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+		    WEXT_PNO_REPEAT);
+	bp += WEXT_PNO_REPEAT_LENGTH;
+
+	buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+		    WEXT_PNO_MAX_REPEAT);
+	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.data.pointer = buf;
+	iwr.u.data.length = bp;
+
+	ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+			   ret);
+		drv->errors++;
+		if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+			drv->errors = 0;
+			wpa_msg(drv->ctx, MSG_INFO,
+				WPA_EVENT_DRIVER_STATE "HANGED");
+		}
+		return ret;
+	}
+
+	drv->errors = 0;
+	drv->bgscan_enabled = 1;
+
+	return android_wext_cmd(drv, "PNOFORCE 1");
+}
+
+
+static int wext_stop_sched_scan(void *priv)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	drv->bgscan_enabled = 0;
+	return android_wext_cmd(drv, "PNOFORCE 0");
+}
+
+#endif /* ANDROID */
+
+
 const struct wpa_driver_ops wpa_driver_wext_ops = {
 	.name = "wext",
 	.desc = "Linux wireless extensions (generic)",
@@ -2371,7 +2498,7 @@
 	.set_operstate = wpa_driver_wext_set_operstate,
 	.get_radio_name = wext_get_radio_name,
 #ifdef ANDROID
-	.signal_poll = wpa_driver_signal_poll,
-	.driver_cmd = wpa_driver_wext_driver_cmd,
-#endif
+	.sched_scan = wext_sched_scan,
+	.stop_sched_scan = wext_stop_sched_scan,
+#endif /* ANDROID */
 };
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
index 51e4d98..03df8e4 100644
--- a/src/drivers/driver_wext.h
+++ b/src/drivers/driver_wext.h
@@ -50,12 +50,13 @@
 	int cfg80211; /* whether driver is using cfg80211 */
 
 	u8 max_level;
+
 #ifdef ANDROID
 	int errors;
 	int driver_is_started;
 	int skip_disconnect;
 	int bgscan_enabled;
-#endif
+#endif /* ANDROID */
 };
 
 int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);
@@ -90,9 +91,4 @@
 int wpa_driver_wext_cipher2wext(int cipher);
 int wpa_driver_wext_keymgmt2wext(int keymgmt);
 
-#ifdef ANDROID
-#define WPA_EVENT_DRIVER_STATE		"CTRL-EVENT-DRIVER-STATE "
-#define WEXT_CSCAN_AMOUNT		9
-#endif
-
 #endif /* DRIVER_WEXT_H */
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index b710778..667ea22 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -27,9 +27,6 @@
 #ifdef CONFIG_DRIVER_MADWIFI
 extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
 #endif /* CONFIG_DRIVER_MADWIFI */
-#ifdef CONFIG_DRIVER_BROADCOM
-extern struct wpa_driver_ops wpa_driver_broadcom_ops; /* driver_broadcom.c */
-#endif /* CONFIG_DRIVER_BROADCOM */
 #ifdef CONFIG_DRIVER_BSD
 extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
 #endif /* CONFIG_DRIVER_BSD */
@@ -42,15 +39,6 @@
 #ifdef CONFIG_DRIVER_TEST
 extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
 #endif /* CONFIG_DRIVER_TEST */
-#ifdef CONFIG_DRIVER_RALINK
-extern struct wpa_driver_ops wpa_driver_ralink_ops; /* driver_ralink.c */
-#endif /* CONFIG_DRIVER_RALINK */
-#ifdef CONFIG_DRIVER_OSX
-extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */
-#endif /* CONFIG_DRIVER_OSX */
-#ifdef CONFIG_DRIVER_IPHONE
-extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */
-#endif /* CONFIG_DRIVER_IPHONE */
 #ifdef CONFIG_DRIVER_ROBOSWITCH
 /* driver_roboswitch.c */
 extern struct wpa_driver_ops wpa_driver_roboswitch_ops;
@@ -77,9 +65,6 @@
 #ifdef CONFIG_DRIVER_MADWIFI
 	&wpa_driver_madwifi_ops,
 #endif /* CONFIG_DRIVER_MADWIFI */
-#ifdef CONFIG_DRIVER_BROADCOM
-	&wpa_driver_broadcom_ops,
-#endif /* CONFIG_DRIVER_BROADCOM */
 #ifdef CONFIG_DRIVER_BSD
 	&wpa_driver_bsd_ops,
 #endif /* CONFIG_DRIVER_BSD */
@@ -92,15 +77,6 @@
 #ifdef CONFIG_DRIVER_TEST
 	&wpa_driver_test_ops,
 #endif /* CONFIG_DRIVER_TEST */
-#ifdef CONFIG_DRIVER_RALINK
-	&wpa_driver_ralink_ops,
-#endif /* CONFIG_DRIVER_RALINK */
-#ifdef CONFIG_DRIVER_OSX
-	&wpa_driver_osx_ops,
-#endif /* CONFIG_DRIVER_OSX */
-#ifdef CONFIG_DRIVER_IPHONE
-	&wpa_driver_iphone_ops,
-#endif /* CONFIG_DRIVER_IPHONE */
 #ifdef CONFIG_DRIVER_ROBOSWITCH
 	&wpa_driver_roboswitch_ops,
 #endif /* CONFIG_DRIVER_ROBOSWITCH */
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index ebf39c8..0cc81f9 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -12,29 +12,11 @@
 
 ##### COMMON DRIVERS
 
-ifdef CONFIG_DRIVER_HOSTAP
-DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP
-DRV_OBJS += ../src/drivers/driver_hostap.o
-CONFIG_WIRELESS_EXTENSION=y
-NEED_AP_MLME=y
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
 ifdef CONFIG_DRIVER_WIRED
 DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
 DRV_OBJS += ../src/drivers/driver_wired.o
 endif
 
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_OBJS += ../src/drivers/driver_madwifi.o
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_L2_PACKET=linux
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
 ifdef CONFIG_DRIVER_NL80211
 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
 DRV_OBJS += ../src/drivers/driver_nl80211.o
@@ -44,15 +26,22 @@
 NEED_NETLINK=y
 NEED_LINUX_IOCTL=y
 NEED_RFKILL=y
-ifdef CONFIG_LIBNL_TINY
-DRV_LIBS += -lnl-tiny
-else
-DRV_LIBS += -lnl
-endif
 
-ifdef CONFIG_LIBNL20
-DRV_LIBS += -lnl-genl
-DRV_CFLAGS += -DCONFIG_LIBNL20
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-3
+  DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+  ifdef CONFIG_LIBNL_TINY
+    DRV_LIBS += -lnl-tiny
+  else
+    DRV_LIBS += -lnl
+  endif
+
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
 endif
 endif
 
@@ -79,6 +68,24 @@
 
 ##### PURE AP DRIVERS
 
+ifdef CONFIG_DRIVER_HOSTAP
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP
+DRV_AP_OBJS += ../src/drivers/driver_hostap.o
+CONFIG_WIRELESS_EXTENSION=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+ifdef CONFIG_DRIVER_MADWIFI
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
+DRV_AP_OBJS += ../src/drivers/driver_madwifi.o
+CONFIG_WIRELESS_EXTENSION=y
+CONFIG_L2_PACKET=linux
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
 ifdef CONFIG_DRIVER_ATHEROS
 DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
 DRV_AP_OBJS += ../src/drivers/driver_atheros.o
@@ -97,18 +104,6 @@
 NEED_RFKILL=y
 endif
 
-ifdef CONFIG_DRIVER_RALINK
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK
-DRV_WPA_OBJS += ../src/drivers/driver_ralink.o
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
-ifdef CONFIG_DRIVER_BROADCOM
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM
-DRV_WPA_OBJS += ../src/drivers/driver_broadcom.o
-endif
-
 ifdef CONFIG_DRIVER_NDIS
 DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS
 DRV_WPA_OBJS += ../src/drivers/driver_ndis.o
@@ -124,20 +119,6 @@
 endif
 endif
 
-ifdef CONFIG_DRIVER_OSX
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX
-DRV_WPA_OBJS += ../src/drivers/driver_osx.o
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211
-endif
-
-ifdef CONFIG_DRIVER_IPHONE
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE
-DRV_WPA_OBJS += ../src/drivers/driver_iphone.o
-DRV_WPA_OBJS += ../src/drivers/MobileApple80211.o
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-endif
-
 ifdef CONFIG_DRIVER_ROBOSWITCH
 DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
 DRV_WPA_OBJS += ../src/drivers/driver_roboswitch.o
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index c690e1c..1d7129c 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -12,29 +12,11 @@
 
 ##### COMMON DRIVERS
 
-ifdef CONFIG_DRIVER_HOSTAP
-DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP
-DRV_OBJS += src/drivers/driver_hostap.c
-CONFIG_WIRELESS_EXTENSION=y
-NEED_AP_MLME=y
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
 ifdef CONFIG_DRIVER_WIRED
 DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
 DRV_OBJS += src/drivers/driver_wired.c
 endif
 
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_OBJS += src/drivers/driver_madwifi.c
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_L2_PACKET=linux
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
 ifdef CONFIG_DRIVER_NL80211
 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
 DRV_OBJS += src/drivers/driver_nl80211.c
@@ -44,15 +26,22 @@
 NEED_NETLINK=y
 NEED_LINUX_IOCTL=y
 NEED_RFKILL=y
-ifdef CONFIG_LIBNL_TINY
-DRV_LIBS += -lnl-tiny
-else
-DRV_LIBS += -lnl
-endif
 
-ifdef CONFIG_LIBNL20
-DRV_LIBS += -lnl-genl
-DRV_CFLAGS += -DCONFIG_LIBNL20
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-3
+  DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+  ifdef CONFIG_LIBNL_TINY
+    DRV_LIBS += -lnl-tiny
+  else
+    DRV_LIBS += -lnl
+  endif
+
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
 endif
 endif
 
@@ -79,6 +68,24 @@
 
 ##### PURE AP DRIVERS
 
+ifdef CONFIG_DRIVER_HOSTAP
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP
+DRV_AP_OBJS += src/drivers/driver_hostap.c
+CONFIG_WIRELESS_EXTENSION=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+ifdef CONFIG_DRIVER_MADWIFI
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
+DRV_AP_OBJS += src/drivers/driver_madwifi.c
+CONFIG_WIRELESS_EXTENSION=y
+CONFIG_L2_PACKET=linux
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
 ifdef CONFIG_DRIVER_ATHEROS
 DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
 DRV_AP_OBJS += src/drivers/driver_atheros.c
@@ -97,18 +104,6 @@
 NEED_RFKILL=y
 endif
 
-ifdef CONFIG_DRIVER_RALINK
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK
-DRV_WPA_OBJS += src/drivers/driver_ralink.c
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
-ifdef CONFIG_DRIVER_BROADCOM
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM
-DRV_WPA_OBJS += src/drivers/driver_broadcom.c
-endif
-
 ifdef CONFIG_DRIVER_NDIS
 DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS
 DRV_WPA_OBJS += src/drivers/driver_ndis.c
@@ -124,20 +119,6 @@
 endif
 endif
 
-ifdef CONFIG_DRIVER_OSX
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX
-DRV_WPA_OBJS += src/drivers/driver_osx.c
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211
-endif
-
-ifdef CONFIG_DRIVER_IPHONE
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE
-DRV_WPA_OBJS += src/drivers/driver_iphone.c
-DRV_WPA_OBJS += src/drivers/MobileApple80211.c
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-endif
-
 ifdef CONFIG_DRIVER_ROBOSWITCH
 DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
 DRV_WPA_OBJS += src/drivers/driver_roboswitch.c
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index 0d6cf54..d7501cf 100644
--- a/src/drivers/linux_ioctl.c
+++ b/src/drivers/linux_ioctl.c
@@ -24,6 +24,7 @@
 int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
 {
 	struct ifreq ifr;
+	int ret;
 
 	if (sock < 0)
 		return -1;
@@ -32,9 +33,10 @@
 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
 
 	if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
+		ret = errno ? -errno : -999;
 		wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
 			   ifname, strerror(errno));
-		return -1;
+		return ret;
 	}
 
 	if (dev_up) {
@@ -48,15 +50,38 @@
 	}
 
 	if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
+		ret = errno ? -errno : -999;
 		wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s",
 			   ifname, strerror(errno));
-		return -1;
+		return ret;
 	}
 
 	return 0;
 }
 
 
+int linux_iface_up(int sock, const char *ifname)
+{
+	struct ifreq ifr;
+	int ret;
+
+	if (sock < 0)
+		return -1;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+	if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
+		ret = errno ? -errno : -999;
+		wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
+			   ifname, strerror(errno));
+		return ret;
+	}
+
+	return !!(ifr.ifr_flags & IFF_UP);
+}
+
+
 int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
 {
 	struct ifreq ifr;
diff --git a/src/drivers/linux_ioctl.h b/src/drivers/linux_ioctl.h
index a555738..e0bf673 100644
--- a/src/drivers/linux_ioctl.h
+++ b/src/drivers/linux_ioctl.h
@@ -16,6 +16,7 @@
 #define LINUX_IOCTL_H
 
 int linux_set_iface_flags(int sock, const char *ifname, int dev_up);
+int linux_iface_up(int sock, const char *ifname);
 int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr);
 int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr);
 int linux_br_add(int sock, const char *brname);
diff --git a/src/drivers/linux_wext.h b/src/drivers/linux_wext.h
new file mode 100644
index 0000000..b6eea68
--- /dev/null
+++ b/src/drivers/linux_wext.h
@@ -0,0 +1,51 @@
+/*
+ * Driver interaction with generic Linux Wireless Extensions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef LINUX_WEXT_H
+#define LINUX_WEXT_H
+
+#ifndef ANDROID
+
+/*
+ * Avoid including other kernel header to avoid conflicts with C library
+ * headers.
+ */
+#define _LINUX_TYPES_H
+#define _LINUX_SOCKET_H
+#define _LINUX_IF_H
+
+#include <sys/types.h>
+#include <net/if.h>
+typedef __uint32_t __u32;
+typedef __int32_t __s32;
+typedef __uint16_t __u16;
+typedef __int16_t __s16;
+typedef __uint8_t __u8;
+#ifndef __user
+#define __user
+#endif /* __user */
+
+#endif /* ANDROID */
+
+#include <linux/wireless.h>
+
+#ifndef IW_ENCODE_ALG_PMK
+#define IW_ENCODE_ALG_PMK 4
+#endif
+
+#ifndef IW_ENC_CAPA_4WAY_HANDSHAKE
+#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010
+#endif
+
+#endif /* LINUX_WEXT_H */
diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c
index ad15b1d..6778907 100644
--- a/src/drivers/netlink.c
+++ b/src/drivers/netlink.c
@@ -34,7 +34,7 @@
 	if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg))
 		return;
 	cb(netlink->cfg->ctx, NLMSG_DATA(h),
-	   NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
+	   (u8 *) NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
 	   NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg)));
 }
 
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 7483a89..f9261c2 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -6,7 +6,7 @@
  * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2008 Michael Wu <flamingice@sourmilk.net>
  * Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com>
- * Copyright 2008 Michael Buesch <mb@bu3sch.de>
+ * Copyright 2008 Michael Buesch <m@bues.ch>
  * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
  * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
  * Copyright 2008 Colin McCabe <colin@cozybit.com>
@@ -77,6 +77,39 @@
  */
 
 /**
+ * DOC: Virtual interface / concurrency capabilities
+ *
+ * Some devices are able to operate with virtual MACs, they can have
+ * more than one virtual interface. The capability handling for this
+ * is a bit complex though, as there may be a number of restrictions
+ * on the types of concurrency that are supported.
+ *
+ * To start with, each device supports the interface types listed in
+ * the %NL80211_ATTR_SUPPORTED_IFTYPES attribute, but by listing the
+ * types there no concurrency is implied.
+ *
+ * Once concurrency is desired, more attributes must be observed:
+ * To start with, since some interface types are purely managed in
+ * software, like the AP-VLAN type in mac80211 for example, there's
+ * an additional list of these, they can be added at any time and
+ * are only restricted by some semantic restrictions (e.g. AP-VLAN
+ * cannot be added without a corresponding AP interface). This list
+ * is exported in the %NL80211_ATTR_SOFTWARE_IFTYPES attribute.
+ *
+ * Further, the list of supported combinations is exported. This is
+ * in the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute. Basically,
+ * it exports a list of "groups", and at any point in time the
+ * interfaces that are currently active must fall into any one of
+ * the advertised groups. Within each group, there are restrictions
+ * on the number of interfaces of different types that are supported
+ * and also the number of different channels, along with potentially
+ * some other restrictions. See &enum nl80211_if_combination_attrs.
+ *
+ * All together, these attributes define the concurrency of virtual
+ * interfaces that a given device supports.
+ */
+
+/**
  * enum nl80211_commands - supported nl80211 commands
  *
  * @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -128,6 +161,13 @@
  * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
  *	using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
  *	%NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
+ *	Following attributes are provided for drivers that generate full Beacon
+ *	and Probe Response frames internally: %NL80211_ATTR_SSID,
+ *	%NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
+ *	%NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
+ *	%NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
+ *	%NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP,
+ *	%NL80211_ATTR_IE_ASSOC_RESP.
  * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
  *	parameters are like for %NL80211_CMD_SET_BEACON.
  * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
@@ -148,6 +188,10 @@
  * @NL80211_CMD_SET_MPATH:  Set mesh path attributes for mesh path to
  * 	destination %NL80211_ATTR_MAC on the interface identified by
  * 	%NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_MPATH: Create a new mesh path for the destination given by
+ *	%NL80211_ATTR_MAC via %NL80211_ATTR_MPATH_NEXT_HOP.
+ * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by
+ *	%NL80211_ATTR_MAC.
  * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
  *	the interface identified by %NL80211_ATTR_IFINDEX.
  * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
@@ -172,10 +216,10 @@
  * 	to the specified ISO/IEC 3166-1 alpha2 country code. The core will
  * 	store this as a valid request and then query userspace for it.
  *
- * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the
+ * @NL80211_CMD_GET_MESH_CONFIG: Get mesh networking properties for the
  *	interface identified by %NL80211_ATTR_IFINDEX
  *
- * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the
+ * @NL80211_CMD_SET_MESH_CONFIG: Set mesh networking properties for the
  *      interface identified by %NL80211_ATTR_IFINDEX
  *
  * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The
@@ -194,11 +238,36 @@
  *
  * @NL80211_CMD_GET_SCAN: get scan results
  * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ *	%NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ *	probe requests at CCK rate or not.
  * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
  *	NL80211_CMD_GET_SCAN and on the "scan" multicast group)
  * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
  *	partial scan results may be available
  *
+ * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain
+ *	intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL.
+ *	Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS)
+ *	are passed, they are used in the probe requests.  For
+ *	broadcast, a broadcast SSID must be passed (ie. an empty
+ *	string).  If no SSID is passed, no probe requests are sent and
+ *	a passive scan is performed.  %NL80211_ATTR_SCAN_FREQUENCIES,
+ *	if passed, define which channels should be scanned; if not
+ *	passed, all channels allowed for the current regulatory domain
+ *	are used.  Extra IEs can also be passed from the userspace by
+ *	using the %NL80211_ATTR_IE attribute.
+ * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan.  Returns -ENOENT
+ *	if scheduled scan is not running.
+ * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan
+ *	results available.
+ * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has
+ *	stopped.  The driver may issue this event at any time during a
+ *	scheduled scan.  One reason for stopping the scan is if the hardware
+ *	does not support starting an association or a normal scan while running
+ *	a scheduled scan.  This event is also sent when the
+ *	%NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface
+ *	is brought down while a scheduled scan was running.
+ *
  * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
  *      or noise level
  * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
@@ -365,6 +434,8 @@
  *	specified using %NL80211_ATTR_DURATION. When called, this operation
  *	returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
  *	TX status event pertaining to the TX request.
+ *	%NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ *	management frames at CCK rate or not in 2GHz band.
  * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
  *	command may be used with the corresponding cookie to cancel the wait
  *	time if it is known that it is no longer necessary.
@@ -406,11 +477,72 @@
  *	notification. This event is used to indicate that an unprotected
  *	disassociation frame was dropped when MFP is in use.
  *
+ * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a
+ *      beacon or probe response from a compatible mesh peer.  This is only
+ *      sent while no station information (sta_info) exists for the new peer
+ *      candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set.  On
+ *      reception of this notification, userspace may decide to create a new
+ *      station (@NL80211_CMD_NEW_STATION).  To stop this notification from
+ *      reoccurring, the userspace authentication daemon may want to create the
+ *      new station with the AUTHENTICATED flag unset and maybe change it later
+ *      depending on the authentication result.
+ *
+ * @NL80211_CMD_GET_WOWLAN: get Wake-on-Wireless-LAN (WoWLAN) settings.
+ * @NL80211_CMD_SET_WOWLAN: set Wake-on-Wireless-LAN (WoWLAN) settings.
+ *	Since wireless is more complex than wired ethernet, it supports
+ *	various triggers. These triggers can be configured through this
+ *	command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
+ *	more background information, see
+ *	http://wireless.kernel.org/en/users/Documentation/WoWLAN.
+ *
+ * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
+ *	the necessary information for supporting GTK rekey offload. This
+ *	feature is typically used during WoWLAN. The configuration data
+ *	is contained in %NL80211_ATTR_REKEY_DATA (which is nested and
+ *	contains the data in sub-attributes). After rekeying happened,
+ *	this command may also be sent by the driver as an MLME event to
+ *	inform userspace of the new replay counter.
+ *
+ * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace
+ *	of PMKSA caching dandidates.
+ *
+ * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
+ * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
+ *
+ * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
+ *	(or GO) interface (i.e. hostapd) to ask for unexpected frames to
+ *	implement sending deauth to stations that send unexpected class 3
+ *	frames. Also used as the event sent by the kernel when such a frame
+ *	is received.
+ *	For the event, the %NL80211_ATTR_MAC attribute carries the TA and
+ *	other attributes like the interface index are present.
+ *	If used as the command it must have an interface index and you can
+ *	only unsubscribe from the event by closing the socket. Subscription
+ *	is also for %NL80211_CMD_UNEXPECTED_4ADDR_FRAME events.
+ *
+ * @NL80211_CMD_UNEXPECTED_4ADDR_FRAME: Sent as an event indicating that the
+ *	associated station identified by %NL80211_ATTR_MAC sent a 4addr frame
+ *	and wasn't already in a 4-addr VLAN. The event will be sent similarly
+ *	to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener.
+ *
+ * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface
+ *	by sending a null data frame to it and reporting when the frame is
+ *	acknowleged. This is used to allow timing out inactive clients. Uses
+ *	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
+ *	direct reply with an %NL80211_ATTR_COOKIE that is later used to match
+ *	up the event with the request. The event includes the same data and
+ *	has %NL80211_ATTR_ACK set if the frame was ACKed.
+ *
+ * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from
+ *	other BSSes when any interfaces are in AP mode. This helps implement
+ *	OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
+ *	messages. Note that per PHY only one application may register.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
 enum nl80211_commands {
-/* don't change the order or add anything inbetween, this is ABI! */
+/* don't change the order or add anything between, this is ABI! */
 	NL80211_CMD_UNSPEC,
 
 	NL80211_CMD_GET_WIPHY,		/* can dump */
@@ -448,8 +580,8 @@
 	NL80211_CMD_SET_REG,
 	NL80211_CMD_REQ_SET_REG,
 
-	NL80211_CMD_GET_MESH_PARAMS,
-	NL80211_CMD_SET_MESH_PARAMS,
+	NL80211_CMD_GET_MESH_CONFIG,
+	NL80211_CMD_SET_MESH_CONFIG,
 
 	NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */,
 
@@ -518,6 +650,31 @@
 	NL80211_CMD_UNPROT_DEAUTHENTICATE,
 	NL80211_CMD_UNPROT_DISASSOCIATE,
 
+	NL80211_CMD_NEW_PEER_CANDIDATE,
+
+	NL80211_CMD_GET_WOWLAN,
+	NL80211_CMD_SET_WOWLAN,
+
+	NL80211_CMD_START_SCHED_SCAN,
+	NL80211_CMD_STOP_SCHED_SCAN,
+	NL80211_CMD_SCHED_SCAN_RESULTS,
+	NL80211_CMD_SCHED_SCAN_STOPPED,
+
+	NL80211_CMD_SET_REKEY_OFFLOAD,
+
+	NL80211_CMD_PMKSA_CANDIDATE,
+
+	NL80211_CMD_TDLS_OPER,
+	NL80211_CMD_TDLS_MGMT,
+
+	NL80211_CMD_UNEXPECTED_FRAME,
+
+	NL80211_CMD_PROBE_CLIENT,
+
+	NL80211_CMD_REGISTER_BEACONS,
+
+	NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -538,6 +695,13 @@
 #define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
 #define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
 
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
+
+/* source-level API compatibility */
+#define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG
+#define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG
+#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE
+
 /**
  * enum nl80211_attrs - nl80211 netlink attributes
  *
@@ -608,7 +772,7 @@
  *	consisting of a nested array.
  *
  * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
- * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link.
  * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
  * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
  * 	info given for %NL80211_CMD_GET_MPATH, nested attribute described at
@@ -653,8 +817,14 @@
  *
  * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
  *	a single scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS: number of SSIDs you can
+ *	scan with a single scheduled scan request, a wiphy attribute.
  * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
  *	that can be added to a scan request
+ * @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information
+ *	elements that can be added to a scheduled scan request
+ * @NL80211_ATTR_MAX_MATCH_SETS: maximum number of sets that can be
+ *	used with @NL80211_ATTR_SCHED_SCAN_MATCH, a wiphy attribute.
  *
  * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
  * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
@@ -735,18 +905,20 @@
  * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
  *	event (u16)
  * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
- *	that protected APs should be used.
+ *	that protected APs should be used. This is also used with NEW_BEACON to
+ *	indicate that the BSS is to use protection.
  *
- * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
- *	indicate which unicast key ciphers will be used with the connection
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT, ASSOCIATE, and NEW_BEACON
+ *	to indicate which unicast key ciphers will be used with the connection
  *	(an array of u32).
- * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
- *	which group key cipher will be used with the connection (a u32).
- * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
- *	which WPA version(s) the AP we want to associate with is using
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *	indicate which group key cipher will be used with the connection (a
+ *	u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *	indicate which WPA version(s) the AP we want to associate with is using
  *	(a u32 with flags from &enum nl80211_wpa_versions).
- * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
- *	which key management algorithm(s) to use (an array of u32).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *	indicate which key management algorithm(s) to use (an array of u32).
  *
  * @NL80211_ATTR_REQ_IE: (Re)association request information elements as
  *	sent out by the card, for ROAM and successful CONNECT events.
@@ -852,7 +1024,13 @@
  *	This can be used to mask out antennas which are not attached or should
  *	not be used for receiving. If an antenna is not selected in this bitmap
  *	the hardware should not be configured to receive on this antenna.
- *	For a more detailed descripton see @NL80211_ATTR_WIPHY_ANTENNA_TX.
+ *	For a more detailed description see @NL80211_ATTR_WIPHY_ANTENNA_TX.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX: Bitmap of antennas which are available
+ *	for configuration as TX antennas via the above parameters.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX: Bitmap of antennas which are available
+ *	for configuration as RX antennas via the above parameters.
  *
  * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS
  *
@@ -868,11 +1046,135 @@
  *	attributes, specifying what a key should be set as default as.
  *	See &enum nl80211_key_default_types.
  *
+ * @NL80211_ATTR_MESH_SETUP: Optional mesh setup parameters.  These cannot be
+ *	changed once the mesh is active.
+ * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute
+ *	containing attributes from &enum nl80211_meshconf_params.
+ * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver
+ *	allows auth frames in a mesh to be passed to userspace for processing via
+ *	the @NL80211_MESH_SETUP_USERSPACE_AUTH flag.
+ * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as
+ *	defined in &enum nl80211_plink_state. Used when userspace is
+ *	driving the peer link management state machine.
+ *	@NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled.
+ *
+ * @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy
+ *	capabilities, the supported WoWLAN triggers
+ * @NL80211_ATTR_WOWLAN_TRIGGERS: used by %NL80211_CMD_SET_WOWLAN to
+ *	indicate which WoW triggers should be enabled. This is also
+ *	used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN
+ *	triggers.
+
+ * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
+ *	cycles, in msecs.
+
+ * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more
+ *	sets of attributes to match during scheduled scans.  Only BSSs
+ *	that match any of the sets will be reported.  These are
+ *	pass-thru filter rules.
+ *	For a match to succeed, the BSS must match all attributes of a
+ *	set.  Since not every hardware supports matching all types of
+ *	attributes, there is no guarantee that the reported BSSs are
+ *	fully complying with the match sets and userspace needs to be
+ *	able to ignore them by itself.
+ *	Thus, the implementation is somewhat hardware-dependent, but
+ *	this is only an optimization and the userspace application
+ *	needs to handle all the non-filtered results anyway.
+ *	If the match attributes don't make sense when combined with
+ *	the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID
+ *	is included in the probe request, but the match attributes
+ *	will never let it go through), -EINVAL may be returned.
+ *	If ommited, no filtering is done.
+ *
+ * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
+ *	interface combinations. In each nested item, it contains attributes
+ *	defined in &enum nl80211_if_combination_attrs.
+ * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like
+ *	%NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that
+ *	are managed in software: interfaces of these types aren't subject to
+ *	any restrictions in their number or combinations.
+ *
+ * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
+ *	necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
+ *
+ * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan,
+ *	nested array attribute containing an entry for each band, with the entry
+ *	being a list of supported rates as defined by IEEE 802.11 7.3.2.2 but
+ *	without the length restriction (at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HIDDEN_SSID: indicates whether SSID is to be hidden from Beacon
+ *	and Probe Response (when response to wildcard Probe Request); see
+ *	&enum nl80211_hidden_ssid, represented as a u32
+ *
+ * @NL80211_ATTR_IE_PROBE_RESP: Information element(s) for Probe Response frame.
+ *	This is used with %NL80211_CMD_NEW_BEACON and %NL80211_CMD_SET_BEACON to
+ *	provide extra IEs (e.g., WPS/P2P IE) into Probe Response frames when the
+ *	driver (or firmware) replies to Probe Request frames.
+ * @NL80211_ATTR_IE_ASSOC_RESP: Information element(s) for (Re)Association
+ *	Response frames. This is used with %NL80211_CMD_NEW_BEACON and
+ *	%NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into
+ *	(Re)Association Response frames when the driver (or firmware) replies to
+ *	(Re)Association Request frames.
+ *
+ * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration
+ *	of the station, see &enum nl80211_sta_wme_attr.
+ * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working
+ *	as AP.
+ *
+ * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of
+ *	roaming to another AP in the same ESS if the signal lever is low.
+ *
+ * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching
+ *	candidate information, see &enum nl80211_pmksa_candidate_attr.
+ *
+ * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not
+ *	for management frames transmission. In order to avoid p2p probe/action
+ *	frames are being transmitted at CCK rate in 2GHz band, the user space
+ *	applications use this attribute.
+ *	This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
+ *	%NL80211_CMD_FRAME commands.
+ *
+ * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup
+ *	request, link setup confirm, link teardown, etc.). Values are
+ *	described in the TDLS (802.11z) specification.
+ * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a
+ *	TDLS conversation between two devices.
+ * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see
+ *	&enum nl80211_tdls_operation, represented as a u8.
+ * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate
+ *	as a TDLS peer sta.
+ * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown
+ *	procedures should be performed by sending TDLS packets via
+ *	%NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
+ *	used for asking the driver to perform a TDLS operation.
+ *
+ * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
+ *	that have AP support to indicate that they have the AP SME integrated
+ *	with support for the features listed in this attribute, see
+ *	&enum nl80211_ap_sme_features.
+ *
+ * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
+ *	the driver to not wait for an acknowledgement. Note that due to this,
+ *	it will also not give a status callback nor return a cookie. This is
+ *	mostly useful for probe responses to save airtime.
+ *
+ * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
+ *	&enum nl80211_feature_flags and is advertised in wiphy information.
+ * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
+ *
+ *	requests while operating in AP-mode.
+ *	This attribute holds a bitmap of the supported protocols for
+ *	offloading (see &enum nl80211_probe_resp_offload_support_attr).
+ *
+ * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
+ *	probe-response frame. The DA field in the 802.11 header is zero-ed out,
+ *	to be filled by the FW.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_attrs {
-/* don't change the order or add anything inbetween, this is ABI! */
+/* don't change the order or add anything between, this is ABI! */
 	NL80211_ATTR_UNSPEC,
 
 	NL80211_ATTR_WIPHY,
@@ -922,7 +1224,7 @@
 	NL80211_ATTR_REG_ALPHA2,
 	NL80211_ATTR_REG_RULES,
 
-	NL80211_ATTR_MESH_PARAMS,
+	NL80211_ATTR_MESH_CONFIG,
 
 	NL80211_ATTR_BSS_BASIC_RATES,
 
@@ -1050,6 +1352,62 @@
 
 	NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
 
+	NL80211_ATTR_MESH_SETUP,
+
+	NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
+	NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
+
+	NL80211_ATTR_SUPPORT_MESH_AUTH,
+	NL80211_ATTR_STA_PLINK_STATE,
+
+	NL80211_ATTR_WOWLAN_TRIGGERS,
+	NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED,
+
+	NL80211_ATTR_SCHED_SCAN_INTERVAL,
+
+	NL80211_ATTR_INTERFACE_COMBINATIONS,
+	NL80211_ATTR_SOFTWARE_IFTYPES,
+
+	NL80211_ATTR_REKEY_DATA,
+
+	NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
+	NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
+
+	NL80211_ATTR_SCAN_SUPP_RATES,
+
+	NL80211_ATTR_HIDDEN_SSID,
+
+	NL80211_ATTR_IE_PROBE_RESP,
+	NL80211_ATTR_IE_ASSOC_RESP,
+
+	NL80211_ATTR_STA_WME,
+	NL80211_ATTR_SUPPORT_AP_UAPSD,
+
+	NL80211_ATTR_ROAM_SUPPORT,
+
+	NL80211_ATTR_SCHED_SCAN_MATCH,
+	NL80211_ATTR_MAX_MATCH_SETS,
+
+	NL80211_ATTR_PMKSA_CANDIDATE,
+
+	NL80211_ATTR_TX_NO_CCK_RATE,
+
+	NL80211_ATTR_TDLS_ACTION,
+	NL80211_ATTR_TDLS_DIALOG_TOKEN,
+	NL80211_ATTR_TDLS_OPERATION,
+	NL80211_ATTR_TDLS_SUPPORT,
+	NL80211_ATTR_TDLS_EXTERNAL_SETUP,
+
+	NL80211_ATTR_DEVICE_AP_SME,
+
+	NL80211_ATTR_DONT_WAIT_FOR_ACK,
+
+	NL80211_ATTR_FEATURE_FLAGS,
+
+	NL80211_ATTR_PROBE_RESP_OFFLOAD,
+
+	NL80211_ATTR_PROBE_RESP,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -1058,6 +1416,7 @@
 
 /* source-level API compatibility */
 #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
+#define	NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
 
 /*
  * Allow user space programs to use #ifdef on new attributes by defining them
@@ -1083,6 +1442,7 @@
 #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
 #define NL80211_ATTR_KEY NL80211_ATTR_KEY
 #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
 
 #define NL80211_MAX_SUPP_RATES			32
 #define NL80211_MAX_SUPP_REG_RULES		32
@@ -1101,7 +1461,9 @@
  * @NL80211_IFTYPE_ADHOC: independent BSS member
  * @NL80211_IFTYPE_STATION: managed BSS member
  * @NL80211_IFTYPE_AP: access point
- * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points; VLAN interfaces
+ *	are a bit special in that they must always be tied to a pre-existing
+ *	AP type interface.
  * @NL80211_IFTYPE_WDS: wireless distribution interface
  * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
  * @NL80211_IFTYPE_MESH_POINT: mesh point
@@ -1143,6 +1505,8 @@
  *	with short barker preamble
  * @NL80211_STA_FLAG_WME: station is WME/QoS capable
  * @NL80211_STA_FLAG_MFP: station uses management frame protection
+ * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
+ * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer
  * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
  * @__NL80211_STA_FLAG_AFTER_LAST: internal use
  */
@@ -1152,6 +1516,8 @@
 	NL80211_STA_FLAG_SHORT_PREAMBLE,
 	NL80211_STA_FLAG_WME,
 	NL80211_STA_FLAG_MFP,
+	NL80211_STA_FLAG_AUTHENTICATED,
+	NL80211_STA_FLAG_TDLS_PEER,
 
 	/* keep last */
 	__NL80211_STA_FLAG_AFTER_LAST,
@@ -1197,6 +1563,36 @@
 };
 
 /**
+ * enum nl80211_sta_bss_param - BSS information collected by STA
+ *
+ * These attribute types are used with %NL80211_STA_INFO_BSS_PARAM
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_STA_BSS_PARAM_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_BSS_PARAM_CTS_PROT: whether CTS protection is enabled (flag)
+ * @NL80211_STA_BSS_PARAM_SHORT_PREAMBLE:  whether short preamble is enabled
+ *	(flag)
+ * @NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME:  whether short slot time is enabled
+ *	(flag)
+ * @NL80211_STA_BSS_PARAM_DTIM_PERIOD: DTIM period for beaconing (u8)
+ * @NL80211_STA_BSS_PARAM_BEACON_INTERVAL: Beacon interval (u16)
+ * @NL80211_STA_BSS_PARAM_MAX: highest sta_bss_param number currently defined
+ * @__NL80211_STA_BSS_PARAM_AFTER_LAST: internal use
+ */
+enum nl80211_sta_bss_param {
+	__NL80211_STA_BSS_PARAM_INVALID,
+	NL80211_STA_BSS_PARAM_CTS_PROT,
+	NL80211_STA_BSS_PARAM_SHORT_PREAMBLE,
+	NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME,
+	NL80211_STA_BSS_PARAM_DTIM_PERIOD,
+	NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
+
+	/* keep last */
+	__NL80211_STA_BSS_PARAM_AFTER_LAST,
+	NL80211_STA_BSS_PARAM_MAX = __NL80211_STA_BSS_PARAM_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_sta_info - station information
  *
  * These attribute types are used with %NL80211_ATTR_STA_INFO
@@ -1206,17 +1602,27 @@
  * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
  * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
  * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
- * @__NL80211_STA_INFO_AFTER_LAST: internal
- * @NL80211_STA_INFO_MAX: highest possible station info attribute
  * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
  * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
- * 	containing info as possible, see &enum nl80211_sta_info_txrate.
+ * 	containing info as possible, see &enum nl80211_rate_info
  * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
  * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
  *	station)
  * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
  * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
  * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm)
+ * @NL80211_STA_INFO_LLID: the station's mesh LLID
+ * @NL80211_STA_INFO_PLID: the station's mesh PLID
+ * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station
+ *	(see %enum nl80211_plink_state)
+ * @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested
+ *	attribute, like NL80211_STA_INFO_TX_BITRATE.
+ * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute
+ *     containing info as possible, see &enum nl80211_sta_bss_param
+ * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected
+ * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
 enum nl80211_sta_info {
 	__NL80211_STA_INFO_INVALID,
@@ -1233,6 +1639,10 @@
 	NL80211_STA_INFO_TX_RETRIES,
 	NL80211_STA_INFO_TX_FAILED,
 	NL80211_STA_INFO_SIGNAL_AVG,
+	NL80211_STA_INFO_RX_BITRATE,
+	NL80211_STA_INFO_BSS_PARAM,
+	NL80211_STA_INFO_CONNECTED_TIME,
+	NL80211_STA_INFO_STA_FLAGS,
 
 	/* keep last */
 	__NL80211_STA_INFO_AFTER_LAST,
@@ -1388,7 +1798,7 @@
  * 	802.11 country information element with regulatory information it
  * 	thinks we should consider. cfg80211 only processes the country
  *	code from the IE, and relies on the regulatory domain information
- *	structure pased by userspace (CRDA) from our wireless-regdb.
+ *	structure passed by userspace (CRDA) from our wireless-regdb.
  *	If a channel is enabled but the country code indicates it should
  *	be disabled we disable the channel and re-enable it upon disassociation.
  */
@@ -1462,6 +1872,26 @@
 };
 
 /**
+ * enum nl80211_sched_scan_match_attr - scheduled scan match attributes
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
+ * only report BSS with matching SSID.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
+ *	attribute number currently defined
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_sched_scan_match_attr {
+	__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID,
+
+	NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+
+	/* keep last */
+	__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
+	NL80211_SCHED_SCAN_MATCH_ATTR_MAX =
+		__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_reg_rule_flags - regulatory rule flags
  *
  * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
@@ -1559,14 +1989,15 @@
 /**
  * enum nl80211_meshconf_params - mesh configuration parameters
  *
- * Mesh configuration parameters
+ * Mesh configuration parameters. These can be changed while the mesh is
+ * active.
  *
  * @__NL80211_MESHCONF_INVALID: internal use
  *
  * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
  * millisecond units, used by the Peer Link Open message
  *
- * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in
+ * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in
  * millisecond units, used by the peer link management to close a peer link
  *
  * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
@@ -1582,9 +2013,6 @@
  * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
  * point.
  *
- * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
- * source mesh point for path selection elements.
- *
  * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
  * open peer links when we detect compatible mesh peers.
  *
@@ -1609,7 +2037,17 @@
  * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
  * that it takes for an HWMP information element to propagate across the mesh
  *
- * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not
+ * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not
+ *
+ * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
+ * source mesh point for path selection elements.
+ *
+ * @NL80211_MESHCONF_HWMP_RANN_INTERVAL:  The interval of time (in TUs) between
+ * root announcements are transmitted.
+ *
+ * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has
+ * access to a broader network beyond the MBSS.  This is done via Root
+ * Announcement frames.
  *
  * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
  *
@@ -1632,6 +2070,8 @@
 	NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
 	NL80211_MESHCONF_HWMP_ROOTMODE,
 	NL80211_MESHCONF_ELEMENT_TTL,
+	NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+	NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
 
 	/* keep last */
 	__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -1639,6 +2079,54 @@
 };
 
 /**
+ * enum nl80211_mesh_setup_params - mesh setup parameters
+ *
+ * Mesh setup parameters.  These are used to start/join a mesh and cannot be
+ * changed while the mesh is active.
+ *
+ * @__NL80211_MESH_SETUP_INVALID: Internal use
+ *
+ * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a
+ * vendor specific path selection algorithm or disable it to use the default
+ * HWMP.
+ *
+ * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a
+ * vendor specific path metric or disable it to use the default Airtime
+ * metric.
+ *
+ * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a
+ * robust security network ie, or a vendor specific information element that
+ * vendors will use to identify the path selection methods and metrics in use.
+ *
+ * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication
+ * daemon will be authenticating mesh candidates.
+ *
+ * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication
+ * daemon will be securing peer link frames.  AMPE is a secured version of Mesh
+ * Peering Management (MPM) and is implemented with the assistance of a
+ * userspace daemon.  When this flag is set, the kernel will send peer
+ * management frames to a userspace daemon that will implement AMPE
+ * functionality (security capabilities selection, key confirmation, and key
+ * management).  When the flag is unset (default), the kernel can autonomously
+ * complete (unsecured) mesh peering without the need of a userspace daemon.
+ *
+ * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
+ * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
+ */
+enum nl80211_mesh_setup_params {
+	__NL80211_MESH_SETUP_INVALID,
+	NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL,
+	NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC,
+	NL80211_MESH_SETUP_IE,
+	NL80211_MESH_SETUP_USERSPACE_AUTH,
+	NL80211_MESH_SETUP_USERSPACE_AMPE,
+
+	/* keep last */
+	__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
+	NL80211_MESH_SETUP_ATTR_MAX = __NL80211_MESH_SETUP_ATTR_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_txq_attr - TX queue parameter attributes
  * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
  * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
@@ -1936,4 +2424,341 @@
 	NL80211_TX_POWER_FIXED,
 };
 
+/**
+ * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute
+ * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute
+ * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has
+ *	a zero bit are ignored
+ * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have
+ *	a bit for each byte in the pattern. The lowest-order bit corresponds
+ *	to the first byte of the pattern, but the bytes of the pattern are
+ *	in a little-endian-like format, i.e. the 9th byte of the pattern
+ *	corresponds to the lowest-order bit in the second byte of the mask.
+ *	For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where
+ *	xx indicates "don't care") would be represented by a pattern of
+ *	twelve zero bytes, and a mask of "0xed,0x07".
+ *	Note that the pattern matching is done as though frames were not
+ *	802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
+ *	first (including SNAP header unpacking) and then matched.
+ * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
+ * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
+ */
+enum nl80211_wowlan_packet_pattern_attr {
+	__NL80211_WOWLAN_PKTPAT_INVALID,
+	NL80211_WOWLAN_PKTPAT_MASK,
+	NL80211_WOWLAN_PKTPAT_PATTERN,
+
+	NUM_NL80211_WOWLAN_PKTPAT,
+	MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
+};
+
+/**
+ * struct nl80211_wowlan_pattern_support - pattern support information
+ * @max_patterns: maximum number of patterns supported
+ * @min_pattern_len: minimum length of each pattern
+ * @max_pattern_len: maximum length of each pattern
+ *
+ * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
+ * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
+ * capability information given by the kernel to userspace.
+ */
+struct nl80211_wowlan_pattern_support {
+	__u32 max_patterns;
+	__u32 min_pattern_len;
+	__u32 max_pattern_len;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_wowlan_triggers - WoWLAN trigger definitions
+ * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes
+ * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put
+ *	the chip into a special state -- works best with chips that have
+ *	support for low-power operation already (flag)
+ * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect
+ *	is detected is implementation-specific (flag)
+ * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed
+ *	by 16 repetitions of MAC addr, anywhere in payload) (flag)
+ * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns
+ *	which are passed in an array of nested attributes, each nested attribute
+ *	defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern.
+ *	Each pattern defines a wakeup packet. The matching is done on the MSDU,
+ *	i.e. as though the packet was an 802.3 packet, so the pattern matching
+ *	is done after the packet is converted to the MSDU.
+ *
+ *	In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
+ *	carrying a &struct nl80211_wowlan_pattern_support.
+ * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be
+ *	used when setting, used only to indicate that GTK rekeying is supported
+ *	by the device (flag)
+ * @NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE: wake up on GTK rekey failure (if
+ *	done by the device) (flag)
+ * @NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST: wake up on EAP Identity Request
+ *	packet (flag)
+ * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag)
+ * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released
+ *	(on devices that have rfkill in the device) (flag)
+ * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
+ * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
+ */
+enum nl80211_wowlan_triggers {
+	__NL80211_WOWLAN_TRIG_INVALID,
+	NL80211_WOWLAN_TRIG_ANY,
+	NL80211_WOWLAN_TRIG_DISCONNECT,
+	NL80211_WOWLAN_TRIG_MAGIC_PKT,
+	NL80211_WOWLAN_TRIG_PKT_PATTERN,
+	NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED,
+	NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE,
+	NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST,
+	NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE,
+	NL80211_WOWLAN_TRIG_RFKILL_RELEASE,
+
+	/* keep last */
+	NUM_NL80211_WOWLAN_TRIG,
+	MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1
+};
+
+/**
+ * enum nl80211_iface_limit_attrs - limit attributes
+ * @NL80211_IFACE_LIMIT_UNSPEC: (reserved)
+ * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that
+ *	can be chosen from this set of interface types (u32)
+ * @NL80211_IFACE_LIMIT_TYPES: nested attribute containing a
+ *	flag attribute for each interface type in this set
+ * @NUM_NL80211_IFACE_LIMIT: number of attributes
+ * @MAX_NL80211_IFACE_LIMIT: highest attribute number
+ */
+enum nl80211_iface_limit_attrs {
+	NL80211_IFACE_LIMIT_UNSPEC,
+	NL80211_IFACE_LIMIT_MAX,
+	NL80211_IFACE_LIMIT_TYPES,
+
+	/* keep last */
+	NUM_NL80211_IFACE_LIMIT,
+	MAX_NL80211_IFACE_LIMIT = NUM_NL80211_IFACE_LIMIT - 1
+};
+
+/**
+ * enum nl80211_if_combination_attrs -- interface combination attributes
+ *
+ * @NL80211_IFACE_COMB_UNSPEC: (reserved)
+ * @NL80211_IFACE_COMB_LIMITS: Nested attributes containing the limits
+ *	for given interface types, see &enum nl80211_iface_limit_attrs.
+ * @NL80211_IFACE_COMB_MAXNUM: u32 attribute giving the total number of
+ *	interfaces that can be created in this group. This number doesn't
+ *	apply to interfaces purely managed in software, which are listed
+ *	in a separate attribute %NL80211_ATTR_INTERFACES_SOFTWARE.
+ * @NL80211_IFACE_COMB_STA_AP_BI_MATCH: flag attribute specifying that
+ *	beacon intervals within this group must be all the same even for
+ *	infrastructure and AP/GO combinations, i.e. the GO(s) must adopt
+ *	the infrastructure network's beacon interval.
+ * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many
+ *	different channels may be used within this group.
+ * @NUM_NL80211_IFACE_COMB: number of attributes
+ * @MAX_NL80211_IFACE_COMB: highest attribute number
+ *
+ * Examples:
+ *	limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2
+ *	=> allows an AP and a STA that must match BIs
+ *
+ *	numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8
+ *	=> allows 8 of AP/GO
+ *
+ *	numbers = [ #{STA} <= 2 ], channels = 2, max = 2
+ *	=> allows two STAs on different channels
+ *
+ *	numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4
+ *	=> allows a STA plus three P2P interfaces
+ *
+ * The list of these four possiblities could completely be contained
+ * within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate
+ * that any of these groups must match.
+ *
+ * "Combinations" of just a single interface will not be listed here,
+ * a single interface of any valid interface type is assumed to always
+ * be possible by itself. This means that implicitly, for each valid
+ * interface type, the following group always exists:
+ *	numbers = [ #{<type>} <= 1 ], channels = 1, max = 1
+ */
+enum nl80211_if_combination_attrs {
+	NL80211_IFACE_COMB_UNSPEC,
+	NL80211_IFACE_COMB_LIMITS,
+	NL80211_IFACE_COMB_MAXNUM,
+	NL80211_IFACE_COMB_STA_AP_BI_MATCH,
+	NL80211_IFACE_COMB_NUM_CHANNELS,
+
+	/* keep last */
+	NUM_NL80211_IFACE_COMB,
+	MAX_NL80211_IFACE_COMB = NUM_NL80211_IFACE_COMB - 1
+};
+
+
+/**
+ * enum nl80211_plink_state - state of a mesh peer link finite state machine
+ *
+ * @NL80211_PLINK_LISTEN: initial state, considered the implicit
+ *	state of non existant mesh peer links
+ * @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to
+ *	this mesh peer
+ * @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received
+ *	from this mesh peer
+ * @NL80211_PLINK_CNF_RCVD: mesh plink confirm frame has been
+ *	received from this mesh peer
+ * @NL80211_PLINK_ESTAB: mesh peer link is established
+ * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled
+ * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh
+ *	plink are discarded
+ * @NUM_NL80211_PLINK_STATES: number of peer link states
+ * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states
+ */
+enum nl80211_plink_state {
+	NL80211_PLINK_LISTEN,
+	NL80211_PLINK_OPN_SNT,
+	NL80211_PLINK_OPN_RCVD,
+	NL80211_PLINK_CNF_RCVD,
+	NL80211_PLINK_ESTAB,
+	NL80211_PLINK_HOLDING,
+	NL80211_PLINK_BLOCKED,
+
+	/* keep last */
+	NUM_NL80211_PLINK_STATES,
+	MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
+};
+
+#define NL80211_KCK_LEN			16
+#define NL80211_KEK_LEN			16
+#define NL80211_REPLAY_CTR_LEN		8
+
+/**
+ * enum nl80211_rekey_data - attributes for GTK rekey offload
+ * @__NL80211_REKEY_DATA_INVALID: invalid number for nested attributes
+ * @NL80211_REKEY_DATA_KEK: key encryption key (binary)
+ * @NL80211_REKEY_DATA_KCK: key confirmation key (binary)
+ * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary)
+ * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal)
+ * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal)
+ */
+enum nl80211_rekey_data {
+	__NL80211_REKEY_DATA_INVALID,
+	NL80211_REKEY_DATA_KEK,
+	NL80211_REKEY_DATA_KCK,
+	NL80211_REKEY_DATA_REPLAY_CTR,
+
+	/* keep last */
+	NUM_NL80211_REKEY_DATA,
+	MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1
+};
+
+/**
+ * enum nl80211_hidden_ssid - values for %NL80211_ATTR_HIDDEN_SSID
+ * @NL80211_HIDDEN_SSID_NOT_IN_USE: do not hide SSID (i.e., broadcast it in
+ *	Beacon frames)
+ * @NL80211_HIDDEN_SSID_ZERO_LEN: hide SSID by using zero-length SSID element
+ *	in Beacon frames
+ * @NL80211_HIDDEN_SSID_ZERO_CONTENTS: hide SSID by using correct length of SSID
+ *	element in Beacon frames but zero out each byte in the SSID
+ */
+enum nl80211_hidden_ssid {
+	NL80211_HIDDEN_SSID_NOT_IN_USE,
+	NL80211_HIDDEN_SSID_ZERO_LEN,
+	NL80211_HIDDEN_SSID_ZERO_CONTENTS
+};
+
+/**
+ * enum nl80211_sta_wme_attr - station WME attributes
+ * @__NL80211_STA_WME_INVALID: invalid number for nested attribute
+ * @NL80211_STA_WME_UAPSD_QUEUES: bitmap of uapsd queues. the format
+ *	is the same as the AC bitmap in the QoS info field.
+ * @NL80211_STA_WME_MAX_SP: max service period. the format is the same
+ *	as the MAX_SP field in the QoS info field (but already shifted down).
+ * @__NL80211_STA_WME_AFTER_LAST: internal
+ * @NL80211_STA_WME_MAX: highest station WME attribute
+ */
+enum nl80211_sta_wme_attr {
+	__NL80211_STA_WME_INVALID,
+	NL80211_STA_WME_UAPSD_QUEUES,
+	NL80211_STA_WME_MAX_SP,
+
+	/* keep last */
+	__NL80211_STA_WME_AFTER_LAST,
+	NL80211_STA_WME_MAX = __NL80211_STA_WME_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_pmksa_candidate_attr - attributes for PMKSA caching candidates
+ * @__NL80211_PMKSA_CANDIDATE_INVALID: invalid number for nested attributes
+ * @NL80211_PMKSA_CANDIDATE_INDEX: candidate index (u32; the smaller, the higher
+ *	priority)
+ * @NL80211_PMKSA_CANDIDATE_BSSID: candidate BSSID (6 octets)
+ * @NL80211_PMKSA_CANDIDATE_PREAUTH: RSN pre-authentication supported (flag)
+ * @NUM_NL80211_PMKSA_CANDIDATE: number of PMKSA caching candidate attributes
+ *	(internal)
+ * @MAX_NL80211_PMKSA_CANDIDATE: highest PMKSA caching candidate attribute
+ *	(internal)
+ */
+enum nl80211_pmksa_candidate_attr {
+	__NL80211_PMKSA_CANDIDATE_INVALID,
+	NL80211_PMKSA_CANDIDATE_INDEX,
+	NL80211_PMKSA_CANDIDATE_BSSID,
+	NL80211_PMKSA_CANDIDATE_PREAUTH,
+
+	/* keep last */
+	NUM_NL80211_PMKSA_CANDIDATE,
+	MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1
+};
+
+/**
+ * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION
+ * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request
+ * @NL80211_TDLS_SETUP: Setup TDLS link
+ * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established
+ * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link
+ * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link
+ */
+enum nl80211_tdls_operation {
+	NL80211_TDLS_DISCOVERY_REQ,
+	NL80211_TDLS_SETUP,
+	NL80211_TDLS_TEARDOWN,
+	NL80211_TDLS_ENABLE_LINK,
+	NL80211_TDLS_DISABLE_LINK,
+};
+
+/*
+ * enum nl80211_ap_sme_features - device-integrated AP features
+ * Reserved for future use, no bits are defined in
+ * NL80211_ATTR_DEVICE_AP_SME yet.
+enum nl80211_ap_sme_features {
+};
+ */
+
+/**
+ * enum nl80211_feature_flags - device/driver features
+ * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back
+ *	TX status to the socket error queue when requested with the
+ *	socket option.
+ */
+enum nl80211_feature_flags {
+	NL80211_FEATURE_SK_TX_STATUS	= 1 << 0,
+};
+
+/**
+ * enum nl80211_probe_resp_offload_support_attr - optional supported
+ *	protocols for probe-response offloading by the driver/FW.
+ *	To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute.
+ *	Each enum value represents a bit in the bitmap of supported
+ *	protocols. Typically a subset of probe-requests belonging to a
+ *	supported protocol will be excluded from offload and uploaded
+ *	to the host.
+ *
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u
+ */
+enum nl80211_probe_resp_offload_support_attr {
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS =	1<<0,
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 =	1<<1,
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P =	1<<2,
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U =	1<<3,
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/src/drivers/wireless_copy.h b/src/drivers/wireless_copy.h
deleted file mode 100644
index 201719b..0000000
--- a/src/drivers/wireless_copy.h
+++ /dev/null
@@ -1,1185 +0,0 @@
-/* This is based on Linux Wireless Extensions header file from WIRELESS_EXT 22.
- * I have just removed kernel related headers and added some typedefs etc. to
- * make this easier to include into user space programs.
- * Jouni Malinen, 2005-03-12.
- */
-
-
-/*
- * This file define a set of standard wireless extensions
- *
- * Version :	22	16.3.07
- *
- * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
- */
-
-#ifndef _LINUX_WIRELESS_H
-#define _LINUX_WIRELESS_H
-
-/************************** DOCUMENTATION **************************/
-/*
- * Initial APIs (1996 -> onward) :
- * -----------------------------
- * Basically, the wireless extensions are for now a set of standard ioctl
- * call + /proc/net/wireless
- *
- * The entry /proc/net/wireless give statistics and information on the
- * driver.
- * This is better than having each driver having its entry because
- * its centralised and we may remove the driver module safely.
- *
- * Ioctl are used to configure the driver and issue commands.  This is
- * better than command line options of insmod because we may want to
- * change dynamically (while the driver is running) some parameters.
- *
- * The ioctl mechanimsm are copied from standard devices ioctl.
- * We have the list of command plus a structure descibing the
- * data exchanged...
- * Note that to add these ioctl, I was obliged to modify :
- *	# net/core/dev.c (two place + add include)
- *	# net/ipv4/af_inet.c (one place + add include)
- *
- * /proc/net/wireless is a copy of /proc/net/dev.
- * We have a structure for data passed from the driver to /proc/net/wireless
- * Too add this, I've modified :
- *	# net/core/dev.c (two other places)
- *	# include/linux/netdevice.h (one place)
- *	# include/linux/proc_fs.h (one place)
- *
- * New driver API (2002 -> onward) :
- * -------------------------------
- * This file is only concerned with the user space API and common definitions.
- * The new driver API is defined and documented in :
- *	# include/net/iw_handler.h
- *
- * Note as well that /proc/net/wireless implementation has now moved in :
- *	# net/core/wireless.c
- *
- * Wireless Events (2002 -> onward) :
- * --------------------------------
- * Events are defined at the end of this file, and implemented in :
- *	# net/core/wireless.c
- *
- * Other comments :
- * --------------
- * Do not add here things that are redundant with other mechanisms
- * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
- * wireless specific.
- *
- * These wireless extensions are not magic : each driver has to provide
- * support for them...
- *
- * IMPORTANT NOTE : As everything in the kernel, this is very much a
- * work in progress. Contact me if you have ideas of improvements...
- */
-
-/***************************** INCLUDES *****************************/
-
- /* jkm - replaced linux headers with C library headers, added typedefs */
-#if 0
-#include <linux/types.h>		/* for __u* and __s* typedefs */
-#include <linux/socket.h>		/* for "struct sockaddr" et al	*/
-#include <linux/if.h>			/* for IFNAMSIZ and co... */
-#else
-#include <sys/types.h>
-#include <net/if.h>
-#ifndef ANDROID
-typedef __uint32_t __u32;
-typedef __int32_t __s32;
-typedef __uint16_t __u16;
-typedef __int16_t __s16;
-typedef __uint8_t __u8;
-#endif /* ANDROID */
-#ifndef __user
-#define __user
-#endif /* __user */
-#endif
-
-/***************************** VERSION *****************************/
-/*
- * This constant is used to know the availability of the wireless
- * extensions and to know which version of wireless extensions it is
- * (there is some stuff that will be added in the future...)
- * I just plan to increment with each new version.
- */
-#define WIRELESS_EXT	22
-
-/*
- * Changes :
- *
- * V2 to V3
- * --------
- *	Alan Cox start some incompatibles changes. I've integrated a bit more.
- *	- Encryption renamed to Encode to avoid US regulation problems
- *	- Frequency changed from float to struct to avoid problems on old 386
- *
- * V3 to V4
- * --------
- *	- Add sensitivity
- *
- * V4 to V5
- * --------
- *	- Missing encoding definitions in range
- *	- Access points stuff
- *
- * V5 to V6
- * --------
- *	- 802.11 support (ESSID ioctls)
- *
- * V6 to V7
- * --------
- *	- define IW_ESSID_MAX_SIZE and IW_MAX_AP
- *
- * V7 to V8
- * --------
- *	- Changed my e-mail address
- *	- More 802.11 support (nickname, rate, rts, frag)
- *	- List index in frequencies
- *
- * V8 to V9
- * --------
- *	- Support for 'mode of operation' (ad-hoc, managed...)
- *	- Support for unicast and multicast power saving
- *	- Change encoding to support larger tokens (>64 bits)
- *	- Updated iw_params (disable, flags) and use it for NWID
- *	- Extracted iw_point from iwreq for clarity
- *
- * V9 to V10
- * ---------
- *	- Add PM capability to range structure
- *	- Add PM modifier : MAX/MIN/RELATIVE
- *	- Add encoding option : IW_ENCODE_NOKEY
- *	- Add TxPower ioctls (work like TxRate)
- *
- * V10 to V11
- * ----------
- *	- Add WE version in range (help backward/forward compatibility)
- *	- Add retry ioctls (work like PM)
- *
- * V11 to V12
- * ----------
- *	- Add SIOCSIWSTATS to get /proc/net/wireless programatically
- *	- Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
- *	- Add new statistics (frag, retry, beacon)
- *	- Add average quality (for user space calibration)
- *
- * V12 to V13
- * ----------
- *	- Document creation of new driver API.
- *	- Extract union iwreq_data from struct iwreq (for new driver API).
- *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
- *
- * V13 to V14
- * ----------
- *	- Wireless Events support : define struct iw_event
- *	- Define additional specific event numbers
- *	- Add "addr" and "param" fields in union iwreq_data
- *	- AP scanning stuff (SIOCSIWSCAN and friends)
- *
- * V14 to V15
- * ----------
- *	- Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
- *	- Make struct iw_freq signed (both m & e), add explicit padding
- *	- Add IWEVCUSTOM for driver specific event/scanning token
- *	- Add IW_MAX_GET_SPY for driver returning a lot of addresses
- *	- Add IW_TXPOW_RANGE for range of Tx Powers
- *	- Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
- *	- Add IW_MODE_MONITOR for passive monitor
- *
- * V15 to V16
- * ----------
- *	- Increase the number of bitrates in iw_range to 32 (for 802.11g)
- *	- Increase the number of frequencies in iw_range to 32 (for 802.11b+a)
- *	- Reshuffle struct iw_range for increases, add filler
- *	- Increase IW_MAX_AP to 64 for driver returning a lot of addresses
- *	- Remove IW_MAX_GET_SPY because conflict with enhanced spy support
- *	- Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
- *	- Add IW_ENCODE_TEMP and iw_range->encoding_login_index
- *
- * V16 to V17
- * ----------
- *	- Add flags to frequency -> auto/fixed
- *	- Document (struct iw_quality *)->updated, add new flags (INVALID)
- *	- Wireless Event capability in struct iw_range
- *	- Add support for relative TxPower (yick !)
- *
- * V17 to V18 (From Jouni Malinen <j@w1.fi>)
- * ----------
- *	- Add support for WPA/WPA2
- *	- Add extended encoding configuration (SIOCSIWENCODEEXT and
- *	  SIOCGIWENCODEEXT)
- *	- Add SIOCSIWGENIE/SIOCGIWGENIE
- *	- Add SIOCSIWMLME
- *	- Add SIOCSIWPMKSA
- *	- Add struct iw_range bit field for supported encoding capabilities
- *	- Add optional scan request parameters for SIOCSIWSCAN
- *	- Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA
- *	  related parameters (extensible up to 4096 parameter values)
- *	- Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE,
- *	  IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND
- *
- * V18 to V19
- * ----------
- *	- Remove (struct iw_point *)->pointer from events and streams
- *	- Remove header includes to help user space
- *	- Increase IW_ENCODING_TOKEN_MAX from 32 to 64
- *	- Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros
- *	- Add explicit flag to tell stats are in dBm : IW_QUAL_DBM
- *	- Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros
- *
- * V19 to V20
- * ----------
- *	- RtNetlink requests support (SET/GET)
- *
- * V20 to V21
- * ----------
- *	- Remove (struct net_device *)->get_wireless_stats()
- *	- Change length in ESSID and NICK to strlen() instead of strlen()+1
- *	- Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers
- *	- Power/Retry relative values no longer * 100000
- *	- Add explicit flag to tell stats are in 802.11k RCPI : IW_QUAL_RCPI
- *
- * V21 to V22
- * ----------
- *	- Prevent leaking of kernel space in stream on 64 bits.
- */
-
-/**************************** CONSTANTS ****************************/
-
-/* -------------------------- IOCTL LIST -------------------------- */
-
-/* Wireless Identification */
-#define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
-#define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
-/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
- * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
- * Don't put the name of your driver there, it's useless. */
-
-/* Basic operations */
-#define SIOCSIWNWID	0x8B02		/* set network id (pre-802.11) */
-#define SIOCGIWNWID	0x8B03		/* get network id (the cell) */
-#define SIOCSIWFREQ	0x8B04		/* set channel/frequency (Hz) */
-#define SIOCGIWFREQ	0x8B05		/* get channel/frequency (Hz) */
-#define SIOCSIWMODE	0x8B06		/* set operation mode */
-#define SIOCGIWMODE	0x8B07		/* get operation mode */
-#define SIOCSIWSENS	0x8B08		/* set sensitivity (dBm) */
-#define SIOCGIWSENS	0x8B09		/* get sensitivity (dBm) */
-
-/* Informative stuff */
-#define SIOCSIWRANGE	0x8B0A		/* Unused */
-#define SIOCGIWRANGE	0x8B0B		/* Get range of parameters */
-#define SIOCSIWPRIV	0x8B0C		/* Unused */
-#define SIOCGIWPRIV	0x8B0D		/* get private ioctl interface info */
-#define SIOCSIWSTATS	0x8B0E		/* Unused */
-#define SIOCGIWSTATS	0x8B0F		/* Get /proc/net/wireless stats */
-/* SIOCGIWSTATS is strictly used between user space and the kernel, and
- * is never passed to the driver (i.e. the driver will never see it). */
-
-/* Spy support (statistics per MAC address - used for Mobile IP support) */
-#define SIOCSIWSPY	0x8B10		/* set spy addresses */
-#define SIOCGIWSPY	0x8B11		/* get spy info (quality of link) */
-#define SIOCSIWTHRSPY	0x8B12		/* set spy threshold (spy event) */
-#define SIOCGIWTHRSPY	0x8B13		/* get spy threshold */
-
-/* Access Point manipulation */
-#define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
-#define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
-#define SIOCGIWAPLIST	0x8B17		/* Deprecated in favor of scanning */
-#define SIOCSIWSCAN	0x8B18		/* trigger scanning (list cells) */
-#define SIOCGIWSCAN	0x8B19		/* get scanning results */
-
-/* 802.11 specific support */
-#define SIOCSIWESSID	0x8B1A		/* set ESSID (network name) */
-#define SIOCGIWESSID	0x8B1B		/* get ESSID */
-#define SIOCSIWNICKN	0x8B1C		/* set node name/nickname */
-#define SIOCGIWNICKN	0x8B1D		/* get node name/nickname */
-/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
- * within the 'iwreq' structure, so we need to use the 'data' member to
- * point to a string in user space, like it is done for RANGE... */
-
-/* Other parameters useful in 802.11 and some other devices */
-#define SIOCSIWRATE	0x8B20		/* set default bit rate (bps) */
-#define SIOCGIWRATE	0x8B21		/* get default bit rate (bps) */
-#define SIOCSIWRTS	0x8B22		/* set RTS/CTS threshold (bytes) */
-#define SIOCGIWRTS	0x8B23		/* get RTS/CTS threshold (bytes) */
-#define SIOCSIWFRAG	0x8B24		/* set fragmentation thr (bytes) */
-#define SIOCGIWFRAG	0x8B25		/* get fragmentation thr (bytes) */
-#define SIOCSIWTXPOW	0x8B26		/* set transmit power (dBm) */
-#define SIOCGIWTXPOW	0x8B27		/* get transmit power (dBm) */
-#define SIOCSIWRETRY	0x8B28		/* set retry limits and lifetime */
-#define SIOCGIWRETRY	0x8B29		/* get retry limits and lifetime */
-
-/* Encoding stuff (scrambling, hardware security, WEP...) */
-#define SIOCSIWENCODE	0x8B2A		/* set encoding token & mode */
-#define SIOCGIWENCODE	0x8B2B		/* get encoding token & mode */
-/* Power saving stuff (power management, unicast and multicast) */
-#define SIOCSIWPOWER	0x8B2C		/* set Power Management settings */
-#define SIOCGIWPOWER	0x8B2D		/* get Power Management settings */
-
-/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM).
- * This ioctl uses struct iw_point and data buffer that includes IE id and len
- * fields. More than one IE may be included in the request. Setting the generic
- * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers
- * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers
- * are required to report the used IE as a wireless event, e.g., when
- * associating with an AP. */
-#define SIOCSIWGENIE	0x8B30		/* set generic IE */
-#define SIOCGIWGENIE	0x8B31		/* get generic IE */
-
-/* WPA : IEEE 802.11 MLME requests */
-#define SIOCSIWMLME	0x8B16		/* request MLME operation; uses
-					 * struct iw_mlme */
-/* WPA : Authentication mode parameters */
-#define SIOCSIWAUTH	0x8B32		/* set authentication mode params */
-#define SIOCGIWAUTH	0x8B33		/* get authentication mode params */
-
-/* WPA : Extended version of encoding configuration */
-#define SIOCSIWENCODEEXT 0x8B34		/* set encoding token & mode */
-#define SIOCGIWENCODEEXT 0x8B35		/* get encoding token & mode */
-
-/* WPA2 : PMKSA cache management */
-#define SIOCSIWPMKSA	0x8B36		/* PMKSA cache operation */
-
-/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
-
-/* These 32 ioctl are wireless device private, for 16 commands.
- * Each driver is free to use them for whatever purpose it chooses,
- * however the driver *must* export the description of those ioctls
- * with SIOCGIWPRIV and *must* use arguments as defined below.
- * If you don't follow those rules, DaveM is going to hate you (reason :
- * it make mixed 32/64bit operation impossible).
- */
-#define SIOCIWFIRSTPRIV	0x8BE0
-#define SIOCIWLASTPRIV	0x8BFF
-/* Previously, we were using SIOCDEVPRIVATE, but we now have our
- * separate range because of collisions with other tools such as
- * 'mii-tool'.
- * We now have 32 commands, so a bit more space ;-).
- * Also, all 'even' commands are only usable by root and don't return the
- * content of ifr/iwr to user (but you are not obliged to use the set/get
- * convention, just use every other two command). More details in iwpriv.c.
- * And I repeat : you are not forced to use them with iwpriv, but you
- * must be compliant with it.
- */
-
-/* ------------------------- IOCTL STUFF ------------------------- */
-
-/* The first and the last (range) */
-#define SIOCIWFIRST	0x8B00
-#define SIOCIWLAST	SIOCIWLASTPRIV		/* 0x8BFF */
-#define IW_IOCTL_IDX(cmd)	((cmd) - SIOCIWFIRST)
-#define IW_HANDLER(id, func)			\
-	[IW_IOCTL_IDX(id)] = func
-
-/* Odd : get (world access), even : set (root access) */
-#define IW_IS_SET(cmd)	(!((cmd) & 0x1))
-#define IW_IS_GET(cmd)	((cmd) & 0x1)
-
-/* ----------------------- WIRELESS EVENTS ----------------------- */
-/* Those are *NOT* ioctls, do not issue request on them !!! */
-/* Most events use the same identifier as ioctl requests */
-
-#define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
-#define IWEVQUAL	0x8C01		/* Quality part of statistics (scan) */
-#define IWEVCUSTOM	0x8C02		/* Driver specific ascii string */
-#define IWEVREGISTERED	0x8C03		/* Discovered a new node (AP mode) */
-#define IWEVEXPIRED	0x8C04		/* Expired a node (AP mode) */
-#define IWEVGENIE	0x8C05		/* Generic IE (WPA, RSN, WMM, ..)
-					 * (scan results); This includes id and
-					 * length fields. One IWEVGENIE may
-					 * contain more than one IE. Scan
-					 * results may contain one or more
-					 * IWEVGENIE events. */
-#define IWEVMICHAELMICFAILURE 0x8C06	/* Michael MIC failure
-					 * (struct iw_michaelmicfailure)
-					 */
-#define IWEVASSOCREQIE	0x8C07		/* IEs used in (Re)Association Request.
-					 * The data includes id and length
-					 * fields and may contain more than one
-					 * IE. This event is required in
-					 * Managed mode if the driver
-					 * generates its own WPA/RSN IE. This
-					 * should be sent just before
-					 * IWEVREGISTERED event for the
-					 * association. */
-#define IWEVASSOCRESPIE	0x8C08		/* IEs used in (Re)Association
-					 * Response. The data includes id and
-					 * length fields and may contain more
-					 * than one IE. This may be sent
-					 * between IWEVASSOCREQIE and
-					 * IWEVREGISTERED events for the
-					 * association. */
-#define IWEVPMKIDCAND	0x8C09		/* PMKID candidate for RSN
-					 * pre-authentication
-					 * (struct iw_pmkid_cand) */
-
-#define IWEVFIRST	0x8C00
-#define IW_EVENT_IDX(cmd)	((cmd) - IWEVFIRST)
-
-/* ------------------------- PRIVATE INFO ------------------------- */
-/*
- * The following is used with SIOCGIWPRIV. It allow a driver to define
- * the interface (name, type of data) for its private ioctl.
- * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV
- */
-
-#define IW_PRIV_TYPE_MASK	0x7000	/* Type of arguments */
-#define IW_PRIV_TYPE_NONE	0x0000
-#define IW_PRIV_TYPE_BYTE	0x1000	/* Char as number */
-#define IW_PRIV_TYPE_CHAR	0x2000	/* Char as character */
-#define IW_PRIV_TYPE_INT	0x4000	/* 32 bits int */
-#define IW_PRIV_TYPE_FLOAT	0x5000	/* struct iw_freq */
-#define IW_PRIV_TYPE_ADDR	0x6000	/* struct sockaddr */
-
-#define IW_PRIV_SIZE_FIXED	0x0800	/* Variable or fixed number of args */
-
-#define IW_PRIV_SIZE_MASK	0x07FF	/* Max number of those args */
-
-/*
- * Note : if the number of args is fixed and the size < 16 octets,
- * instead of passing a pointer we will put args in the iwreq struct...
- */
-
-/* ----------------------- OTHER CONSTANTS ----------------------- */
-
-/* Maximum frequencies in the range struct */
-#define IW_MAX_FREQUENCIES	32
-/* Note : if you have something like 80 frequencies,
- * don't increase this constant and don't fill the frequency list.
- * The user will be able to set by channel anyway... */
-
-/* Maximum bit rates in the range struct */
-#define IW_MAX_BITRATES		32
-
-/* Maximum tx powers in the range struct */
-#define IW_MAX_TXPOWER		8
-/* Note : if you more than 8 TXPowers, just set the max and min or
- * a few of them in the struct iw_range. */
-
-/* Maximum of address that you may set with SPY */
-#define IW_MAX_SPY		8
-
-/* Maximum of address that you may get in the
-   list of access points in range */
-#define IW_MAX_AP		64
-
-/* Maximum size of the ESSID and NICKN strings */
-#define IW_ESSID_MAX_SIZE	32
-
-/* Modes of operation */
-#define IW_MODE_AUTO	0	/* Let the driver decides */
-#define IW_MODE_ADHOC	1	/* Single cell network */
-#define IW_MODE_INFRA	2	/* Multi cell network, roaming, ... */
-#define IW_MODE_MASTER	3	/* Synchronisation master or Access Point */
-#define IW_MODE_REPEAT	4	/* Wireless Repeater (forwarder) */
-#define IW_MODE_SECOND	5	/* Secondary master/repeater (backup) */
-#define IW_MODE_MONITOR	6	/* Passive monitor (listen only) */
-#define IW_MODE_MESH	7	/* Mesh (IEEE 802.11s) network */
-
-/* Statistics flags (bitmask in updated) */
-#define IW_QUAL_QUAL_UPDATED	0x01	/* Value was updated since last read */
-#define IW_QUAL_LEVEL_UPDATED	0x02
-#define IW_QUAL_NOISE_UPDATED	0x04
-#define IW_QUAL_ALL_UPDATED	0x07
-#define IW_QUAL_DBM		0x08	/* Level + Noise are dBm */
-#define IW_QUAL_QUAL_INVALID	0x10	/* Driver doesn't provide value */
-#define IW_QUAL_LEVEL_INVALID	0x20
-#define IW_QUAL_NOISE_INVALID	0x40
-#define IW_QUAL_RCPI		0x80	/* Level + Noise are 802.11k RCPI */
-#define IW_QUAL_ALL_INVALID	0x70
-
-/* Frequency flags */
-#define IW_FREQ_AUTO		0x00	/* Let the driver decides */
-#define IW_FREQ_FIXED		0x01	/* Force a specific value */
-
-/* Maximum number of size of encoding token available
- * they are listed in the range structure */
-#define IW_MAX_ENCODING_SIZES	8
-
-/* Maximum size of the encoding token in bytes */
-#define IW_ENCODING_TOKEN_MAX	64	/* 512 bits (for now) */
-
-/* Flags for encoding (along with the token) */
-#define IW_ENCODE_INDEX		0x00FF	/* Token index (if needed) */
-#define IW_ENCODE_FLAGS		0xFF00	/* Flags defined below */
-#define IW_ENCODE_MODE		0xF000	/* Modes defined below */
-#define IW_ENCODE_DISABLED	0x8000	/* Encoding disabled */
-#define IW_ENCODE_ENABLED	0x0000	/* Encoding enabled */
-#define IW_ENCODE_RESTRICTED	0x4000	/* Refuse non-encoded packets */
-#define IW_ENCODE_OPEN		0x2000	/* Accept non-encoded packets */
-#define IW_ENCODE_NOKEY		0x0800  /* Key is write only, so not present */
-#define IW_ENCODE_TEMP		0x0400  /* Temporary key */
-
-/* Power management flags available (along with the value, if any) */
-#define IW_POWER_ON		0x0000	/* No details... */
-#define IW_POWER_TYPE		0xF000	/* Type of parameter */
-#define IW_POWER_PERIOD		0x1000	/* Value is a period/duration of  */
-#define IW_POWER_TIMEOUT	0x2000	/* Value is a timeout (to go asleep) */
-#define IW_POWER_MODE		0x0F00	/* Power Management mode */
-#define IW_POWER_UNICAST_R	0x0100	/* Receive only unicast messages */
-#define IW_POWER_MULTICAST_R	0x0200	/* Receive only multicast messages */
-#define IW_POWER_ALL_R		0x0300	/* Receive all messages though PM */
-#define IW_POWER_FORCE_S	0x0400	/* Force PM procedure for sending unicast */
-#define IW_POWER_REPEATER	0x0800	/* Repeat broadcast messages in PM period */
-#define IW_POWER_MODIFIER	0x000F	/* Modify a parameter */
-#define IW_POWER_MIN		0x0001	/* Value is a minimum  */
-#define IW_POWER_MAX		0x0002	/* Value is a maximum */
-#define IW_POWER_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
-
-/* Transmit Power flags available */
-#define IW_TXPOW_TYPE		0x00FF	/* Type of value */
-#define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
-#define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
-#define IW_TXPOW_RELATIVE	0x0002	/* Value is in arbitrary units */
-#define IW_TXPOW_RANGE		0x1000	/* Range of value between min/max */
-
-/* Retry limits and lifetime flags available */
-#define IW_RETRY_ON		0x0000	/* No details... */
-#define IW_RETRY_TYPE		0xF000	/* Type of parameter */
-#define IW_RETRY_LIMIT		0x1000	/* Maximum number of retries*/
-#define IW_RETRY_LIFETIME	0x2000	/* Maximum duration of retries in us */
-#define IW_RETRY_MODIFIER	0x00FF	/* Modify a parameter */
-#define IW_RETRY_MIN		0x0001	/* Value is a minimum  */
-#define IW_RETRY_MAX		0x0002	/* Value is a maximum */
-#define IW_RETRY_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
-#define IW_RETRY_SHORT		0x0010	/* Value is for short packets  */
-#define IW_RETRY_LONG		0x0020	/* Value is for long packets */
-
-/* Scanning request flags */
-#define IW_SCAN_DEFAULT		0x0000	/* Default scan of the driver */
-#define IW_SCAN_ALL_ESSID	0x0001	/* Scan all ESSIDs */
-#define IW_SCAN_THIS_ESSID	0x0002	/* Scan only this ESSID */
-#define IW_SCAN_ALL_FREQ	0x0004	/* Scan all Frequencies */
-#define IW_SCAN_THIS_FREQ	0x0008	/* Scan only this Frequency */
-#define IW_SCAN_ALL_MODE	0x0010	/* Scan all Modes */
-#define IW_SCAN_THIS_MODE	0x0020	/* Scan only this Mode */
-#define IW_SCAN_ALL_RATE	0x0040	/* Scan all Bit-Rates */
-#define IW_SCAN_THIS_RATE	0x0080	/* Scan only this Bit-Rate */
-/* struct iw_scan_req scan_type */
-#define IW_SCAN_TYPE_ACTIVE 0
-#define IW_SCAN_TYPE_PASSIVE 1
-/* Maximum size of returned data */
-#define IW_SCAN_MAX_DATA	4096	/* In bytes */
-
-/* Scan capability flags - in (struct iw_range *)->scan_capa */
-#define IW_SCAN_CAPA_NONE		0x00
-#define IW_SCAN_CAPA_ESSID		0x01
-#define IW_SCAN_CAPA_BSSID		0x02
-#define IW_SCAN_CAPA_CHANNEL	0x04
-#define IW_SCAN_CAPA_MODE		0x08
-#define IW_SCAN_CAPA_RATE		0x10
-#define IW_SCAN_CAPA_TYPE		0x20
-#define IW_SCAN_CAPA_TIME		0x40
-
-/* Max number of char in custom event - use multiple of them if needed */
-#define IW_CUSTOM_MAX		256	/* In bytes */
-
-/* Generic information element */
-#define IW_GENERIC_IE_MAX	1024
-
-/* MLME requests (SIOCSIWMLME / struct iw_mlme) */
-#define IW_MLME_DEAUTH		0
-#define IW_MLME_DISASSOC	1
-#define IW_MLME_AUTH		2
-#define IW_MLME_ASSOC		3
-
-/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */
-#define IW_AUTH_INDEX		0x0FFF
-#define IW_AUTH_FLAGS		0xF000
-/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095)
- * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the
- * parameter that is being set/get to; value will be read/written to
- * struct iw_param value field) */
-#define IW_AUTH_WPA_VERSION		0
-#define IW_AUTH_CIPHER_PAIRWISE		1
-#define IW_AUTH_CIPHER_GROUP		2
-#define IW_AUTH_KEY_MGMT		3
-#define IW_AUTH_TKIP_COUNTERMEASURES	4
-#define IW_AUTH_DROP_UNENCRYPTED	5
-#define IW_AUTH_80211_AUTH_ALG		6
-#define IW_AUTH_WPA_ENABLED		7
-#define IW_AUTH_RX_UNENCRYPTED_EAPOL	8
-#define IW_AUTH_ROAMING_CONTROL		9
-#define IW_AUTH_PRIVACY_INVOKED		10
-#define IW_AUTH_CIPHER_GROUP_MGMT	11
-#define IW_AUTH_MFP			12
-
-/* IW_AUTH_WPA_VERSION values (bit field) */
-#define IW_AUTH_WPA_VERSION_DISABLED	0x00000001
-#define IW_AUTH_WPA_VERSION_WPA		0x00000002
-#define IW_AUTH_WPA_VERSION_WPA2	0x00000004
-
-/* IW_AUTH_PAIRWISE_CIPHER, IW_AUTH_GROUP_CIPHER, and IW_AUTH_CIPHER_GROUP_MGMT
- * values (bit field) */
-#define IW_AUTH_CIPHER_NONE	0x00000001
-#define IW_AUTH_CIPHER_WEP40	0x00000002
-#define IW_AUTH_CIPHER_TKIP	0x00000004
-#define IW_AUTH_CIPHER_CCMP	0x00000008
-#define IW_AUTH_CIPHER_WEP104	0x00000010
-#define IW_AUTH_CIPHER_AES_CMAC	0x00000020
-
-/* IW_AUTH_KEY_MGMT values (bit field) */
-#define IW_AUTH_KEY_MGMT_802_1X	1
-#define IW_AUTH_KEY_MGMT_PSK	2
-
-/* IW_AUTH_80211_AUTH_ALG values (bit field) */
-#define IW_AUTH_ALG_OPEN_SYSTEM	0x00000001
-#define IW_AUTH_ALG_SHARED_KEY	0x00000002
-#define IW_AUTH_ALG_LEAP	0x00000004
-
-/* IW_AUTH_ROAMING_CONTROL values */
-#define IW_AUTH_ROAMING_ENABLE	0	/* driver/firmware based roaming */
-#define IW_AUTH_ROAMING_DISABLE	1	/* user space program used for roaming
-					 * control */
-
-/* IW_AUTH_MFP (management frame protection) values */
-#define IW_AUTH_MFP_DISABLED	0	/* MFP disabled */
-#define IW_AUTH_MFP_OPTIONAL	1	/* MFP optional */
-#define IW_AUTH_MFP_REQUIRED	2	/* MFP required */
-
-/* SIOCSIWENCODEEXT definitions */
-#define IW_ENCODE_SEQ_MAX_SIZE	8
-/* struct iw_encode_ext ->alg */
-#define IW_ENCODE_ALG_NONE	0
-#define IW_ENCODE_ALG_WEP	1
-#define IW_ENCODE_ALG_TKIP	2
-#define IW_ENCODE_ALG_CCMP	3
-#define IW_ENCODE_ALG_PMK	4
-#define IW_ENCODE_ALG_AES_CMAC	5
-/* struct iw_encode_ext ->ext_flags */
-#define IW_ENCODE_EXT_TX_SEQ_VALID	0x00000001
-#define IW_ENCODE_EXT_RX_SEQ_VALID	0x00000002
-#define IW_ENCODE_EXT_GROUP_KEY		0x00000004
-#define IW_ENCODE_EXT_SET_TX_KEY	0x00000008
-
-/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */
-#define IW_MICFAILURE_KEY_ID	0x00000003 /* Key ID 0..3 */
-#define IW_MICFAILURE_GROUP	0x00000004
-#define IW_MICFAILURE_PAIRWISE	0x00000008
-#define IW_MICFAILURE_STAKEY	0x00000010
-#define IW_MICFAILURE_COUNT	0x00000060 /* 1 or 2 (0 = count not supported)
-					    */
-
-/* Bit field values for enc_capa in struct iw_range */
-#define IW_ENC_CAPA_WPA		0x00000001
-#define IW_ENC_CAPA_WPA2	0x00000002
-#define IW_ENC_CAPA_CIPHER_TKIP	0x00000004
-#define IW_ENC_CAPA_CIPHER_CCMP	0x00000008
-#define IW_ENC_CAPA_4WAY_HANDSHAKE	0x00000010
-
-/* Event capability macros - in (struct iw_range *)->event_capa
- * Because we have more than 32 possible events, we use an array of
- * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */
-#define IW_EVENT_CAPA_BASE(cmd)		((cmd >= SIOCIWFIRSTPRIV) ? \
-					 (cmd - SIOCIWFIRSTPRIV + 0x60) : \
-					 (cmd - SIOCIWFIRST))
-#define IW_EVENT_CAPA_INDEX(cmd)	(IW_EVENT_CAPA_BASE(cmd) >> 5)
-#define IW_EVENT_CAPA_MASK(cmd)		(1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F))
-/* Event capability constants - event autogenerated by the kernel
- * This list is valid for most 802.11 devices, customise as needed... */
-#define IW_EVENT_CAPA_K_0	(IW_EVENT_CAPA_MASK(0x8B04) | \
-				 IW_EVENT_CAPA_MASK(0x8B06) | \
-				 IW_EVENT_CAPA_MASK(0x8B1A))
-#define IW_EVENT_CAPA_K_1	(IW_EVENT_CAPA_MASK(0x8B2A))
-/* "Easy" macro to set events in iw_range (less efficient) */
-#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd))
-#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; }
-
-
-/****************************** TYPES ******************************/
-
-/* --------------------------- SUBTYPES --------------------------- */
-/*
- *	Generic format for most parameters that fit in an int
- */
-struct	iw_param
-{
-  __s32		value;		/* The value of the parameter itself */
-  __u8		fixed;		/* Hardware should not use auto select */
-  __u8		disabled;	/* Disable the feature */
-  __u16		flags;		/* Various specifc flags (if any) */
-};
-
-/*
- *	For all data larger than 16 octets, we need to use a
- *	pointer to memory allocated in user space.
- */
-struct	iw_point
-{
-  void __user	*pointer;	/* Pointer to the data  (in user space) */
-  __u16		length;		/* number of fields or size in bytes */
-  __u16		flags;		/* Optional params */
-};
-
-#ifdef __KERNEL__
-#ifdef CONFIG_COMPAT
-
-#include <linux/compat.h>
-
-struct compat_iw_point {
-	compat_caddr_t pointer;
-	__u16 length;
-	__u16 flags;
-};
-#endif
-#endif
-
-/*
- *	A frequency
- *	For numbers lower than 10^9, we encode the number in 'm' and
- *	set 'e' to 0
- *	For number greater than 10^9, we divide it by the lowest power
- *	of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')...
- *	The power of 10 is in 'e', the result of the division is in 'm'.
- */
-struct	iw_freq
-{
-	__s32		m;		/* Mantissa */
-	__s16		e;		/* Exponent */
-	__u8		i;		/* List index (when in range struct) */
-	__u8		flags;		/* Flags (fixed/auto) */
-};
-
-/*
- *	Quality of the link
- */
-struct	iw_quality
-{
-	__u8		qual;		/* link quality (%retries, SNR,
-					   %missed beacons or better...) */
-	__u8		level;		/* signal level (dBm) */
-	__u8		noise;		/* noise level (dBm) */
-	__u8		updated;	/* Flags to know if updated */
-};
-
-/*
- *	Packet discarded in the wireless adapter due to
- *	"wireless" specific problems...
- *	Note : the list of counter and statistics in net_device_stats
- *	is already pretty exhaustive, and you should use that first.
- *	This is only additional stats...
- */
-struct	iw_discarded
-{
-	__u32		nwid;		/* Rx : Wrong nwid/essid */
-	__u32		code;		/* Rx : Unable to code/decode (WEP) */
-	__u32		fragment;	/* Rx : Can't perform MAC reassembly */
-	__u32		retries;	/* Tx : Max MAC retries num reached */
-	__u32		misc;		/* Others cases */
-};
-
-/*
- *	Packet/Time period missed in the wireless adapter due to
- *	"wireless" specific problems...
- */
-struct	iw_missed
-{
-	__u32		beacon;		/* Missed beacons/superframe */
-};
-
-/*
- *	Quality range (for spy threshold)
- */
-struct	iw_thrspy
-{
-	struct sockaddr		addr;		/* Source address (hw/mac) */
-	struct iw_quality	qual;		/* Quality of the link */
-	struct iw_quality	low;		/* Low threshold */
-	struct iw_quality	high;		/* High threshold */
-};
-
-/*
- *	Optional data for scan request
- *
- *	Note: these optional parameters are controlling parameters for the
- *	scanning behavior, these do not apply to getting scan results
- *	(SIOCGIWSCAN). Drivers are expected to keep a local BSS table and
- *	provide a merged results with all BSSes even if the previous scan
- *	request limited scanning to a subset, e.g., by specifying an SSID.
- *	Especially, scan results are required to include an entry for the
- *	current BSS if the driver is in Managed mode and associated with an AP.
- */
-struct	iw_scan_req
-{
-	__u8		scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */
-	__u8		essid_len;
-	__u8		num_channels; /* num entries in channel_list;
-				       * 0 = scan all allowed channels */
-	__u8		flags; /* reserved as padding; use zero, this may
-				* be used in the future for adding flags
-				* to request different scan behavior */
-	struct sockaddr	bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or
-				* individual address of a specific BSS */
-
-	/*
-	 * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using
-	 * the current ESSID. This allows scan requests for specific ESSID
-	 * without having to change the current ESSID and potentially breaking
-	 * the current association.
-	 */
-	__u8		essid[IW_ESSID_MAX_SIZE];
-
-	/*
-	 * Optional parameters for changing the default scanning behavior.
-	 * These are based on the MLME-SCAN.request from IEEE Std 802.11.
-	 * TU is 1.024 ms. If these are set to 0, driver is expected to use
-	 * reasonable default values. min_channel_time defines the time that
-	 * will be used to wait for the first reply on each channel. If no
-	 * replies are received, next channel will be scanned after this. If
-	 * replies are received, total time waited on the channel is defined by
-	 * max_channel_time.
-	 */
-	__u32		min_channel_time; /* in TU */
-	__u32		max_channel_time; /* in TU */
-
-	struct iw_freq	channel_list[IW_MAX_FREQUENCIES];
-};
-
-/* ------------------------- WPA SUPPORT ------------------------- */
-
-/*
- *	Extended data structure for get/set encoding (this is used with
- *	SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_*
- *	flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and
- *	only the data contents changes (key data -> this structure, including
- *	key data).
- *
- *	If the new key is the first group key, it will be set as the default
- *	TX key. Otherwise, default TX key index is only changed if
- *	IW_ENCODE_EXT_SET_TX_KEY flag is set.
- *
- *	Key will be changed with SIOCSIWENCODEEXT in all cases except for
- *	special "change TX key index" operation which is indicated by setting
- *	key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY.
- *
- *	tx_seq/rx_seq are only used when respective
- *	IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal
- *	TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start
- *	TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally
- *	used only by an Authenticator (AP or an IBSS station) to get the
- *	current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and
- *	RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for
- *	debugging/testing.
- */
-struct	iw_encode_ext
-{
-	__u32		ext_flags; /* IW_ENCODE_EXT_* */
-	__u8		tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
-	__u8		rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
-	struct sockaddr	addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast
-			       * (group) keys or unicast address for
-			       * individual keys */
-	__u16		alg; /* IW_ENCODE_ALG_* */
-	__u16		key_len;
-	__u8		key[0];
-};
-
-/* SIOCSIWMLME data */
-struct	iw_mlme
-{
-	__u16		cmd; /* IW_MLME_* */
-	__u16		reason_code;
-	struct sockaddr	addr;
-};
-
-/* SIOCSIWPMKSA data */
-#define IW_PMKSA_ADD		1
-#define IW_PMKSA_REMOVE		2
-#define IW_PMKSA_FLUSH		3
-
-#define IW_PMKID_LEN	16
-
-struct	iw_pmksa
-{
-	__u32		cmd; /* IW_PMKSA_* */
-	struct sockaddr	bssid;
-	__u8		pmkid[IW_PMKID_LEN];
-};
-
-/* IWEVMICHAELMICFAILURE data */
-struct	iw_michaelmicfailure
-{
-	__u32		flags;
-	struct sockaddr	src_addr;
-	__u8		tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
-};
-
-/* IWEVPMKIDCAND data */
-#define IW_PMKID_CAND_PREAUTH	0x00000001 /* RNS pre-authentication enabled */
-struct	iw_pmkid_cand
-{
-	__u32		flags; /* IW_PMKID_CAND_* */
-	__u32		index; /* the smaller the index, the higher the
-				* priority */
-	struct sockaddr	bssid;
-};
-
-/* ------------------------ WIRELESS STATS ------------------------ */
-/*
- * Wireless statistics (used for /proc/net/wireless)
- */
-struct	iw_statistics
-{
-	__u16		status;		/* Status
-					 * - device dependent for now */
-
-	struct iw_quality	qual;		/* Quality of the link
-						 * (instant/mean/max) */
-	struct iw_discarded	discard;	/* Packet discarded counts */
-	struct iw_missed	miss;		/* Packet missed counts */
-};
-
-/* ------------------------ IOCTL REQUEST ------------------------ */
-/*
- * This structure defines the payload of an ioctl, and is used 
- * below.
- *
- * Note that this structure should fit on the memory footprint
- * of iwreq (which is the same as ifreq), which mean a max size of
- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
- * You should check this when increasing the structures defined
- * above in this file...
- */
-union	iwreq_data
-{
-	/* Config - generic */
-	char		name[IFNAMSIZ];
-	/* Name : used to verify the presence of  wireless extensions.
-	 * Name of the protocol/provider... */
-
-	struct iw_point	essid;		/* Extended network name */
-	struct iw_param	nwid;		/* network id (or domain - the cell) */
-	struct iw_freq	freq;		/* frequency or channel :
-					 * 0-1000 = channel
-					 * > 1000 = frequency in Hz */
-
-	struct iw_param	sens;		/* signal level threshold */
-	struct iw_param	bitrate;	/* default bit rate */
-	struct iw_param	txpower;	/* default transmit power */
-	struct iw_param	rts;		/* RTS threshold threshold */
-	struct iw_param	frag;		/* Fragmentation threshold */
-	__u32		mode;		/* Operation mode */
-	struct iw_param	retry;		/* Retry limits & lifetime */
-
-	struct iw_point	encoding;	/* Encoding stuff : tokens */
-	struct iw_param	power;		/* PM duration/timeout */
-	struct iw_quality qual;		/* Quality part of statistics */
-
-	struct sockaddr	ap_addr;	/* Access point address */
-	struct sockaddr	addr;		/* Destination address (hw/mac) */
-
-	struct iw_param	param;		/* Other small parameters */
-	struct iw_point	data;		/* Other large parameters */
-};
-
-/*
- * The structure to exchange data for ioctl.
- * This structure is the same as 'struct ifreq', but (re)defined for
- * convenience...
- * Do I need to remind you about structure size (32 octets) ?
- */
-struct	iwreq 
-{
-	union
-	{
-		char	ifrn_name[IFNAMSIZ];	/* if name, e.g. "eth0" */
-	} ifr_ifrn;
-
-	/* Data part (defined just above) */
-	union	iwreq_data	u;
-};
-
-/* -------------------------- IOCTL DATA -------------------------- */
-/*
- *	For those ioctl which want to exchange mode data that what could
- *	fit in the above structure...
- */
-
-/*
- *	Range of parameters
- */
-
-struct	iw_range
-{
-	/* Informative stuff (to choose between different interface) */
-	__u32		throughput;	/* To give an idea... */
-	/* In theory this value should be the maximum benchmarked
-	 * TCP/IP throughput, because with most of these devices the
-	 * bit rate is meaningless (overhead an co) to estimate how
-	 * fast the connection will go and pick the fastest one.
-	 * I suggest people to play with Netperf or any benchmark...
-	 */
-
-	/* NWID (or domain id) */
-	__u32		min_nwid;	/* Minimal NWID we are able to set */
-	__u32		max_nwid;	/* Maximal NWID we are able to set */
-
-	/* Old Frequency (backward compat - moved lower ) */
-	__u16		old_num_channels;
-	__u8		old_num_frequency;
-
-	/* Scan capabilities */
-	__u8		scan_capa; 	/* IW_SCAN_CAPA_* bit field */
-
-	/* Wireless event capability bitmasks */
-	__u32		event_capa[6];
-
-	/* signal level threshold range */
-	__s32		sensitivity;
-
-	/* Quality of link & SNR stuff */
-	/* Quality range (link, level, noise)
-	 * If the quality is absolute, it will be in the range [0 ; max_qual],
-	 * if the quality is dBm, it will be in the range [max_qual ; 0].
-	 * Don't forget that we use 8 bit arithmetics... */
-	struct iw_quality	max_qual;	/* Quality of the link */
-	/* This should contain the average/typical values of the quality
-	 * indicator. This should be the threshold between a "good" and
-	 * a "bad" link (example : monitor going from green to orange).
-	 * Currently, user space apps like quality monitors don't have any
-	 * way to calibrate the measurement. With this, they can split
-	 * the range between 0 and max_qual in different quality level
-	 * (using a geometric subdivision centered on the average).
-	 * I expect that people doing the user space apps will feedback
-	 * us on which value we need to put in each driver... */
-	struct iw_quality	avg_qual;	/* Quality of the link */
-
-	/* Rates */
-	__u8		num_bitrates;	/* Number of entries in the list */
-	__s32		bitrate[IW_MAX_BITRATES];	/* list, in bps */
-
-	/* RTS threshold */
-	__s32		min_rts;	/* Minimal RTS threshold */
-	__s32		max_rts;	/* Maximal RTS threshold */
-
-	/* Frag threshold */
-	__s32		min_frag;	/* Minimal frag threshold */
-	__s32		max_frag;	/* Maximal frag threshold */
-
-	/* Power Management duration & timeout */
-	__s32		min_pmp;	/* Minimal PM period */
-	__s32		max_pmp;	/* Maximal PM period */
-	__s32		min_pmt;	/* Minimal PM timeout */
-	__s32		max_pmt;	/* Maximal PM timeout */
-	__u16		pmp_flags;	/* How to decode max/min PM period */
-	__u16		pmt_flags;	/* How to decode max/min PM timeout */
-	__u16		pm_capa;	/* What PM options are supported */
-
-	/* Encoder stuff */
-	__u16	encoding_size[IW_MAX_ENCODING_SIZES];	/* Different token sizes */
-	__u8	num_encoding_sizes;	/* Number of entry in the list */
-	__u8	max_encoding_tokens;	/* Max number of tokens */
-	/* For drivers that need a "login/passwd" form */
-	__u8	encoding_login_index;	/* token index for login token */
-
-	/* Transmit power */
-	__u16		txpower_capa;	/* What options are supported */
-	__u8		num_txpower;	/* Number of entries in the list */
-	__s32		txpower[IW_MAX_TXPOWER];	/* list, in bps */
-
-	/* Wireless Extension version info */
-	__u8		we_version_compiled;	/* Must be WIRELESS_EXT */
-	__u8		we_version_source;	/* Last update of source */
-
-	/* Retry limits and lifetime */
-	__u16		retry_capa;	/* What retry options are supported */
-	__u16		retry_flags;	/* How to decode max/min retry limit */
-	__u16		r_time_flags;	/* How to decode max/min retry life */
-	__s32		min_retry;	/* Minimal number of retries */
-	__s32		max_retry;	/* Maximal number of retries */
-	__s32		min_r_time;	/* Minimal retry lifetime */
-	__s32		max_r_time;	/* Maximal retry lifetime */
-
-	/* Frequency */
-	__u16		num_channels;	/* Number of channels [0; num - 1] */
-	__u8		num_frequency;	/* Number of entry in the list */
-	struct iw_freq	freq[IW_MAX_FREQUENCIES];	/* list */
-	/* Note : this frequency list doesn't need to fit channel numbers,
-	 * because each entry contain its channel index */
-
-	__u32		enc_capa;	/* IW_ENC_CAPA_* bit field */
-};
-
-/*
- * Private ioctl interface information
- */
- 
-struct	iw_priv_args
-{
-	__u32		cmd;		/* Number of the ioctl to issue */
-	__u16		set_args;	/* Type and number of args */
-	__u16		get_args;	/* Type and number of args */
-	char		name[IFNAMSIZ];	/* Name of the extension */
-};
-
-/* ----------------------- WIRELESS EVENTS ----------------------- */
-/*
- * Wireless events are carried through the rtnetlink socket to user
- * space. They are encapsulated in the IFLA_WIRELESS field of
- * a RTM_NEWLINK message.
- */
-
-/*
- * A Wireless Event. Contains basically the same data as the ioctl...
- */
-struct iw_event
-{
-	__u16		len;			/* Real length of this stuff */
-	__u16		cmd;			/* Wireless IOCTL */
-	union iwreq_data	u;		/* IOCTL fixed payload */
-};
-
-/* Size of the Event prefix (including padding and alignement junk) */
-#define IW_EV_LCP_LEN	(sizeof(struct iw_event) - sizeof(union iwreq_data))
-/* Size of the various events */
-#define IW_EV_CHAR_LEN	(IW_EV_LCP_LEN + IFNAMSIZ)
-#define IW_EV_UINT_LEN	(IW_EV_LCP_LEN + sizeof(__u32))
-#define IW_EV_FREQ_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_freq))
-#define IW_EV_PARAM_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_param))
-#define IW_EV_ADDR_LEN	(IW_EV_LCP_LEN + sizeof(struct sockaddr))
-#define IW_EV_QUAL_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_quality))
-
-/* iw_point events are special. First, the payload (extra data) come at
- * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second,
- * we omit the pointer, so start at an offset. */
-#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \
-			  (char *) NULL)
-#define IW_EV_POINT_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_point) - \
-			 IW_EV_POINT_OFF)
-
-#ifdef __KERNEL__
-#ifdef CONFIG_COMPAT
-struct __compat_iw_event {
-	__u16		len;			/* Real length of this stuff */
-	__u16		cmd;			/* Wireless IOCTL */
-	compat_caddr_t	pointer;
-};
-#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer)
-#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length)
-
-/* Size of the various events for compat */
-#define IW_EV_COMPAT_CHAR_LEN	(IW_EV_COMPAT_LCP_LEN + IFNAMSIZ)
-#define IW_EV_COMPAT_UINT_LEN	(IW_EV_COMPAT_LCP_LEN + sizeof(__u32))
-#define IW_EV_COMPAT_FREQ_LEN	(IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_freq))
-#define IW_EV_COMPAT_PARAM_LEN	(IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_param))
-#define IW_EV_COMPAT_ADDR_LEN	(IW_EV_COMPAT_LCP_LEN + sizeof(struct sockaddr))
-#define IW_EV_COMPAT_QUAL_LEN	(IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_quality))
-#define IW_EV_COMPAT_POINT_LEN	\
-	(IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \
-	 IW_EV_COMPAT_POINT_OFF)
-#endif
-#endif
-
-/* Size of the Event prefix when packed in stream */
-#define IW_EV_LCP_PK_LEN	(4)
-/* Size of the various events when packed in stream */
-#define IW_EV_CHAR_PK_LEN	(IW_EV_LCP_PK_LEN + IFNAMSIZ)
-#define IW_EV_UINT_PK_LEN	(IW_EV_LCP_PK_LEN + sizeof(__u32))
-#define IW_EV_FREQ_PK_LEN	(IW_EV_LCP_PK_LEN + sizeof(struct iw_freq))
-#define IW_EV_PARAM_PK_LEN	(IW_EV_LCP_PK_LEN + sizeof(struct iw_param))
-#define IW_EV_ADDR_PK_LEN	(IW_EV_LCP_PK_LEN + sizeof(struct sockaddr))
-#define IW_EV_QUAL_PK_LEN	(IW_EV_LCP_PK_LEN + sizeof(struct iw_quality))
-#define IW_EV_POINT_PK_LEN	(IW_EV_LCP_PK_LEN + 4)
-
-#endif	/* _LINUX_WIRELESS_H */
diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c
index 4de34a8..d3406f3 100644
--- a/src/eap_common/eap_fast_common.c
+++ b/src/eap_common/eap_fast_common.c
@@ -133,9 +133,9 @@
 
 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
 			"expansion", keys.master_key, keys.master_key_len);
-	if (tls_prf(keys.master_key, keys.master_key_len,
-		    label, rnd, keys.client_random_len +
-		    keys.server_random_len, out, block_size + len))
+	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+			     label, rnd, keys.client_random_len +
+			     keys.server_random_len, out, block_size + len))
 		goto fail;
 	os_free(rnd);
 	os_memmove(out, out + block_size, len);
diff --git a/src/eap_common/eap_peap_common.c b/src/eap_common/eap_peap_common.c
index 3a64b8e..8a701d2 100644
--- a/src/eap_common/eap_peap_common.c
+++ b/src/eap_common/eap_peap_common.c
@@ -1,6 +1,6 @@
 /*
  * EAP-PEAP common routines
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -18,9 +18,9 @@
 #include "crypto/sha1.h"
 #include "eap_peap_common.h"
 
-void peap_prfplus(int version, const u8 *key, size_t key_len,
-		  const char *label, const u8 *seed, size_t seed_len,
-		  u8 *buf, size_t buf_len)
+int peap_prfplus(int version, const u8 *key, size_t key_len,
+		 const char *label, const u8 *seed, size_t seed_len,
+		 u8 *buf, size_t buf_len)
 {
 	unsigned char counter = 0;
 	size_t pos, plen;
@@ -75,7 +75,8 @@
 	while (pos < buf_len) {
 		counter++;
 		plen = buf_len - pos;
-		hmac_sha1_vector(key, key_len, 5, addr, len, hash);
+		if (hmac_sha1_vector(key, key_len, 5, addr, len, hash) < 0)
+			return -1;
 		if (plen >= SHA1_MAC_LEN) {
 			os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
 			pos += SHA1_MAC_LEN;
@@ -85,4 +86,6 @@
 		}
 		len[0] = SHA1_MAC_LEN;
 	}
+
+	return 0;
 }
diff --git a/src/eap_common/eap_peap_common.h b/src/eap_common/eap_peap_common.h
index f59afb0..f182078 100644
--- a/src/eap_common/eap_peap_common.h
+++ b/src/eap_common/eap_peap_common.h
@@ -1,6 +1,6 @@
 /*
  * EAP-PEAP common routines
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -15,8 +15,8 @@
 #ifndef EAP_PEAP_COMMON_H
 #define EAP_PEAP_COMMON_H
 
-void peap_prfplus(int version, const u8 *key, size_t key_len,
-		  const char *label, const u8 *seed, size_t seed_len,
-		  u8 *buf, size_t buf_len);
+int peap_prfplus(int version, const u8 *key, size_t key_len,
+		 const char *label, const u8 *seed, size_t seed_len,
+		 u8 *buf, size_t buf_len);
 
 #endif /* EAP_PEAP_COMMON_H */
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index c24b146..0dbdff2 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -75,8 +75,8 @@
 
 	/* since we're expanding to a bit length, mask off the excess */
 	if (resultbitlen % 8) {
-		mask >>= ((resultbytelen * 8) - resultbitlen);
-		result[0] &= mask;
+		mask <<= (8 - (resultbitlen % 8));
+		result[resultbytelen - 1] &= mask;
 	}
 }
 
@@ -189,6 +189,18 @@
 			    prfbuf, primebitlen);
 
 		BN_bin2bn(prfbuf, primebytelen, x_candidate);
+
+		/*
+		 * eap_pwd_kdf() returns a string of bits 0..primebitlen but
+		 * BN_bin2bn will treat that string of bits as a big endian
+		 * number. If the primebitlen is not an even multiple of 8
+		 * then excessive bits-- those _after_ primebitlen-- so now
+		 * we have to shift right the amount we masked off.
+		 */
+		if (primebitlen % 8)
+			BN_rshift(x_candidate, x_candidate,
+				  (8 - (primebitlen % 8)));
+
 		if (BN_ucmp(x_candidate, grp->prime) >= 0)
 			continue;
 
@@ -272,6 +284,7 @@
 	u8 mk[SHA256_DIGEST_LENGTH], *cruft;
 	u8 session_id[SHA256_DIGEST_LENGTH + 1];
 	u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN];
+	int offset;
 
 	if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL)
 		return -1;
@@ -283,16 +296,21 @@
 	session_id[0] = EAP_TYPE_PWD;
 	H_Init(&ctx);
 	H_Update(&ctx, (u8 *)ciphersuite, sizeof(u32));
-	BN_bn2bin(peer_scalar, cruft);
+	offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar);
+	os_memset(cruft, 0, BN_num_bytes(grp->prime));
+	BN_bn2bin(peer_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(grp->order));
-	BN_bn2bin(server_scalar, cruft);
+	offset = BN_num_bytes(grp->order) - BN_num_bytes(server_scalar);
+	os_memset(cruft, 0, BN_num_bytes(grp->prime));
+	BN_bn2bin(server_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(grp->order));
 	H_Final(&ctx, &session_id[1]);
 
 	/* then compute MK = H(k | commit-peer | commit-server) */
 	H_Init(&ctx);
+	offset = BN_num_bytes(grp->prime) - BN_num_bytes(k);
 	os_memset(cruft, 0, BN_num_bytes(grp->prime));
-	BN_bn2bin(k, cruft);
+	BN_bn2bin(k, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(grp->prime));
 	H_Update(&ctx, commit_peer, SHA256_DIGEST_LENGTH);
 	H_Update(&ctx, commit_server, SHA256_DIGEST_LENGTH);
diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h
index 971386d..4b841b7 100644
--- a/src/eap_common/eap_pwd_common.h
+++ b/src/eap_common/eap_pwd_common.h
@@ -35,13 +35,8 @@
 
 /*
  * EAP-pwd header, included on all payloads
+ * L(1 bit) | M(1 bit) | exch(6 bits) | total_length(if L is set)
  */
-struct eap_pwd_hdr {
-	u8 l_bit:1;
-	u8 m_bit:1;
-	u8 exch:6;
-	u8 total_length[0];         /* included when l_bit is set */
-} STRUCT_PACKED;
 
 #define EAP_PWD_OPCODE_ID_EXCH          1
 #define EAP_PWD_OPCODE_COMMIT_EXCH      2
diff --git a/src/eap_common/ikev2_common.h b/src/eap_common/ikev2_common.h
index c96a070..31a2b0d 100644
--- a/src/eap_common/ikev2_common.h
+++ b/src/eap_common/ikev2_common.h
@@ -139,7 +139,7 @@
 	IKEV2_TRANSFORM_ESN = 5
 };
 
-/* IKEv2 Tranform Type 1 (Encryption Algorithm) */
+/* IKEv2 Transform Type 1 (Encryption Algorithm) */
 enum {
 	ENCR_DES_IV64 = 1,
 	ENCR_DES = 2,
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index ecfaf30..91fa4a9 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -147,6 +147,7 @@
 	sm->methodState = METHOD_NONE;
 	sm->allowNotifications = TRUE;
 	sm->decision = DECISION_FAIL;
+	sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
 	eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
 	eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
 	eapol_set_bool(sm, EAPOL_eapFail, FALSE);
@@ -1242,6 +1243,7 @@
 #endif /* CONFIG_FIPS */
 	tlsconf.event_cb = eap_peer_sm_tls_event;
 	tlsconf.cb_ctx = sm;
+	tlsconf.cert_in_cb = conf->cert_in_cb;
 	sm->ssl_ctx = tls_init(&tlsconf);
 	if (sm->ssl_ctx == NULL) {
 		wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
@@ -1466,16 +1468,11 @@
 
 
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-typedef enum {
-	TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD,
-	TYPE_PASSPHRASE
-} eap_ctrl_req_type;
-
-static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
+static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
 			   const char *msg, size_t msglen)
 {
 	struct eap_peer_config *config;
-	char *field, *txt, *tmp;
+	char *txt = NULL, *tmp;
 
 	if (sm == NULL)
 		return;
@@ -1483,29 +1480,20 @@
 	if (config == NULL)
 		return;
 
-	switch (type) {
-	case TYPE_IDENTITY:
-		field = "IDENTITY";
-		txt = "Identity";
+	switch (field) {
+	case WPA_CTRL_REQ_EAP_IDENTITY:
 		config->pending_req_identity++;
 		break;
-	case TYPE_PASSWORD:
-		field = "PASSWORD";
-		txt = "Password";
+	case WPA_CTRL_REQ_EAP_PASSWORD:
 		config->pending_req_password++;
 		break;
-	case TYPE_NEW_PASSWORD:
-		field = "NEW_PASSWORD";
-		txt = "New Password";
+	case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
 		config->pending_req_new_password++;
 		break;
-	case TYPE_PIN:
-		field = "PIN";
-		txt = "PIN";
+	case WPA_CTRL_REQ_EAP_PIN:
 		config->pending_req_pin++;
 		break;
-	case TYPE_OTP:
-		field = "OTP";
+	case WPA_CTRL_REQ_EAP_OTP:
 		if (msg) {
 			tmp = os_malloc(msglen + 3);
 			if (tmp == NULL)
@@ -1524,9 +1512,7 @@
 			txt = config->pending_req_otp;
 		}
 		break;
-	case TYPE_PASSPHRASE:
-		field = "PASSPHRASE";
-		txt = "Private key passphrase";
+	case WPA_CTRL_REQ_EAP_PASSPHRASE:
 		config->pending_req_passphrase++;
 		break;
 	default:
@@ -1559,7 +1545,7 @@
  */
 void eap_sm_request_identity(struct eap_sm *sm)
 {
-	eap_sm_request(sm, TYPE_IDENTITY, NULL, 0);
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_IDENTITY, NULL, 0);
 }
 
 
@@ -1574,7 +1560,7 @@
  */
 void eap_sm_request_password(struct eap_sm *sm)
 {
-	eap_sm_request(sm, TYPE_PASSWORD, NULL, 0);
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSWORD, NULL, 0);
 }
 
 
@@ -1589,7 +1575,7 @@
  */
 void eap_sm_request_new_password(struct eap_sm *sm)
 {
-	eap_sm_request(sm, TYPE_NEW_PASSWORD, NULL, 0);
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_NEW_PASSWORD, NULL, 0);
 }
 
 
@@ -1604,7 +1590,7 @@
  */
 void eap_sm_request_pin(struct eap_sm *sm)
 {
-	eap_sm_request(sm, TYPE_PIN, NULL, 0);
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_PIN, NULL, 0);
 }
 
 
@@ -1620,7 +1606,7 @@
  */
 void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
 {
-	eap_sm_request(sm, TYPE_OTP, msg, msg_len);
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_OTP, msg, msg_len);
 }
 
 
@@ -1635,7 +1621,7 @@
  */
 void eap_sm_request_passphrase(struct eap_sm *sm)
 {
-	eap_sm_request(sm, TYPE_PASSPHRASE, NULL, 0);
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSPHRASE, NULL, 0);
 }
 
 
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index 2a80d4e..f35197f 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -216,10 +216,10 @@
 	/**
 	 * eap_param_needed - Notify that EAP parameter is needed
 	 * @ctx: eapol_ctx from eap_peer_sm_init() call
-	 * @field: Field name (e.g., "IDENTITY")
+	 * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY)
 	 * @txt: User readable text describing the required parameter
 	 */
-	void (*eap_param_needed)(void *ctx, const char *field,
+	void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field,
 				 const char *txt);
 
 	/**
@@ -262,6 +262,11 @@
 	 * This is only used by EAP-WSC and can be left %NULL if not available.
 	 */
 	struct wps_context *wps;
+
+	/**
+	 * cert_in_cb - Include server certificates in callback
+	 */
+	int cert_in_cb;
 };
 
 struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 182f01a..766764b 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -235,21 +235,20 @@
 
 static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
 {
-	wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old%s%s%s",
-		   id & CLEAR_PSEUDONYM ? " pseudonym" : "",
-		   id & CLEAR_REAUTH_ID ? " reauth_id" : "",
-		   id & CLEAR_EAP_ID ? " eap_id" : "");
 	if (id & CLEAR_PSEUDONYM) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym");
 		os_free(data->pseudonym);
 		data->pseudonym = NULL;
 		data->pseudonym_len = 0;
 	}
 	if (id & CLEAR_REAUTH_ID) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
 		os_free(data->reauth_id);
 		data->reauth_id = NULL;
 		data->reauth_id_len = 0;
 	}
 	if (id & CLEAR_EAP_ID) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id");
 		os_free(data->last_eap_identity);
 		data->last_eap_identity = NULL;
 		data->last_eap_identity_len = 0;
@@ -880,11 +879,11 @@
 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
 	}
 
-	/* Old reauthentication and pseudonym identities must not be used
-	 * anymore. In other words, if no new identities are received, full
-	 * authentication will be used on next reauthentication. */
-	eap_aka_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
-				 CLEAR_EAP_ID);
+	/* Old reauthentication identity must not be used anymore. In
+	 * other words, if no new identities are received, full
+	 * authentication will be used on next reauthentication (using
+	 * pseudonym identity or permanent identity). */
+	eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
 
 	if (attr->encr_data) {
 		u8 *decrypted;
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 5d3e69d..3cfb41a 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -444,8 +444,9 @@
 		return 0;
 	}
 
-	if (data->phase2_priv == NULL &&
-	    eap_fast_init_phase2_method(sm, data) < 0) {
+	if ((data->phase2_priv == NULL &&
+	     eap_fast_init_phase2_method(sm, data) < 0) ||
+	    data->phase2_method == NULL) {
 		wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize "
 			   "Phase 2 EAP method %d", *pos);
 		ret->methodState = METHOD_DONE;
@@ -542,7 +543,7 @@
 
 static struct wpabuf * eap_fast_process_eap_payload_tlv(
 	struct eap_sm *sm, struct eap_fast_data *data,
-	struct eap_method_ret *ret, const struct eap_hdr *req,
+	struct eap_method_ret *ret,
 	u8 *eap_payload_tlv, size_t eap_payload_tlv_len)
 {
 	struct eap_hdr *hdr;
@@ -1037,11 +1038,15 @@
 	} else {
 		/*
 		 * This is PAC refreshing, i.e., normal authentication that is
-		 * expected to be completed with an EAP-Success.
+		 * expected to be completed with an EAP-Success. However,
+		 * RFC 5422, Section 3.5 allows EAP-Failure to be sent even
+		 * after protected success exchange in case of EAP-Fast
+		 * provisioning, so we better use DECISION_COND_SUCC here
+		 * instead of DECISION_UNCOND_SUCC.
 		 */
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
 			   "- PAC refreshing completed successfully");
-		ret->decision = DECISION_UNCOND_SUCC;
+		ret->decision = DECISION_COND_SUCC;
 	}
 	ret->methodState = METHOD_DONE;
 	return eap_fast_tlv_pac_ack();
@@ -1184,7 +1189,7 @@
 
 	if (tlv.eap_payload_tlv) {
 		tmp = eap_fast_process_eap_payload_tlv(
-			sm, data, ret, req, tlv.eap_payload_tlv,
+			sm, data, ret, tlv.eap_payload_tlv,
 			tlv.eap_payload_tlv_len);
 		resp = wpabuf_concat(resp, tmp);
 	}
diff --git a/src/eap_peer/eap_methods.c b/src/eap_peer/eap_methods.c
index 3b0af05..937fd45 100644
--- a/src/eap_peer/eap_methods.c
+++ b/src/eap_peer/eap_methods.c
@@ -77,6 +77,8 @@
 const char * eap_get_name(int vendor, EapType type)
 {
 	struct eap_method *m;
+	if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
+		return "expanded";
 	for (m = eap_methods; m; m = m->next) {
 		if (m->vendor == vendor && m->method == type)
 			return m->name;
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 2b72084..7cb8213 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -196,7 +196,7 @@
  * @nak_type: TLV type (EAP_TLV_*)
  * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
  *
- * This funtion builds an EAP-TLV NAK message. The caller is responsible for
+ * This function builds an EAP-TLV NAK message. The caller is responsible for
  * freeing the returned buffer.
  */
 static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
@@ -285,8 +285,10 @@
 	 * in the end of the label just before ISK; is that just a typo?)
 	 */
 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
-	peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
-		     isk, sizeof(isk), imck, sizeof(imck));
+	if (peap_prfplus(data->peap_version, tk, 40,
+			 "Inner Methods Compound Keys",
+			 isk, sizeof(isk), imck, sizeof(imck)) < 0)
+		return -1;
 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
 			imck, sizeof(imck));
 
@@ -346,8 +348,8 @@
  * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
  * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
  *
- * This funtion builds an EAP-TLV Result message. The caller is responsible for
- * freeing the returned buffer.
+ * This function builds an EAP-TLV Result message. The caller is responsible
+ * for freeing the returned buffer.
  */
 static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
 					    struct eap_peap_data *data,
@@ -1247,9 +1249,12 @@
 		 * termination for this label while the one used for deriving
 		 * IPMK|CMK did not use null termination.
 		 */
-		peap_prfplus(data->peap_version, data->ipmk, 40,
-			     "Session Key Generating Function",
-			     (u8 *) "\00", 1, csk, sizeof(csk));
+		if (peap_prfplus(data->peap_version, data->ipmk, 40,
+				 "Session Key Generating Function",
+				 (u8 *) "\00", 1, csk, sizeof(csk)) < 0) {
+			os_free(key);
+			return NULL;
+		}
 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
 		os_memcpy(key, csk, EAP_TLS_KEY_LEN);
 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index e4705b7..1957c82 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -423,8 +423,7 @@
 	BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
 
 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-			     sizeof(struct eap_pwd_hdr) +
-			     BN_num_bytes(data->grp->order) +
+			     1 + BN_num_bytes(data->grp->order) +
 			     (2 * BN_num_bytes(data->grp->prime)),
 			     EAP_CODE_RESPONSE, eap_get_id(reqData));
 	if (resp == NULL)
@@ -465,6 +464,7 @@
 	u32 cs;
 	u16 grp;
 	u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+	int offset;
 
 	/*
 	 * first build up the ciphersuite which is group | random_function |
@@ -497,7 +497,8 @@
 	 * value may start with a few zeros and the previous one did not.
 	 */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->k, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+	BN_bn2bin(data->k, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server element: x, y */
@@ -509,15 +510,19 @@
 		goto fin;
 	}
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->server_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->server_scalar);
+	BN_bn2bin(data->server_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* my element: x, y */
@@ -530,15 +535,19 @@
 	}
 
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* my scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->my_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* the ciphersuite */
@@ -564,7 +573,8 @@
 
 	/* k */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->k, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+	BN_bn2bin(data->k, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* my element */
@@ -576,15 +586,19 @@
 		goto fin;
 	}
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* my scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->my_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* server element: x, y */
@@ -596,15 +610,19 @@
 		goto fin;
 	}
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->server_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->server_scalar);
+	BN_bn2bin(data->server_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* the ciphersuite */
@@ -614,7 +632,7 @@
 	H_Final(&ctx, conf);
 
 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-			     sizeof(struct eap_pwd_hdr) + SHA256_DIGEST_LENGTH,
+			     1 + SHA256_DIGEST_LENGTH,
 			     EAP_CODE_RESPONSE, eap_get_id(reqData));
 	if (resp == NULL)
 		goto fin;
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index 6677063..06fbc5b 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -266,21 +266,20 @@
 
 static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
 {
-	wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old%s%s%s",
-		   id & CLEAR_PSEUDONYM ? " pseudonym" : "",
-		   id & CLEAR_REAUTH_ID ? " reauth_id" : "",
-		   id & CLEAR_EAP_ID ? " eap_id" : "");
-	if (id & CLEAR_PSEUDONYM) {
+	if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old pseudonym");
 		os_free(data->pseudonym);
 		data->pseudonym = NULL;
 		data->pseudonym_len = 0;
 	}
-	if (id & CLEAR_REAUTH_ID) {
+	if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
 		os_free(data->reauth_id);
 		data->reauth_id = NULL;
 		data->reauth_id_len = 0;
 	}
-	if (id & CLEAR_EAP_ID) {
+	if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old eap_id");
 		os_free(data->last_eap_identity);
 		data->last_eap_identity = NULL;
 		data->last_eap_identity_len = 0;
@@ -649,11 +648,11 @@
 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
 	}
 
-	/* Old reauthentication and pseudonym identities must not be used
-	 * anymore. In other words, if no new identities are received, full
-	 * authentication will be used on next reauthentication. */
-	eap_sim_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
-				 CLEAR_EAP_ID);
+	/* Old reauthentication identity must not be used anymore. In
+	 * other words, if no new reauth identity is received, full
+	 * authentication will be used on next reauthentication (using
+	 * pseudonym identity or permanent identity). */
+	eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
 
 	if (attr->encr_data) {
 		u8 *decrypted;
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index d1567e9..2934ba4 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -112,7 +112,6 @@
 		wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
 		eap_tls_params_from_conf1(params, config);
 	}
-	params->tls_ia = data->tls_ia;
 
 	/*
 	 * Use blob data, if available. Otherwise, leave reference to external
@@ -295,9 +294,9 @@
 	os_memcpy(rnd + keys.client_random_len, keys.server_random,
 		  keys.server_random_len);
 
-	if (tls_prf(keys.master_key, keys.master_key_len,
-		    label, rnd, keys.client_random_len +
-		    keys.server_random_len, out, len))
+	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+			     label, rnd, keys.client_random_len +
+			     keys.server_random_len, out, len))
 		goto fail;
 
 	os_free(rnd);
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index e9e0998..e9a07b8 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -66,11 +66,6 @@
 	int include_tls_length;
 
 	/**
-	 * tls_ia - Whether TLS/IA is enabled for this TLS connection
-	 */
-	int tls_ia;
-
-	/**
 	 * eap - EAP state machine allocated with eap_peer_sm_init()
 	 */
 	struct eap_sm *eap;
diff --git a/src/eap_peer/eap_tnc.c b/src/eap_peer/eap_tnc.c
index 6c95f72..da288eb 100644
--- a/src/eap_peer/eap_tnc.c
+++ b/src/eap_peer/eap_tnc.c
@@ -15,7 +15,6 @@
 #include "includes.h"
 
 #include "common.h"
-#include "base64.h"
 #include "eap_i.h"
 #include "tncc.h"
 
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index e8f0f38..612dfa7 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -26,17 +26,7 @@
 #include "eap_config.h"
 
 
-/* Maximum supported TTLS version
- * 0 = RFC 5281
- * 1 = draft-funk-eap-ttls-v1-00.txt
- */
-#ifndef EAP_TTLS_VERSION
-#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */
-#endif /* EAP_TTLS_VERSION */
-
-
-#define MSCHAPV2_KEY_LEN 16
-#define MSCHAPV2_NT_RESPONSE_LEN 24
+#define EAP_TTLS_VERSION 0
 
 
 static void eap_ttls_deinit(struct eap_sm *sm, void *priv);
@@ -44,9 +34,8 @@
 
 struct eap_ttls_data {
 	struct eap_ssl_data ssl;
-	int ssl_initialized;
 
-	int ttls_version, force_ttls_version;
+	int ttls_version;
 
 	const struct eap_method *phase2_method;
 	void *phase2_priv;
@@ -91,22 +80,9 @@
 	if (data == NULL)
 		return NULL;
 	data->ttls_version = EAP_TTLS_VERSION;
-	data->force_ttls_version = -1;
 	selected = "EAP";
 	data->phase2_type = EAP_TTLS_PHASE2_EAP;
 
-#if EAP_TTLS_VERSION > 0
-	if (config && config->phase1) {
-		const char *pos = os_strstr(config->phase1, "ttlsver=");
-		if (pos) {
-			data->force_ttls_version = atoi(pos + 8);
-			data->ttls_version = data->force_ttls_version;
-			wpa_printf(MSG_DEBUG, "EAP-TTLS: Forced TTLS version "
-				   "%d", data->force_ttls_version);
-		}
-	}
-#endif /* EAP_TTLS_VERSION */
-
 	if (config && config->phase2) {
 		if (os_strstr(config->phase2, "autheap=")) {
 			selected = "EAP";
@@ -140,19 +116,11 @@
 		data->phase2_eap_type.method = EAP_TYPE_NONE;
 	}
 
-#if EAP_TTLS_VERSION > 0
-	if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) &&
-	    data->ttls_version > 0) {
-		if (data->force_ttls_version > 0) {
-			wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and "
-				   "TLS library does not support TLS/IA.",
-				   data->force_ttls_version);
-			eap_ttls_deinit(sm, data);
-			return NULL;
-		}
-		data->ttls_version = 0;
+	if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
+		eap_ttls_deinit(sm, data);
+		return NULL;
 	}
-#endif /* EAP_TTLS_VERSION */
 
 	return data;
 }
@@ -176,8 +144,7 @@
 		return;
 	eap_ttls_phase2_eap_deinit(sm, data);
 	os_free(data->phase2_eap_types);
-	if (data->ssl_initialized)
-		eap_peer_tls_ssl_deinit(sm, &data->ssl);
+	eap_peer_tls_ssl_deinit(sm, &data->ssl);
 	os_free(data->key_data);
 	wpabuf_free(data->pending_phase2_req);
 	os_free(data);
@@ -246,39 +213,6 @@
 }
 
 
-#if EAP_TTLS_VERSION > 0
-static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm,
-					    struct eap_ttls_data *data,
-					    const u8 *key, size_t key_len)
-{
-	u8 *buf;
-	size_t buf_len;
-	int ret;
-
-	if (key) {
-		buf_len = 2 + key_len;
-		buf = os_malloc(buf_len);
-		if (buf == NULL)
-			return -1;
-		WPA_PUT_BE16(buf, key_len);
-		os_memcpy(buf + 2, key, key_len);
-	} else {
-		buf = NULL;
-		buf_len = 0;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner "
-			"secret permutation", buf, buf_len);
-	ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx,
-						     data->ssl.conn,
-						     buf, buf_len);
-	os_free(buf);
-
-	return ret;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
 static int eap_ttls_v0_derive_key(struct eap_sm *sm,
 				  struct eap_ttls_data *data)
 {
@@ -298,156 +232,10 @@
 }
 
 
-#if EAP_TTLS_VERSION > 0
-static int eap_ttls_v1_derive_key(struct eap_sm *sm,
-				  struct eap_ttls_data *data)
-{
-	struct tls_keys keys;
-	u8 *rnd;
-
-	os_free(data->key_data);
-	data->key_data = NULL;
-
-	os_memset(&keys, 0, sizeof(keys));
-	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-	    keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.inner_secret == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-			   "client random, or server random to derive keying "
-			   "material");
-		return -1;
-	}
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	data->key_data = os_malloc(EAP_TLS_KEY_LEN);
-	if (rnd == NULL || data->key_data == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation");
-		os_free(rnd);
-		os_free(data->key_data);
-		data->key_data = NULL;
-		return -1;
-	}
-	os_memcpy(rnd, keys.client_random, keys.client_random_len);
-	os_memcpy(rnd + keys.client_random_len, keys.server_random,
-		  keys.server_random_len);
-
-	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-		    "ttls v1 keying material", rnd, keys.client_random_len +
-		    keys.server_random_len, data->key_data, EAP_TLS_KEY_LEN)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
-		os_free(rnd);
-		os_free(data->key_data);
-		data->key_data = NULL;
-		return -1;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random",
-		    rnd, keys.client_random_len + keys.server_random_len);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret",
-			keys.inner_secret, keys.inner_secret_len);
-
-	os_free(rnd);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
-			data->key_data, EAP_TLS_KEY_LEN);
-
-	return 0;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
 static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
 					struct eap_ttls_data *data, size_t len)
 {
-#if EAP_TTLS_VERSION > 0
-	struct tls_keys keys;
-	u8 *challenge, *rnd;
-#endif /* EAP_TTLS_VERSION */
-
-	if (data->ttls_version == 0) {
-		return eap_peer_tls_derive_key(sm, &data->ssl,
-					       "ttls challenge", len);
-	}
-
-#if EAP_TTLS_VERSION > 0
-
-	os_memset(&keys, 0, sizeof(keys));
-	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-	    keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.inner_secret == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-			   "client random, or server random to derive "
-			   "implicit challenge");
-		return NULL;
-	}
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	challenge = os_malloc(len);
-	if (rnd == NULL || challenge == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit "
-			   "challenge derivation");
-		os_free(rnd);
-		os_free(challenge);
-		return NULL;
-	}
-	os_memcpy(rnd, keys.server_random, keys.server_random_len);
-	os_memcpy(rnd + keys.server_random_len, keys.client_random,
-		  keys.client_random_len);
-
-	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-		    "inner application challenge", rnd,
-		    keys.client_random_len + keys.server_random_len,
-		    challenge, len)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit "
-			   "challenge");
-		os_free(rnd);
-		os_free(challenge);
-		return NULL;
-	}
-
-	os_free(rnd);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge",
-			challenge, len);
-
-	return challenge;
-
-#else /* EAP_TTLS_VERSION */
-
-	return NULL;
-
-#endif /* EAP_TTLS_VERSION */
-}
-
-
-static void eap_ttlsv1_phase2_eap_finish(struct eap_sm *sm,
-					 struct eap_ttls_data *data,
-					 struct eap_method_ret *ret)
-{
-#if EAP_TTLS_VERSION > 0
-	if (data->ttls_version > 0) {
-		const struct eap_method *m = data->phase2_method;
-		void *priv = data->phase2_priv;
-
-		/* TTLSv1 requires TLS/IA FinalPhaseFinished */
-		if (ret->decision == DECISION_UNCOND_SUCC)
-			ret->decision = DECISION_COND_SUCC;
-		ret->methodState = METHOD_CONT;
-
-		if (ret->decision == DECISION_COND_SUCC &&
-		    m->isKeyAvailable && m->getKey &&
-		    m->isKeyAvailable(sm, priv)) {
-			u8 *key;
-			size_t key_len;
-			key = m->getKey(sm, priv, &key_len);
-			if (key) {
-				eap_ttls_ia_permute_inner_secret(
-					sm, data, key, key_len);
-				os_free(key);
-			}
-		}
-	}
-#endif /* EAP_TTLS_VERSION */
+	return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len);
 }
 
 
@@ -494,7 +282,6 @@
 		ret->methodState = iret.methodState;
 		ret->decision = iret.decision;
 	}
-	eap_ttlsv1_phase2_eap_finish(sm, data, ret);
 
 	return 0;
 }
@@ -615,26 +402,6 @@
 }
 
 
-static void eap_ttlsv1_permute_inner(struct eap_sm *sm,
-				     struct eap_ttls_data *data)
-{
-#if EAP_TTLS_VERSION > 0
-	u8 session_key[2 * MSCHAPV2_KEY_LEN];
-
-	if (data->ttls_version == 0)
-		return;
-
-	get_asymetric_start_key(data->master_key, session_key,
-				MSCHAPV2_KEY_LEN, 0, 0);
-	get_asymetric_start_key(data->master_key,
-				session_key + MSCHAPV2_KEY_LEN,
-				MSCHAPV2_KEY_LEN, 1, 0);
-	eap_ttls_ia_permute_inner_secret(sm, data, session_key,
-					 sizeof(session_key));
-#endif /* EAP_TTLS_VERSION */
-}
-
-
 static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
 					    struct eap_ttls_data *data,
 					    struct eap_method_ret *ret,
@@ -702,8 +469,6 @@
 	}
 	data->auth_response_valid = 1;
 
-	eap_ttlsv1_permute_inner(sm, data);
-
 	pos += 24;
 	os_free(challenge);
 	AVP_PAD(buf, pos);
@@ -711,7 +476,7 @@
 	wpabuf_put(msg, pos - buf);
 	*resp = msg;
 
-	if (sm->workaround && data->ttls_version == 0) {
+	if (sm->workaround) {
 		/* At least FreeRADIUS seems to be terminating
 		 * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success
 		 * packet. */
@@ -798,17 +563,10 @@
 	wpabuf_put(msg, pos - buf);
 	*resp = msg;
 
-	if (data->ttls_version > 0) {
-		/* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-		 * so do not allow connection to be terminated yet. */
-		ret->methodState = METHOD_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	} else {
-		/* EAP-TTLS/MSCHAP does not provide tunneled success
-		 * notification, so assume that Phase2 succeeds. */
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_COND_SUCC;
-	}
+	/* EAP-TTLS/MSCHAP does not provide tunneled success
+	 * notification, so assume that Phase2 succeeds. */
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
 
 	return 0;
 }
@@ -859,17 +617,10 @@
 	wpabuf_put(msg, pos - buf);
 	*resp = msg;
 
-	if (data->ttls_version > 0) {
-		/* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-		 * so do not allow connection to be terminated yet. */
-		ret->methodState = METHOD_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	} else {
-		/* EAP-TTLS/PAP does not provide tunneled success notification,
-		 * so assume that Phase2 succeeds. */
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_COND_SUCC;
-	}
+	/* EAP-TTLS/PAP does not provide tunneled success notification,
+	 * so assume that Phase2 succeeds. */
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
 
 	return 0;
 }
@@ -942,17 +693,10 @@
 	wpabuf_put(msg, pos - buf);
 	*resp = msg;
 
-	if (data->ttls_version > 0) {
-		/* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-		 * so do not allow connection to be terminated yet. */
-		ret->methodState = METHOD_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	} else {
-		/* EAP-TTLS/CHAP does not provide tunneled success
-		 * notification, so assume that Phase2 succeeds. */
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_COND_SUCC;
-	}
+	/* EAP-TTLS/CHAP does not provide tunneled success
+	 * notification, so assume that Phase2 succeeds. */
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
 
 	return 0;
 }
@@ -1027,36 +771,6 @@
 }
 
 
-#if EAP_TTLS_VERSION > 0
-static struct wpabuf * eap_ttls_build_phase_finished(
-	struct eap_sm *sm, struct eap_ttls_data *data, int id, int final)
-{
-	struct wpabuf *req, *buf;
-
-	buf = tls_connection_ia_send_phase_finished(sm->ssl_ctx,
-						    data->ssl.conn,
-						    final);
-	if (buf == NULL)
-		return NULL;
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS,
-			    1 + wpabuf_len(buf),
-			    EAP_CODE_RESPONSE, id);
-	if (req == NULL) {
-		wpabuf_free(buf);
-		return NULL;
-	}
-
-	wpabuf_put_u8(req, data->ttls_version);
-	wpabuf_put_buf(req, buf);
-	wpabuf_free(buf);
-	eap_update_len(req);
-
-	return req;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
 struct ttls_parse_avp {
 	u8 *mschapv2;
 	u8 *eapdata;
@@ -1366,19 +1080,9 @@
 
 	wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 "
 		   "authentication succeeded");
-	if (data->ttls_version > 0) {
-		/*
-		 * EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report
-		 * success, so do not allow connection to be terminated
-		 * yet.
-		 */
-		ret->methodState = METHOD_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	} else {
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_UNCOND_SUCC;
-		data->phase2_success = 1;
-	}
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_UNCOND_SUCC;
+	data->phase2_success = 1;
 
 	/*
 	 * Reply with empty data; authentication server will reply
@@ -1493,24 +1197,6 @@
 }
 
 
-#if EAP_TTLS_VERSION > 0
-static void eap_ttls_final_phase_finished(struct eap_sm *sm,
-					  struct eap_ttls_data *data,
-					  struct eap_method_ret *ret,
-					  u8 identifier,
-					  struct wpabuf **out_data)
-{
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished received");
-	wpa_printf(MSG_INFO, "EAP-TTLS: TLS/IA authentication succeeded");
-	ret->methodState = METHOD_DONE;
-	ret->decision = DECISION_UNCOND_SUCC;
-	data->phase2_success = 1;
-	*out_data = eap_ttls_build_phase_finished(sm, data, identifier, 1);
-	eap_ttls_v1_derive_key(sm, data);
-}
-#endif /* EAP_TTLS_VERSION */
-
-
 static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
 					      struct eap_ttls_data *data,
 					      struct eap_method_ret *ret,
@@ -1534,6 +1220,21 @@
 			   "processing failed");
 		retval = -1;
 	} else {
+		struct eap_peer_config *config = eap_get_config(sm);
+		if (resp == NULL &&
+		    (config->pending_req_identity ||
+		     config->pending_req_password ||
+		     config->pending_req_otp ||
+		     config->pending_req_new_password)) {
+			/*
+			 * Use empty buffer to force implicit request
+			 * processing when EAP request is re-processed after
+			 * user input.
+			 */
+			wpabuf_free(data->pending_phase2_req);
+			data->pending_phase2_req = wpabuf_alloc(0);
+		}
+
 		retval = eap_ttls_encrypt_response(sm, data, resp, identifier,
 						   out_data);
 	}
@@ -1627,17 +1328,6 @@
 	if (retval)
 		goto done;
 
-#if EAP_TTLS_VERSION > 0
-	if (data->ttls_version > 0 &&
-	    (in_decrypted == NULL || wpabuf_len(in_decrypted) == 0) &&
-	    tls_connection_ia_final_phase_finished(sm->ssl_ctx,
-						   data->ssl.conn)) {
-		eap_ttls_final_phase_finished(sm, data, ret, identifier,
-					      out_data);
-		goto done;
-	}
-#endif /* EAP_TTLS_VERSION */
-
 continue_req:
 	data->phase2_start = 0;
 
@@ -1662,46 +1352,6 @@
 }
 
 
-static int eap_ttls_process_start(struct eap_sm *sm,
-				  struct eap_ttls_data *data, u8 flags,
-				  struct eap_method_ret *ret)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own ver=%d)",
-		   flags & EAP_TLS_VERSION_MASK, data->ttls_version);
-#if EAP_TTLS_VERSION > 0
-	if ((flags & EAP_TLS_VERSION_MASK) < data->ttls_version)
-		data->ttls_version = flags & EAP_TLS_VERSION_MASK;
-	if (data->force_ttls_version >= 0 &&
-	    data->force_ttls_version != data->ttls_version) {
-		wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to select "
-			   "forced TTLS version %d",
-			   data->force_ttls_version);
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		ret->allowNotifications = FALSE;
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: Using TTLS version %d",
-		   data->ttls_version);
-
-	if (data->ttls_version > 0)
-		data->ssl.tls_ia = 1;
-#endif /* EAP_TTLS_VERSION */
-	if (!data->ssl_initialized &&
-	    eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
-		return -1;
-	}
-	data->ssl_initialized = 1;
-
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: Start");
-
-	return 0;
-}
-
-
 static int eap_ttls_process_handshake(struct eap_sm *sm,
 				      struct eap_ttls_data *data,
 				      struct eap_method_ret *ret,
@@ -1725,8 +1375,7 @@
 			ret->methodState = METHOD_MAY_CONT;
 		}
 		data->phase2_start = 1;
-		if (data->ttls_version == 0)
-			eap_ttls_v0_derive_key(sm, data);
+		eap_ttls_v0_derive_key(sm, data);
 
 		if (*out_data == NULL || wpabuf_len(*out_data) == 0) {
 			if (eap_ttls_decrypt(sm, data, ret, identifier,
@@ -1761,7 +1410,7 @@
 				       struct eap_ttls_data *data,
 				       struct eap_method_ret *ret)
 {
-	if (data->ttls_version == 0 && ret->methodState == METHOD_DONE) {
+	if (ret->methodState == METHOD_DONE) {
 		ret->allowNotifications = FALSE;
 		if (ret->decision == DECISION_UNCOND_SUCC ||
 		    ret->decision == DECISION_COND_SUCC) {
@@ -1779,8 +1428,7 @@
 			}
 #endif /* EAP_TNC */
 		}
-	} else if (data->ttls_version == 0 &&
-		   ret->methodState == METHOD_MAY_CONT &&
+	} else if (ret->methodState == METHOD_MAY_CONT &&
 		   (ret->decision == DECISION_UNCOND_SUCC ||
 		    ret->decision == DECISION_COND_SUCC)) {
 			wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
@@ -1808,8 +1456,9 @@
 	id = eap_get_id(reqData);
 
 	if (flags & EAP_TLS_FLAGS_START) {
-		if (eap_ttls_process_start(sm, data, flags, ret) < 0)
-			return NULL;
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own "
+			   "ver=%d)", flags & EAP_TLS_VERSION_MASK,
+			   data->ttls_version);
 
 		/* RFC 5281, Ch. 9.2:
 		 * "This packet MAY contain additional information in the form
@@ -1817,13 +1466,6 @@
 		 * For now, ignore any potential extra data.
 		 */
 		left = 0;
-	} else if (!data->ssl_initialized) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: First message did not "
-			   "include Start flag");
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		ret->allowNotifications = FALSE;
-		return NULL;
 	}
 
 	resp = NULL;
diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c
index 1e169a0..acd7611 100644
--- a/src/eap_peer/ikev2.c
+++ b/src/eap_peer/ikev2.c
@@ -425,7 +425,7 @@
 	}
 
 	/* RFC 4306, Section 3.4:
-	 * The length of DH public value MUST be equal to the lenght of the
+	 * The length of DH public value MUST be equal to the length of the
 	 * prime modulus.
 	 */
 	if (kei_len - 4 != data->dh->prime_len) {
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index e1f500a..d5f8f1d 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -22,8 +22,6 @@
 
 struct eap_sm;
 
-#define EAP_MAX_METHODS 8
-
 #define EAP_TTLS_AUTH_PAP 1
 #define EAP_TTLS_AUTH_CHAP 2
 #define EAP_TTLS_AUTH_MSCHAP 4
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 3cba5aa..f48cf71 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -119,7 +119,7 @@
 
 	/* Full authenticator state machine local variables */
 
-	/* Long-term (maintained betwen packets) */
+	/* Long-term (maintained between packets) */
 	EapType currentMethod;
 	int currentId;
 	enum {
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 0f0da29..7a5beb6 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -136,6 +136,14 @@
 {
 	SM_ENTRY(EAP, INITIALIZE);
 
+	if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) {
+		/*
+		 * Need to allow internal Identity method to be used instead
+		 * of passthrough at the beginning of reauthentication.
+		 */
+		eap_server_clear_identity(sm);
+	}
+
 	sm->currentId = -1;
 	sm->eap_if.eapSuccess = FALSE;
 	sm->eap_if.eapFail = FALSE;
@@ -1028,9 +1036,12 @@
 
 	not_found:
 		/* not found - remove from the list */
-		os_memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
-			   (EAP_MAX_METHODS - i - 1) *
-			   sizeof(sm->user->methods[0]));
+		if (i + 1 < EAP_MAX_METHODS) {
+			os_memmove(&sm->user->methods[i],
+				   &sm->user->methods[i + 1],
+				   (EAP_MAX_METHODS - i - 1) *
+				   sizeof(sm->user->methods[0]));
+		}
 		sm->user->methods[EAP_MAX_METHODS - 1].vendor =
 			EAP_VENDOR_IETF;
 		sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 42cbdce..0f25ffd 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -133,14 +133,13 @@
 		return NULL;
 
 	data->eap_method = EAP_TYPE_AKA_PRIME;
-	data->network_name = os_malloc(os_strlen(network_name));
+	data->network_name = (u8 *) os_strdup(network_name);
 	if (data->network_name == NULL) {
 		os_free(data);
 		return NULL;
 	}
 
 	data->network_name_len = os_strlen(network_name);
-	os_memcpy(data->network_name, network_name, data->network_name_len);
 
 	data->state = IDENTITY;
 	eap_aka_determine_identity(sm, data, 1, 0);
diff --git a/src/eap_server/eap_server_methods.c b/src/eap_server/eap_server_methods.c
index 900a5dd..4d241a4 100644
--- a/src/eap_server/eap_server_methods.c
+++ b/src/eap_server/eap_server_methods.c
@@ -167,6 +167,8 @@
 const char * eap_server_get_name(int vendor, EapType type)
 {
 	struct eap_method *m;
+	if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
+		return "expanded";
 	for (m = eap_methods; m; m = m->next) {
 		if (m->vendor == vendor && m->method == type)
 			return m->name;
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index 64120a4..f5ee7f4 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -405,9 +405,12 @@
 		if (sm->user->password_hash) {
 			pw_hash = sm->user->password;
 		} else {
-			nt_password_hash(sm->user->password,
-					 sm->user->password_len,
-					 pw_hash_buf);
+			if (nt_password_hash(sm->user->password,
+					     sm->user->password_len,
+					     pw_hash_buf) < 0) {
+				data->state = FAILURE;
+				return;
+			}
 			pw_hash = pw_hash_buf;
 		}
 		generate_authenticator_response_pwhash(
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index 8a7d626..50e79c0 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -351,8 +351,12 @@
 	 * in the end of the label just before ISK; is that just a typo?)
 	 */
 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
-	peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
-		     isk, sizeof(isk), imck, sizeof(imck));
+	if (peap_prfplus(data->peap_version, tk, 40,
+			 "Inner Methods Compound Keys",
+			 isk, sizeof(isk), imck, sizeof(imck)) < 0) {
+		os_free(tk);
+		return -1;
+	}
 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
 			imck, sizeof(imck));
 
@@ -1060,8 +1064,6 @@
 	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
 			    in_decrypted);
 
-	hdr = wpabuf_head(in_decrypted);
-
 	if (data->peap_version == 0 && data->state != PHASE2_TLV) {
 		const struct eap_hdr *resp;
 		struct eap_hdr *nhdr;
@@ -1320,9 +1322,10 @@
 		 * termination for this label while the one used for deriving
 		 * IPMK|CMK did not use null termination.
 		 */
-		peap_prfplus(data->peap_version, data->ipmk, 40,
-			     "Session Key Generating Function",
-			     (u8 *) "\00", 1, csk, sizeof(csk));
+		if (peap_prfplus(data->peap_version, data->ipmk, 40,
+				 "Session Key Generating Function",
+				 (u8 *) "\00", 1, csk, sizeof(csk)) < 0)
+			return NULL;
 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
 		eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
 		if (eapKeyData) {
diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c
index efc7a82..fb299ae 100644
--- a/src/eap_server/eap_server_psk.c
+++ b/src/eap_server/eap_server_psk.c
@@ -125,8 +125,10 @@
 
 	os_memcpy(buf, data->id_s, data->id_s_len);
 	os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
-	if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s))
+	if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
+		os_free(buf);
 		goto fail;
+	}
 	os_free(buf);
 
 	if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk,
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index dd2557a..4c6f4d1 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -156,8 +156,8 @@
 
 	wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request");
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-			    sizeof(struct eap_pwd_hdr) +
-			    sizeof(struct eap_pwd_id) + data->id_server_len,
+			    1 + sizeof(struct eap_pwd_id) +
+			    data->id_server_len,
 			    EAP_CODE_REQUEST, id);
 	if (req == NULL) {
 		eap_pwd_state(data, FAILURE);
@@ -257,8 +257,7 @@
 	BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
 
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-			    sizeof(struct eap_pwd_hdr) +
-			    (2 * BN_num_bytes(data->grp->prime)) +
+			    1 + (2 * BN_num_bytes(data->grp->prime)) +
 			    BN_num_bytes(data->grp->order),
 			    EAP_CODE_REQUEST, id);
 	if (req == NULL)
@@ -289,6 +288,7 @@
 	HMAC_CTX ctx;
 	u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
 	u16 grp;
+	int offset;
 
 	wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
 
@@ -313,7 +313,8 @@
 	 * First is k
 	 */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->k, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+	BN_bn2bin(data->k, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server element: x, y */
@@ -326,15 +327,19 @@
 	}
 
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->my_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* peer element: x, y */
@@ -347,15 +352,19 @@
 	}
 
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* peer scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->peer_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->peer_scalar);
+	BN_bn2bin(data->peer_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* ciphersuite */
@@ -375,7 +384,7 @@
 	os_memcpy(data->my_confirm, conf, SHA256_DIGEST_LENGTH);
 
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-			    sizeof(struct eap_pwd_hdr) + SHA256_DIGEST_LENGTH,
+			    1 + SHA256_DIGEST_LENGTH,
 			    EAP_CODE_REQUEST, id);
 	if (req == NULL)
 		goto fin;
@@ -624,6 +633,7 @@
 	u32 cs;
 	u16 grp;
 	u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+	int offset;
 
 	/* build up the ciphersuite: group | random_function | prf */
 	grp = htons(data->group_num);
@@ -649,7 +659,8 @@
 
 	/* k */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->k, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+	BN_bn2bin(data->k, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* peer element: x, y */
@@ -661,15 +672,19 @@
 		goto fin;
 	}
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* peer scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->peer_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->peer_scalar);
+	BN_bn2bin(data->peer_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* server element: x, y */
@@ -682,15 +697,19 @@
 	}
 
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->my_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* ciphersuite */
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index e149ee3..0bb9d14 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -94,9 +94,9 @@
 	os_memcpy(rnd + keys.client_random_len, keys.server_random,
 		  keys.server_random_len);
 
-	if (tls_prf(keys.master_key, keys.master_key_len,
-		    label, rnd, keys.client_random_len +
-		    keys.server_random_len, out, len))
+	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+			     label, rnd, keys.client_random_len +
+			     keys.server_random_len, out, len))
 		goto fail;
 
 	os_free(rnd);
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 702c50c..398d0f1 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -24,16 +24,7 @@
 #include "eap_common/eap_ttls.h"
 
 
-/* Maximum supported TTLS version
- * 0 = RFC 5281
- * 1 = draft-funk-eap-ttls-v1-00.txt
- */
-#ifndef EAP_TTLS_VERSION
-#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */
-#endif /* EAP_TTLS_VERSION */
-
-
-#define MSCHAPV2_KEY_LEN 16
+#define EAP_TTLS_VERSION 0
 
 
 static void eap_ttls_reset(struct eap_sm *sm, void *priv);
@@ -43,17 +34,15 @@
 	struct eap_ssl_data ssl;
 	enum {
 		START, PHASE1, PHASE2_START, PHASE2_METHOD,
-		PHASE2_MSCHAPV2_RESP, PHASE_FINISHED, SUCCESS, FAILURE
+		PHASE2_MSCHAPV2_RESP, SUCCESS, FAILURE
 	} state;
 
 	int ttls_version;
-	int force_version;
 	const struct eap_method *phase2_method;
 	void *phase2_priv;
 	int mschapv2_resp_ok;
 	u8 mschapv2_auth_response[20];
 	u8 mschapv2_ident;
-	int tls_ia_configured;
 	struct wpabuf *pending_phase2_eap_resp;
 	int tnc_started;
 };
@@ -72,8 +61,6 @@
 		return "PHASE2_METHOD";
 	case PHASE2_MSCHAPV2_RESP:
 		return "PHASE2_MSCHAPV2_RESP";
-	case PHASE_FINISHED:
-		return "PHASE_FINISHED";
 	case SUCCESS:
 		return "SUCCESS";
 	case FAILURE:
@@ -111,7 +98,8 @@
 	}
 
 	avp->avp_code = host_to_be32(avp_code);
-	avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len));
+	avp->avp_length = host_to_be32(((u32) flags << 24) |
+				       ((u32) (hdrlen + len)));
 
 	return avphdr + hdrlen;
 }
@@ -320,54 +308,8 @@
 static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
 					struct eap_ttls_data *data, size_t len)
 {
-	struct tls_keys keys;
-	u8 *challenge, *rnd;
-
-	if (data->ttls_version == 0) {
-		return eap_server_tls_derive_key(sm, &data->ssl,
-						 "ttls challenge", len);
-	}
-
-	os_memset(&keys, 0, sizeof(keys));
-	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-	    keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.inner_secret == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-			   "client random, or server random to derive "
-			   "implicit challenge");
-		return NULL;
-	}
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	challenge = os_malloc(len);
-	if (rnd == NULL || challenge == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit "
-			   "challenge derivation");
-		os_free(rnd);
-		os_free(challenge);
-		return NULL;
-	}
-	os_memcpy(rnd, keys.server_random, keys.server_random_len);
-	os_memcpy(rnd + keys.server_random_len, keys.client_random,
-		  keys.client_random_len);
-
-	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-		    "inner application challenge", rnd,
-		    keys.client_random_len + keys.server_random_len,
-		    challenge, len)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit "
-			   "challenge");
-		os_free(rnd);
-		os_free(challenge);
-		return NULL;
-	}
-
-	os_free(rnd);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge",
-			challenge, len);
-
-	return challenge;
+	return eap_server_tls_derive_key(sm, &data->ssl, "ttls challenge",
+					 len);
 }
 
 
@@ -379,27 +321,8 @@
 	if (data == NULL)
 		return NULL;
 	data->ttls_version = EAP_TTLS_VERSION;
-	data->force_version = -1;
-	if (sm->user && sm->user->force_version >= 0) {
-		data->force_version = sm->user->force_version;
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: forcing version %d",
-			   data->force_version);
-		data->ttls_version = data->force_version;
-	}
 	data->state = START;
 
-	if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) &&
-	    data->ttls_version > 0) {
-		if (data->force_version > 0) {
-			wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and "
-				   "TLS library does not support TLS/IA.",
-				   data->force_version);
-			eap_ttls_reset(sm, data);
-			return NULL;
-		}
-		data->ttls_version = 0;
-	}
-
 	if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
 		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
 		eap_ttls_reset(sm, data);
@@ -516,14 +439,6 @@
 }
 
 
-static struct wpabuf * eap_ttls_build_phase_finished(
-	struct eap_sm *sm, struct eap_ttls_data *data, int final)
-{
-	return tls_connection_ia_send_phase_finished(sm->ssl_ctx,
-						     data->ssl.conn, final);
-}
-
-
 static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id)
 {
 	struct eap_ttls_data *data = priv;
@@ -559,11 +474,6 @@
 		data->ssl.tls_out_pos = 0;
 		data->ssl.tls_out = eap_ttls_build_phase2_mschapv2(sm, data);
 		break;
-	case PHASE_FINISHED:
-		wpabuf_free(data->ssl.tls_out);
-		data->ssl.tls_out_pos = 0;
-		data->ssl.tls_out = eap_ttls_build_phase_finished(sm, data, 1);
-		break;
 	default:
 		wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
 			   __func__, data->state);
@@ -591,37 +501,6 @@
 }
 
 
-static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm,
-					    struct eap_ttls_data *data,
-					    const u8 *key, size_t key_len)
-{
-	u8 *buf;
-	size_t buf_len;
-	int ret;
-
-	if (key) {
-		buf_len = 2 + key_len;
-		buf = os_malloc(buf_len);
-		if (buf == NULL)
-			return -1;
-		WPA_PUT_BE16(buf, key_len);
-		os_memcpy(buf + 2, key, key_len);
-	} else {
-		buf = NULL;
-		buf_len = 0;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner "
-			"secret permutation", buf, buf_len);
-	ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx,
-						     data->ssl.conn,
-						     buf, buf_len);
-	os_free(buf);
-
-	return ret;
-}
-
-
 static void eap_ttls_process_phase2_pap(struct eap_sm *sm,
 					struct eap_ttls_data *data,
 					const u8 *user_password,
@@ -644,8 +523,7 @@
 	}
 
 	wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password");
-	eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
-		       SUCCESS);
+	eap_ttls_state(data, SUCCESS);
 }
 
 
@@ -701,8 +579,7 @@
 
 	if (os_memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password");
-		eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
-			       SUCCESS);
+		eap_ttls_state(data, SUCCESS);
 	} else {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password");
 		eap_ttls_state(data, FAILURE);
@@ -762,8 +639,7 @@
 
 	if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response");
-		eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
-			       SUCCESS);
+		eap_ttls_state(data, SUCCESS);
 	} else {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response");
 		wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received",
@@ -863,30 +739,6 @@
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct "
 			   "NT-Response");
 		data->mschapv2_resp_ok = 1;
-		if (data->ttls_version > 0) {
-			const u8 *pw_hash;
-			u8 pw_hash_buf[16], pw_hash_hash[16], master_key[16];
-			u8 session_key[2 * MSCHAPV2_KEY_LEN];
-
-			if (sm->user->password_hash)
-				pw_hash = sm->user->password;
-			else {
-				nt_password_hash(sm->user->password,
-						 sm->user->password_len,
-						 pw_hash_buf);
-				pw_hash = pw_hash_buf;
-			}
-			hash_nt_password_hash(pw_hash, pw_hash_hash);
-			get_master_key(pw_hash_hash, nt_response, master_key);
-			get_asymetric_start_key(master_key, session_key,
-						MSCHAPV2_KEY_LEN, 0, 0);
-			get_asymetric_start_key(master_key,
-						session_key + MSCHAPV2_KEY_LEN,
-						MSCHAPV2_KEY_LEN, 1, 0);
-			eap_ttls_ia_permute_inner_secret(sm, data,
-							 session_key,
-							 sizeof(session_key));
-		}
 
 		if (sm->user->password_hash) {
 			generate_authenticator_response_pwhash(
@@ -1030,17 +882,7 @@
 		}
 		break;
 	case PHASE2_METHOD:
-		if (data->ttls_version > 0) {
-			if (m->getKey) {
-				u8 *key;
-				size_t key_len;
-				key = m->getKey(sm, priv, &key_len);
-				eap_ttls_ia_permute_inner_secret(sm, data,
-								 key, key_len);
-			}
-			eap_ttls_state(data, PHASE_FINISHED);
-		} else
-			eap_ttls_state(data, SUCCESS);
+		eap_ttls_state(data, SUCCESS);
 		break;
 	case FAILURE:
 		break;
@@ -1130,23 +972,6 @@
 		return;
 	}
 
-	if (data->state == PHASE_FINISHED) {
-		if (wpabuf_len(in_decrypted) == 0 &&
-		    tls_connection_ia_final_phase_finished(sm->ssl_ctx,
-							   data->ssl.conn)) {
-			wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished "
-				   "received");
-			eap_ttls_state(data, SUCCESS);
-		} else {
-			wpa_printf(MSG_INFO, "EAP-TTLS: Did not receive valid "
-				   "FinalPhaseFinished");
-			eap_ttls_state(data, FAILURE);
-		}
-
-		wpabuf_free(in_decrypted);
-		return;
-	}
-
 	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP",
 			    in_decrypted);
 
@@ -1245,15 +1070,6 @@
 		data->ttls_version = peer_version;
 	}
 
-	if (data->ttls_version > 0 && !data->tls_ia_configured) {
-		if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) {
-			wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable "
-				   "TLS/IA");
-			return -1;
-		}
-		data->tls_ia_configured = 1;
-	}
-
 	return 0;
 }
 
@@ -1270,7 +1086,6 @@
 		break;
 	case PHASE2_START:
 	case PHASE2_METHOD:
-	case PHASE_FINISHED:
 		eap_ttls_process_phase2(sm, data, data->ssl.tls_in);
 		eap_ttls_start_tnc(sm, data);
 		break;
@@ -1279,8 +1094,7 @@
 		    0) {
 			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
 				   "acknowledged response");
-			eap_ttls_state(data, data->ttls_version > 0 ?
-				       PHASE_FINISHED : SUCCESS);
+			eap_ttls_state(data, SUCCESS);
 		} else if (!data->mschapv2_resp_ok) {
 			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
 				   "acknowledged error");
@@ -1321,54 +1135,6 @@
 }
 
 
-static u8 * eap_ttls_v1_derive_key(struct eap_sm *sm,
-				   struct eap_ttls_data *data)
-{
-	struct tls_keys keys;
-	u8 *rnd, *key;
-
-	os_memset(&keys, 0, sizeof(keys));
-	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-	    keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.inner_secret == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-			   "client random, or server random to derive keying "
-			   "material");
-		return NULL;
-	}
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	key = os_malloc(EAP_TLS_KEY_LEN);
-	if (rnd == NULL || key == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation");
-		os_free(rnd);
-		os_free(key);
-		return NULL;
-	}
-	os_memcpy(rnd, keys.client_random, keys.client_random_len);
-	os_memcpy(rnd + keys.client_random_len, keys.server_random,
-		  keys.server_random_len);
-
-	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-		    "ttls v1 keying material", rnd, keys.client_random_len +
-		    keys.server_random_len, key, EAP_TLS_KEY_LEN)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
-		os_free(rnd);
-		os_free(key);
-		return NULL;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random",
-		    rnd, keys.client_random_len + keys.server_random_len);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret",
-			keys.inner_secret, keys.inner_secret_len);
-
-	os_free(rnd);
-
-	return key;
-}
-
-
 static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
 {
 	struct eap_ttls_data *data = priv;
@@ -1377,14 +1143,9 @@
 	if (data->state != SUCCESS)
 		return NULL;
 
-	if (data->ttls_version == 0) {
-		eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
-						       "ttls keying material",
-						       EAP_TLS_KEY_LEN);
-	} else {
-		eapKeyData = eap_ttls_v1_derive_key(sm, data);
-	}
-
+	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+					       "ttls keying material",
+					       EAP_TLS_KEY_LEN);
 	if (eapKeyData) {
 		*len = EAP_TLS_KEY_LEN;
 		wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
diff --git a/src/eap_server/ikev2.c b/src/eap_server/ikev2.c
index 9624d53..f5bbb14 100644
--- a/src/eap_server/ikev2.c
+++ b/src/eap_server/ikev2.c
@@ -404,7 +404,7 @@
 	}
 
 	/* RFC 4306, Section 3.4:
-	 * The length of DH public value MUST be equal to the lenght of the
+	 * The length of DH public value MUST be equal to the length of the
 	 * prime modulus.
 	 */
 	if (ker_len - 4 != data->dh->prime_len) {
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index 4aa71ad..e600954 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -1017,7 +1017,7 @@
 
 int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
 {
-	if (sm == NULL || ctx != sm->eap)
+	if (sm == NULL || ctx == NULL || ctx != sm->eap)
 		return -1;
 
 	eap_sm_pending_cb(sm->eap);
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index bb6cff6..ffc6619 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -561,7 +561,7 @@
 		 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
 		 * and SUCCESS based on eapFail and eapSuccess, respectively.
 		 * However, IEEE Std 802.1X-2004 is also specifying that
-		 * eapNoResp should be set in conjuction with eapSuccess and
+		 * eapNoResp should be set in conjunction with eapSuccess and
 		 * eapFail which would mean that more than one of the
 		 * transitions here would be activated at the same time.
 		 * Skipping RESPONSE and/or RECEIVE states in these cases can
@@ -1813,7 +1813,7 @@
 
 
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-static void eapol_sm_eap_param_needed(void *ctx, const char *field,
+static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
 				      const char *txt)
 {
 	struct eapol_sm *sm = ctx;
@@ -1883,6 +1883,7 @@
 	conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
 	conf.pkcs11_module_path = ctx->pkcs11_module_path;
 	conf.wps = ctx->wps;
+	conf.cert_in_cb = ctx->cert_in_cb;
 
 	sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
 	if (sm->eap == NULL) {
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 3ea7e79..bcb00b5 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -208,10 +208,10 @@
 	/**
 	 * eap_param_needed - Notify that EAP parameter is needed
 	 * @ctx: Callback context (ctx)
-	 * @field: Field name (e.g., "IDENTITY")
+	 * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY)
 	 * @txt: User readable text describing the required parameter
 	 */
-	void (*eap_param_needed)(void *ctx, const char *field,
+	void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field,
 				 const char *txt);
 
 	/**
@@ -231,6 +231,11 @@
 	 */
 	void (*cert_cb)(void *ctx, int depth, const char *subject,
 			const char *cert_hash, const struct wpabuf *cert);
+
+	/**
+	 * cert_in_cb - Include server certificates in callback
+	 */
+	int cert_in_cb;
 };
 
 
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
old mode 100644
new mode 100755
index bef3926..8c768f6
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -17,6 +17,9 @@
 #include "common.h"
 #include "eloop.h"
 #include "common/ieee802_11_defs.h"
+#ifdef ANDROID_P2P
+#include "common/wpa_ctrl.h"
+#endif
 #include "common/ieee802_11_common.h"
 #include "wps/wps_i.h"
 #include "p2p_i.h"
@@ -106,12 +109,42 @@
 		return "INVITE";
 	case P2P_INVITE_LISTEN:
 		return "INVITE_LISTEN";
+	case P2P_SEARCH_WHEN_READY:
+		return "SEARCH_WHEN_READY";
 	default:
 		return "?";
 	}
 }
 
 
+u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
+{
+	struct p2p_device *dev = NULL;
+
+	if (!addr || !p2p)
+		return 0;
+
+	dev = p2p_get_device(p2p, addr);
+	if (dev)
+		return dev->wps_prov_info;
+	else
+		return 0;
+}
+
+
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr)
+{
+	struct p2p_device *dev = NULL;
+
+	if (!iface_addr || !p2p)
+		return;
+
+	dev = p2p_get_device_interface(p2p, iface_addr);
+	if (dev)
+		dev->wps_prov_info = 0;
+}
+
+
 void p2p_set_state(struct p2p_data *p2p, int new_state)
 {
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s",
@@ -144,6 +177,8 @@
 	struct p2p_go_neg_results res;
 	p2p_clear_timeout(p2p);
 	p2p_set_state(p2p, P2P_IDLE);
+	if (p2p->go_neg_peer)
+		p2p->go_neg_peer->wps_method = WPS_NOT_READY;
 	p2p->go_neg_peer = NULL;
 
 	os_memset(&res, 0, sizeof(res));
@@ -219,6 +254,12 @@
 	p2p->pending_listen_usec = (timeout % 1000) * 1000;
 
 	if (p2p->p2p_scan_running) {
+		if (p2p->start_after_scan == P2P_AFTER_SCAN_NOTHING) {
+			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+				"P2P: p2p_scan running - connect is already "
+				"pending - skip listen");
+			return 0;
+		}
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: p2p_scan running - delay start of listen state");
 		p2p->start_after_scan = P2P_AFTER_SCAN_LISTEN;
@@ -363,7 +404,7 @@
 	 * group, the information will be restored in the loop following this.
 	 */
 	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
-		if (os_memcpy(dev->member_in_go_iface, go_interface_addr,
+		if (os_memcmp(dev->member_in_go_iface, go_interface_addr,
 			      ETH_ALEN) == 0) {
 			os_memset(dev->member_in_go_iface, 0, ETH_ALEN);
 			os_memset(dev->member_in_go_dev, 0, ETH_ALEN);
@@ -372,6 +413,9 @@
 
 	for (c = 0; c < info.num_clients; c++) {
 		struct p2p_client_info *cli = &info.client[c];
+		if (os_memcmp(cli->p2p_device_addr, p2p->cfg->dev_addr,
+			      ETH_ALEN) == 0)
+			continue; /* ignore our own entry */
 		dev = p2p_get_device(p2p, cli->p2p_device_addr);
 		if (dev) {
 			/*
@@ -574,11 +618,6 @@
 			freq, msg.ds_params ? *msg.ds_params : -1);
 	}
 	dev->listen_freq = freq;
-#ifdef ANDROID_BRCM_P2P_PATCH	
-	if(msg.group_info)
-		dev->go_state = REMOTE_GO;
-#endif
-
 	if (msg.group_info)
 		dev->oper_freq = freq;
 	dev->info.level = level;
@@ -631,9 +670,10 @@
 	int i;
 
 	if (p2p->go_neg_peer == dev) {
-#ifdef ANDROID_BRCM_P2P_PATCH
+		/*
+		 * If GO Negotiation is in progress, report that it has failed.
+		 */
 		p2p_go_neg_failed(p2p, dev, -1);
-#endif
 		p2p->go_neg_peer = NULL;
 	}
 	if (p2p->invite_peer == dev)
@@ -787,19 +827,18 @@
 	enum p2p_after_scan op;
 
 	if (p2p->after_scan_tx) {
-		int ret;
 		/* TODO: schedule p2p_run_after_scan to be called from TX
 		 * status callback(?) */
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send pending "
 			"Action frame at p2p_scan completion");
-		ret = p2p->cfg->send_action(p2p->cfg->cb_ctx,
-					    p2p->after_scan_tx->freq,
-					    p2p->after_scan_tx->dst,
-					    p2p->after_scan_tx->src,
-					    p2p->after_scan_tx->bssid,
-					    (u8 *) (p2p->after_scan_tx + 1),
-					    p2p->after_scan_tx->len,
-					    p2p->after_scan_tx->wait_time);
+		p2p->cfg->send_action(p2p->cfg->cb_ctx,
+				      p2p->after_scan_tx->freq,
+				      p2p->after_scan_tx->dst,
+				      p2p->after_scan_tx->src,
+				      p2p->after_scan_tx->bssid,
+				      (u8 *) (p2p->after_scan_tx + 1),
+				      p2p->after_scan_tx->len,
+				      p2p->after_scan_tx->wait_time);
 		os_free(p2p->after_scan_tx);
 		p2p->after_scan_tx = NULL;
 		return 1;
@@ -888,6 +927,7 @@
 	p2p_device_clear_reported(p2p);
 	p2p_set_state(p2p, P2P_SEARCH);
 	eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+	p2p->last_p2p_find_timeout = timeout;
 	if (timeout)
 		eloop_register_timeout(timeout, 0, p2p_find_timeout,
 				       p2p, NULL);
@@ -913,21 +953,47 @@
 		eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
 		eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
 				       p2p, NULL);
+	} else if (res == 1) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
+			"p2p_scan at this point - will try again after "
+			"previous scan completes");
+		res = 0;
+		p2p_set_state(p2p, P2P_SEARCH_WHEN_READY);
+		eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
 	} else {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start "
 			"p2p_scan");
+		p2p_set_state(p2p, P2P_IDLE);
+		eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
 	}
 
 	return res;
 }
 
 
+int p2p_other_scan_completed(struct p2p_data *p2p)
+{
+	if (p2p->state != P2P_SEARCH_WHEN_READY)
+		return 0;
+	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting pending P2P find "
+		"now that previous scan was completed");
+	if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
+		     p2p->num_req_dev_types, p2p->req_dev_types) < 0)
+		return 0;
+	return 1;
+}
+
+
 void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
 {
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find");
 	eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
 	p2p_clear_timeout(p2p);
 	p2p_set_state(p2p, P2P_IDLE);
+#ifdef ANDROID_P2P
+	wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED);
+#endif
+
 	p2p_free_req_dev_types(p2p);
 	p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
 	p2p->go_neg_peer = NULL;
@@ -938,6 +1004,16 @@
 			"since we are on correct channel for response");
 		return;
 	}
+	if (p2p->drv_in_listen) {
+		/*
+		 * The driver may not deliver callback to p2p_listen_end()
+		 * when the operation gets canceled, so clear the internal
+		 * variable that is tracking driver state.
+		 */
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Clear "
+			"drv_in_listen (%d)", p2p->drv_in_listen);
+		p2p->drv_in_listen = 0;
+	}
 	p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
 }
 
@@ -1027,6 +1103,26 @@
 }
 
 
+static void p2p_set_dev_persistent(struct p2p_device *dev,
+				   int persistent_group)
+{
+	switch (persistent_group) {
+	case 0:
+		dev->flags &= ~(P2P_DEV_PREFER_PERSISTENT_GROUP |
+				P2P_DEV_PREFER_PERSISTENT_RECONN);
+		break;
+	case 1:
+		dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
+		dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_RECONN;
+		break;
+	case 2:
+		dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP |
+			P2P_DEV_PREFER_PERSISTENT_RECONN;
+		break;
+	}
+}
+
+
 int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
 		enum p2p_wps_method wps_method,
 		int go_intent, const u8 *own_interface_addr,
@@ -1044,6 +1140,7 @@
 	if (p2p_prepare_channel(p2p, force_freq) < 0)
 		return -1;
 
+	p2p->ssid_set = 0;
 	dev = p2p_get_device(p2p, peer_addr);
 	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1083,10 +1180,7 @@
 	dev->connect_reqs = 0;
 	dev->go_neg_req_sent = 0;
 	dev->go_state = UNKNOWN_GO;
-	if (persistent_group)
-		dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
-	else
-		dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP;
+	p2p_set_dev_persistent(dev, persistent_group);
 	p2p->go_intent = go_intent;
 	os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
 
@@ -1156,10 +1250,7 @@
 	dev->flags &= ~P2P_DEV_USER_REJECTED;
 	dev->go_neg_req_sent = 0;
 	dev->go_state = UNKNOWN_GO;
-	if (persistent_group)
-		dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
-	else
-		dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP;
+	p2p_set_dev_persistent(dev, persistent_group);
 	p2p->go_intent = go_intent;
 	os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
 
@@ -1270,8 +1361,12 @@
 	os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
 	os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
 	res.wps_method = peer->wps_method;
-	if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
-		res.persistent_group = 1;
+	if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
+		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+			res.persistent_group = 2;
+		else
+			res.persistent_group = 1;
+	}
 
 	if (go) {
 		/* Setup AP mode for WPS provisioning */
@@ -1311,6 +1406,7 @@
 	res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout;
 
 	p2p_clear_timeout(p2p);
+	p2p->ssid_set = 0;
 	peer->go_neg_req_sent = 0;
 	peer->wps_method = WPS_NOT_READY;
 
@@ -1367,9 +1463,9 @@
 }
 
 
-void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da, const u8 *sa,
-			  const u8 *bssid, const u8 *data, size_t len,
-			  int freq)
+static void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da,
+				 const u8 *sa, const u8 *bssid, const u8 *data,
+				 size_t len, int freq)
 {
 	if (len < 1)
 		return;
@@ -1514,6 +1610,7 @@
 	if (dev) {
 		if (dev->country[0] == 0 && msg.listen_channel)
 			os_memcpy(dev->country, msg.listen_channel, 3);
+		os_get_time(&dev->last_seen);
 		p2p_parse_free(&msg);
 		return; /* already known */
 	}
@@ -1653,13 +1750,47 @@
 }
 
 
-static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
+static int is_11b(u8 rate)
+{
+	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
+}
+
+
+static int supp_rates_11b_only(struct ieee802_11_elems *elems)
+{
+	int num_11b = 0, num_others = 0;
+	int i;
+
+	if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
+		return 0;
+
+	for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
+		if (is_11b(elems->supp_rates[i]))
+			num_11b++;
+		else
+			num_others++;
+	}
+
+	for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
+	     i++) {
+		if (is_11b(elems->ext_supp_rates[i]))
+			num_11b++;
+		else
+			num_others++;
+	}
+
+	return num_11b > 0 && num_others == 0;
+}
+
+
+static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
+			    const u8 *dst, const u8 *bssid, const u8 *ie,
 			    size_t ie_len)
 {
 	struct ieee802_11_elems elems;
 	struct wpabuf *buf;
 	struct ieee80211_mgmt *resp;
-	struct wpabuf *wps;
+	struct p2p_message msg;
 	struct wpabuf *ies;
 
 	if (!p2p->in_listen || !p2p->drv_in_listen) {
@@ -1678,6 +1809,18 @@
 		return;
 	}
 
+	if (dst && !is_broadcast_ether_addr(dst) &&
+	    os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
+		/* Not sent to the broadcast address or our P2P Device Address
+		 */
+		return;
+	}
+
+	if (bssid && !is_broadcast_ether_addr(bssid)) {
+		/* Not sent to the Wildcard BSSID */
+		return;
+	}
+
 	if (elems.ssid == NULL || elems.ssid_len != P2P_WILDCARD_SSID_LEN ||
 	    os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) !=
 	    0) {
@@ -1685,14 +1828,32 @@
 		return;
 	}
 
-	/* Check Requested Device Type match */
-	wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
-	if (wps && !p2p_match_dev_type(p2p, wps)) {
-		wpabuf_free(wps);
-		/* No match with Requested Device Type */
+	if (supp_rates_11b_only(&elems)) {
+		/* Indicates support for 11b rates only */
 		return;
 	}
-	wpabuf_free(wps);
+
+	os_memset(&msg, 0, sizeof(msg));
+	if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
+		/* Could not parse P2P attributes */
+		return;
+	}
+
+	if (msg.device_id &&
+	    os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN != 0)) {
+		/* Device ID did not match */
+		p2p_parse_free(&msg);
+		return;
+	}
+
+	/* Check Requested Device Type match */
+	if (msg.wps_attributes &&
+	    !p2p_match_dev_type(p2p, msg.wps_attributes)) {
+		/* No match with Requested Device Type */
+		p2p_parse_free(&msg);
+		return;
+	}
+	p2p_parse_free(&msg);
 
 	if (!p2p->cfg->send_probe_resp)
 		return; /* Response generated elsewhere */
@@ -1759,12 +1920,12 @@
 }
 
 
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
-		     size_t ie_len)
+int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+		     const u8 *bssid, const u8 *ie, size_t ie_len)
 {
 	p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
 
-	p2p_reply_probe(p2p, addr, ie, ie_len);
+	p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
 
 	if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
 	    p2p->go_neg_peer &&
@@ -2221,11 +2382,11 @@
 		} else if (dev->req_config_methods &&
 			   !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
-				"pending Provisioning Discovery Request to "
+				"pending Provision Discovery Request to "
 				MACSTR " (config methods 0x%x)",
 				MAC2STR(dev->info.p2p_device_addr),
 				dev->req_config_methods);
-			if (p2p_send_prov_disc_req(p2p, dev, 0) == 0)
+			if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
 				return;
 		}
 	}
@@ -2267,7 +2428,7 @@
  * p2p_retry_pd - Retry any pending provision disc requests in IDLE state
  * @p2p: P2P module context from p2p_init()
  */
-void p2p_retry_pd(struct p2p_data *p2p)
+static void p2p_retry_pd(struct p2p_data *p2p)
 {
 	struct p2p_device *dev;
 
@@ -2290,11 +2451,11 @@
 			continue;
 
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
-			"pending Provisioning Discovery Request to "
+			"pending Provision Discovery Request to "
 			MACSTR " (config methods 0x%x)",
 			MAC2STR(dev->info.p2p_device_addr),
 			dev->req_config_methods);
-		p2p_send_prov_disc_req(p2p, dev, 0);
+		p2p_send_prov_disc_req(p2p, dev, 0, 0);
 		return;
 	}
 }
@@ -2395,6 +2556,12 @@
 }
 
 
+size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
+{
+	return 100;
+}
+
+
 int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end)
 {
 	return p2p_attr_text(p2p_ie, buf, end);
@@ -2674,15 +2841,7 @@
 	 * state once per second to give other uses a chance to use the radio.
 	 */
 	p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
-#ifdef ANDROID_BRCM_P2P_PATCH
-	/*
-	 * We need to be back in Listen state soon enough so that we don't miss
-	 * the GO Nego req from the peer.
-	*/
-	p2p_set_timeout(p2p, 0, 0);
-#else
-	p2p_set_timeout(p2p, 1, 0);
-#endif
+	p2p_set_timeout(p2p, 0, 500000);
 }
 
 
@@ -2862,6 +3021,8 @@
 	case P2P_INVITE_LISTEN:
 		p2p_timeout_invite_listen(p2p);
 		break;
+	case P2P_SEARCH_WHEN_READY:
+		break;
 	}
 }
 
@@ -2884,13 +3045,11 @@
 }
 
 
-static const char * p2p_wps_method_text(enum p2p_wps_method method)
+const char * p2p_wps_method_text(enum p2p_wps_method method)
 {
 	switch (method) {
 	case WPS_NOT_READY:
 		return "not-ready";
-	case WPS_PIN_LABEL:
-		return "Label";
 	case WPS_PIN_DISPLAY:
 		return "Display";
 	case WPS_PIN_KEYPAD:
@@ -2918,14 +3077,10 @@
 }
 
 
-int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
-		      char *buf, size_t buflen)
+const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p,
+					       const u8 *addr, int next)
 {
 	struct p2p_device *dev;
-	int res;
-	char *pos, *end;
-	struct os_time now;
-	char devtype[WPS_DEV_TYPE_BUFSIZE];
 
 	if (addr)
 		dev = p2p_get_device(p2p, addr);
@@ -2939,35 +3094,37 @@
 	}
 
 	if (dev == NULL)
+		return NULL;
+
+	return &dev->info;
+}
+
+
+int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
+			  char *buf, size_t buflen)
+{
+	struct p2p_device *dev;
+	int res;
+	char *pos, *end;
+	struct os_time now;
+
+	if (info == NULL)
 		return -1;
 
+	dev = (struct p2p_device *) (((u8 *) info) -
+				     offsetof(struct p2p_device, info));
+
 	pos = buf;
 	end = buf + buflen;
 
-	res = os_snprintf(pos, end - pos, MACSTR "\n",
-			  MAC2STR(dev->info.p2p_device_addr));
-	if (res < 0 || res >= end - pos)
-		return pos - buf;
-	pos += res;
-
 	os_get_time(&now);
 	res = os_snprintf(pos, end - pos,
 			  "age=%d\n"
 			  "listen_freq=%d\n"
-			  "level=%d\n"
 			  "wps_method=%s\n"
 			  "interface_addr=" MACSTR "\n"
 			  "member_in_go_dev=" MACSTR "\n"
 			  "member_in_go_iface=" MACSTR "\n"
-			  "pri_dev_type=%s\n"
-			  "device_name=%s\n"
-			  "manufacturer=%s\n"
-			  "model_name=%s\n"
-			  "model_number=%s\n"
-			  "serial_number=%s\n"
-			  "config_methods=0x%x\n"
-			  "dev_capab=0x%x\n"
-			  "group_capab=0x%x\n"
 			  "go_neg_req_sent=%d\n"
 			  "go_state=%s\n"
 			  "dialog_token=%u\n"
@@ -2981,21 +3138,10 @@
 			  "invitation_reqs=%u\n",
 			  (int) (now.sec - dev->last_seen.sec),
 			  dev->listen_freq,
-			  dev->info.level,
 			  p2p_wps_method_text(dev->wps_method),
 			  MAC2STR(dev->interface_addr),
 			  MAC2STR(dev->member_in_go_dev),
 			  MAC2STR(dev->member_in_go_iface),
-			  wps_dev_type_bin2str(dev->info.pri_dev_type,
-					       devtype, sizeof(devtype)),
-			  dev->info.device_name,
-			  dev->info.manufacturer,
-			  dev->info.model_name,
-			  dev->info.model_number,
-			  dev->info.serial_number,
-			  dev->info.config_methods,
-			  dev->info.dev_capab,
-			  dev->info.group_capab,
 			  dev->go_neg_req_sent,
 			  p2p_go_state_text(dev->go_state),
 			  dev->dialog_token,
@@ -3064,6 +3210,12 @@
 }
 
 
+int p2p_peer_known(struct p2p_data *p2p, const u8 *addr)
+{
+	return p2p_get_device(p2p, addr) != NULL;
+}
+
+
 void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled)
 {
 	if (enabled) {
@@ -3624,3 +3776,20 @@
 
 	return &dev->info;
 }
+
+#ifdef ANDROID_P2P
+int p2p_search_in_progress(struct p2p_data *p2p)
+{
+	if (p2p == NULL)
+		return 0;
+
+	return p2p->state == P2P_SEARCH;
+}
+#endif
+
+int p2p_in_progress(struct p2p_data *p2p)
+{
+	if (p2p == NULL)
+		return 0;
+	return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
old mode 100644
new mode 100755
index 72c90b1..05b4a16
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -56,7 +56,7 @@
 };
 
 enum p2p_wps_method {
-	WPS_NOT_READY, WPS_PIN_LABEL, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC
+	WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC
 };
 
 /**
@@ -120,6 +120,9 @@
 
 	/**
 	 * persistent_group - Whether the group should be made persistent
+	 * 0 = not persistent
+	 * 1 = persistent group without persistent reconnect
+	 * 2 = persistent group with persistent reconnect
 	 */
 	int persistent_group;
 
@@ -292,17 +295,6 @@
 	 */
 	u8 dev_addr[ETH_ALEN];
 
-#ifdef ANDROID_BRCM_P2P_PATCH
-	/**
-	 * p2p_dev_addr - P2P Device Address
-	 *
-	 * Holds the p2p device address. If the driver uses primary mac address
-	 * for p2p operations, then this will hold the same value as that of 
-	 * dev_addr.
-	 */
-	u8 p2p_dev_addr[ETH_ALEN];
-#endif
-
 	/**
 	 * dev_name - Device Name
 	 */
@@ -602,6 +594,8 @@
 	 * @supp_config_methods: Supported configuration Methods
 	 * @dev_capab: Device Capabilities
 	 * @group_capab: Group Capabilities
+	 * @group_id: P2P Group ID (or %NULL if not included)
+	 * @group_id_len: Length of P2P Group ID
 	 *
 	 * This callback is used to indicate reception of a Provision Discovery
 	 * Request frame that the P2P module accepted.
@@ -609,7 +603,8 @@
 	void (*prov_disc_req)(void *ctx, const u8 *peer, u16 config_methods,
 			      const u8 *dev_addr, const u8 *pri_dev_type,
 			      const char *dev_name, u16 supp_config_methods,
-			      u8 dev_capab, u8 group_capab);
+			      u8 dev_capab, u8 group_capab,
+			      const u8 *group_id, size_t group_id_len);
 
 	/**
 	 * prov_disc_resp - Callback on Provisiong Discovery Response
@@ -857,7 +852,9 @@
  * @go_intent: Local GO intent value (1..15)
  * @own_interface_addr: Intended interface address to use with the group
  * @force_freq: The only allowed channel frequency in MHz or 0
- * @persistent_group: Whether to create a persistent group
+ * @persistent_group: Whether to create a persistent group (0 = no, 1 =
+ * persistent group without persistent reconnect, 2 = persistent group with
+ * persistent reconnect)
  * Returns: 0 on success, -1 on failure
  */
 int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
@@ -873,7 +870,9 @@
  * @go_intent: Local GO intent value (1..15)
  * @own_interface_addr: Intended interface address to use with the group
  * @force_freq: The only allowed channel frequency in MHz or 0
- * @persistent_group: Whether to create a persistent group
+ * @persistent_group: Whether to create a persistent group (0 = no, 1 =
+ * persistent group without persistent reconnect, 2 = persistent group with
+ * persistent reconnect)
  * Returns: 0 on success, -1 on failure
  *
  * This is like p2p_connect(), but the actual group negotiation is not
@@ -898,6 +897,7 @@
  * @peer_addr: MAC address of the peer P2P client
  * @config_methods: WPS Config Methods value (only one bit set)
  * @join: Whether this is used by a client joining an active group
+ * @force_freq: Forced TX frequency for the frame (mainly for the join case)
  * Returns: 0 on success, -1 on failure
  *
  * This function can be used to request a discovered P2P peer to display a PIN
@@ -909,7 +909,7 @@
  * indicated with the p2p_config::prov_disc_resp() callback.
  */
 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
-		      u16 config_methods, int join);
+		      u16 config_methods, int join, int force_freq);
 
 /**
  * p2p_sd_request - Schedule a service discovery query
@@ -1039,6 +1039,28 @@
  */
 void p2p_group_formation_failed(struct p2p_data *p2p);
 
+/**
+ * p2p_get_provisioning_info - Get any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @addr: Peer P2P Device Address
+ * Returns: WPS provisioning information (WPS config method) or 0 if no
+ * information is available
+ *
+ * This function is used to retrieve stored WPS provisioning info for the given
+ * peer.
+ */
+u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr);
+
+/**
+ * p2p_clear_provisioning_info - Clear any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @iface_addr: Peer P2P Interface Address
+ *
+ * This function is used to clear stored WPS provisioning info for the given
+ * peer.
+ */
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr);
+
 
 /* Event notifications from lower layer driver operations */
 
@@ -1046,12 +1068,14 @@
  * p2p_probe_req_rx - Report reception of a Probe Request frame
  * @p2p: P2P module context from p2p_init()
  * @addr: Source MAC address
+ * @dst: Destination MAC address if available or %NULL
+ * @bssid: BSSID if available or %NULL
  * @ie: Information elements from the Probe Request frame body
  * @ie_len: Length of ie buffer in octets
  * Returns: 0 to indicate the frame was not processed or 1 if it was
  */
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
-		     size_t ie_len);
+int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+		     const u8 *bssid, const u8 *ie, size_t ie_len);
 
 /**
  * p2p_rx_action - Report received Action frame
@@ -1173,6 +1197,9 @@
 struct p2p_group_config {
 	/**
 	 * persistent_group - Whether the group is persistent
+	 * 0 = not a persistent group
+	 * 1 = persistent group without persistent reconnect
+	 * 2 = persistent group with persistent reconnect
 	 */
 	int persistent_group;
 
@@ -1244,16 +1271,6 @@
  */
 int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
 			  const u8 *ie, size_t len);
-#ifdef ANDROID_BRCM_P2P_PATCH
-/**
- * p2p_group_get_dev_addr - Retreive the device address of an assocated P2P
- * client. 
- * @group: P2P group context from p2p_group_init()
- * @addr: Interface address of the P2P client
- * Returns: P2P dev_addr on success, NULL on failure
- */
-u8 *p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr);
-#endif /*ANDROID_BRCM_P2P_PATCH */
 
 /**
  * p2p_group_assoc_resp_ie - Build P2P IE for (re)association response
@@ -1363,6 +1380,13 @@
 void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies);
 
 /**
+ * p2p_scan_ie_buf_len - Get maximum buffer length needed for p2p_scan_ie
+ * @p2p: P2P module context from p2p_init()
+ * Returns: Number of octets that p2p_scan_ie() may add to the buffer
+ */
+size_t p2p_scan_ie_buf_len(struct p2p_data *p2p);
+
+/**
  * p2p_go_params - Generate random P2P group parameters
  * @p2p: P2P module context from p2p_init()
  * @params: Buffer for parameters
@@ -1392,16 +1416,36 @@
 const u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie);
 
 /**
- * p2p_get_peer_info - Get P2P peer information in text format
+ * p2p_get_peer_info - Get P2P peer information
  * @p2p: P2P module context from p2p_init()
  * @addr: P2P Device Address of the peer or %NULL to indicate the first peer
  * @next: Whether to select the peer entry following the one indicated by addr
+ * Returns: Pointer to peer info or %NULL if not found
+ */
+const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p,
+					       const u8 *addr, int next);
+
+/**
+ * p2p_get_peer_info_txt - Get internal P2P peer information in text format
+ * @info: Pointer to P2P peer info from p2p_get_peer_info()
  * @buf: Buffer for returning text
  * @buflen: Maximum buffer length
  * Returns: Number of octets written to the buffer or -1 on failure
+ *
+ * Note: This information is internal to the P2P module and subject to change.
+ * As such, this should not really be used by external programs for purposes
+ * other than debugging.
  */
-int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
-		      char *buf, size_t buflen);
+int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
+			  char *buf, size_t buflen);
+
+/**
+ * p2p_peer_known - Check whether P2P peer is known
+ * @p2p: P2P module context from p2p_init()
+ * @addr: P2P Device Address of the peer
+ * Returns: 1 if the specified device is in the P2P peer table or 0 if not
+ */
+int p2p_peer_known(struct p2p_data *p2p, const u8 *addr);
 
 /**
  * p2p_set_client_discoverability - Set client discoverability capability
@@ -1415,7 +1459,7 @@
 void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled);
 
 /**
- * p2p_set_manageD_oper - Set managed P2P Device operations capability
+ * p2p_set_managed_oper - Set managed P2P Device operations capability
  * @p2p: P2P module context from p2p_init()
  * @enabled: Whether managed P2P Device operations will be enabled
  */
@@ -1490,6 +1534,15 @@
 const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
 
 /**
+ * p2p_group_get_dev_addr - Get a P2P Device Address of a client in a group
+ * @group: P2P group context from p2p_group_init()
+ * @addr: P2P Interface Address of the client
+ * Returns: P2P Device Address of the client if found or %NULL if no match
+ * found
+ */
+const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr);
+
+/**
  * p2p_get_peer_found - Get P2P peer info structure of a found peer
  * @p2p: P2P module context from p2p_init()
  * @addr: P2P Device Address of the peer or %NULL to indicate the first peer
@@ -1528,4 +1581,29 @@
 int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
 			 int cfg_op_channel);
 
+/**
+ * p2p_in_progress - Check whether a P2P operation is progress
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation is in progress
+ */
+int p2p_in_progress(struct p2p_data *p2p);
+
+#ifdef ANDROID_P2P
+/**
+ * p2p_in_progress - Check whether a P2P SEARCH is in progress
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation is in progress
+ */
+int p2p_search_in_progress(struct p2p_data *p2p);
+#endif
+
+/**
+ * p2p_other_scan_completed - Notify completion of non-P2P scan
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation was started
+ */
+int p2p_other_scan_completed(struct p2p_data *p2p);
+
+const char * p2p_wps_method_text(enum p2p_wps_method method);
+
 #endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index d59e54b..a82e16d 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -164,27 +164,20 @@
 	len = wpabuf_put(buf, 2); /* IE length to be filled */
 
 	/* P2P Device address */
-#ifdef ANDROID_BRCM_P2P_PATCH
-	/* 
-	* P2P_ADDR: Supplicant uses primary mac addr for p2p and hence advertises that. To
-	* to make it compatible with solution using virtual interface for P2P, a new variable
-	* is added to hold the actual p2p device address.
-	*/
-	wpabuf_put_data(buf, p2p->cfg->p2p_dev_addr, ETH_ALEN);
-#else
 	wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
-#endif
 
 	/* Config Methods */
 	methods = 0;
 	if (peer && peer->wps_method != WPS_NOT_READY) {
 		if (peer->wps_method == WPS_PBC)
 			methods |= WPS_CONFIG_PUSHBUTTON;
-		else if (peer->wps_method == WPS_PIN_LABEL)
-			methods |= WPS_CONFIG_LABEL;
 		else if (peer->wps_method == WPS_PIN_DISPLAY ||
 			 peer->wps_method == WPS_PIN_KEYPAD)
 			methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+	} else if (p2p->cfg->config_methods) {
+		methods |= p2p->cfg->config_methods &
+			(WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
+			 WPS_CONFIG_KEYPAD);
 	} else {
 		methods |= WPS_CONFIG_PUSHBUTTON;
 		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index f5937b9..eb85f51 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -107,8 +107,6 @@
 static u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
 {
 	switch (wps_method) {
-	case WPS_PIN_LABEL:
-		return DEV_PW_DEFAULT;
 	case WPS_PIN_DISPLAY:
 		return DEV_PW_REGISTRAR_SPECIFIED;
 	case WPS_PIN_KEYPAD:
@@ -124,8 +122,6 @@
 static const char * p2p_wps_method_str(enum p2p_wps_method wps_method)
 {
 	switch (wps_method) {
-	case WPS_PIN_LABEL:
-		return "Label";
 	case WPS_PIN_DISPLAY:
 		return "Display";
 	case WPS_PIN_KEYPAD:
@@ -156,8 +152,11 @@
 
 	len = p2p_buf_add_ie_hdr(buf);
 	group_capab = 0;
-	if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
+	if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
 		group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+			group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+	}
 	if (p2p->cross_connect)
 		group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
 	if (p2p->cfg->p2p_intra_bss)
@@ -246,8 +245,12 @@
 	p2p_buf_add_status(buf, status);
 	group_capab = 0;
 	if (peer && peer->go_state == LOCAL_GO) {
-		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
+		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
 			group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+			if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+				group_capab |=
+					P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+		}
 		if (p2p->cross_connect)
 			group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
 		if (p2p->cfg->p2p_intra_bss)
@@ -491,15 +494,7 @@
 		}
 
 		if (dev->go_neg_req_sent &&
-#ifdef ANDROID_BRCM_P2P_PATCH 
-		/* P2P_ADDR: compare against the p2p device address. The own mac 
-		address may not not be the actual p2p device address, if you 
-		are using a virtual interface.
-		*/
-		    os_memcmp(sa, p2p->cfg->p2p_dev_addr, ETH_ALEN) > 0) {
-#else
 		    os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) {
-#endif
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 				"P2P: Do not reply since peer has higher "
 				"address and GO Neg Request already sent");
@@ -524,18 +519,6 @@
 		}
 
 		switch (msg.dev_password_id) {
-		case DEV_PW_DEFAULT:
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: PIN from peer Label");
-			if (dev->wps_method != WPS_PIN_KEYPAD) {
-				wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-					"P2P: We have wps_method=%s -> "
-					"incompatible",
-					p2p_wps_method_str(dev->wps_method));
-				status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
-				goto fail;
-			}
-			break;
 		case DEV_PW_REGISTRAR_SPECIFIED:
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 				"P2P: PIN from peer Display");
@@ -551,8 +534,7 @@
 		case DEV_PW_USER_SPECIFIED:
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 				"P2P: Peer entered PIN on Keypad");
-			if (dev->wps_method != WPS_PIN_LABEL &&
-			    dev->wps_method != WPS_PIN_DISPLAY) {
+			if (dev->wps_method != WPS_PIN_DISPLAY) {
 				wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 					"P2P: We have wps_method=%s -> "
 					"incompatible",
@@ -606,7 +588,10 @@
 						   p2p->op_channel))
 				p2p_reselect_channel(p2p, &intersection);
 
-			p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+			if (!p2p->ssid_set) {
+				p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+				p2p->ssid_set = 1;
+			}
 		}
 
 		dev->go_state = go ? LOCAL_GO : REMOTE_GO;
@@ -695,8 +680,12 @@
 	p2p_buf_add_status(buf, status);
 	group_capab = 0;
 	if (peer->go_state == LOCAL_GO) {
-		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
+		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
 			group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+			if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+				group_capab |=
+					P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+		}
 		if (p2p->cross_connect)
 			group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
 		if (p2p->cfg->p2p_intra_bss)
@@ -907,18 +896,6 @@
 		dev->oper_freq = 0;
 
 	switch (msg.dev_password_id) {
-	case DEV_PW_DEFAULT:
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: PIN from peer Label");
-		if (dev->wps_method != WPS_PIN_KEYPAD) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: We have wps_method=%s -> "
-				"incompatible",
-				p2p_wps_method_str(dev->wps_method));
-			status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
-			goto fail;
-		}
-		break;
 	case DEV_PW_REGISTRAR_SPECIFIED:
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: PIN from peer Display");
@@ -934,8 +911,7 @@
 	case DEV_PW_USER_SPECIFIED:
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Peer entered PIN on Keypad");
-		if (dev->wps_method != WPS_PIN_LABEL &&
-		    dev->wps_method != WPS_PIN_DISPLAY) {
+		if (dev->wps_method != WPS_PIN_DISPLAY) {
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 				"P2P: We have wps_method=%s -> "
 				"incompatible",
@@ -988,7 +964,10 @@
 					   p2p->op_channel))
 			p2p_reselect_channel(p2p, &intersection);
 
-		p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+		if (!p2p->ssid_set) {
+			p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+			p2p->ssid_set = 1;
+		}
 	}
 
 	p2p_set_state(p2p, P2P_GO_NEG);
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 0d05319..59d1507 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -147,8 +147,11 @@
 	dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
 	dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE;
 	group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
-	if (group->cfg->persistent_group)
+	if (group->cfg->persistent_group) {
 		group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+		if (group->cfg->persistent_group == 2)
+			group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+	}
 	if (group->p2p->cfg->p2p_intra_bss)
 		group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
 	if (group->group_formation)
@@ -183,12 +186,7 @@
 
 	len = p2p_buf_add_ie_hdr(ie);
 	p2p_group_add_common_ies(group, ie);
-#ifdef ANDROID_BRCM_P2P_PATCH
-	/* P2P_ADDR: Use p2p_dev_addr instead of own mac addr*/
-	p2p_buf_add_device_id(ie, group->p2p->cfg->p2p_dev_addr);
-#else
 	p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
-#endif
 	p2p_group_add_noa(ie, group->noa);
 	p2p_buf_update_ie_hdr(ie, len);
 
@@ -315,6 +313,36 @@
 }
 
 
+static int p2p_group_remove_member(struct p2p_group *group, const u8 *addr)
+{
+	struct p2p_group_member *m, *prev;
+
+	if (group == NULL)
+		return 0;
+
+	m = group->members;
+	prev = NULL;
+	while (m) {
+		if (os_memcmp(m->addr, addr, ETH_ALEN) == 0)
+			break;
+		prev = m;
+		m = m->next;
+	}
+
+	if (m == NULL)
+		return 0;
+
+	if (prev)
+		prev->next = m->next;
+	else
+		group->members = m->next;
+	p2p_group_free_member(m);
+	group->num_members--;
+
+	return 1;
+}
+
+
 int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
 			  const u8 *ie, size_t len)
 {
@@ -334,6 +362,8 @@
 						       m->dev_addr);
 	}
 
+	p2p_group_remove_member(group, addr);
+
 	m->next = group->members;
 	group->members = m;
 	group->num_members++;
@@ -376,27 +406,7 @@
 
 void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr)
 {
-	struct p2p_group_member *m, *prev;
-
-	if (group == NULL)
-		return;
-
-	m = group->members;
-	prev = NULL;
-	while (m) {
-		if (os_memcmp(m->addr, addr, ETH_ALEN) == 0)
-			break;
-		prev = m;
-		m = m->next;
-	}
-
-	if (m) {
-		if (prev)
-			prev->next = m->next;
-		else
-			group->members = m->next;
-		p2p_group_free_member(m);
-		group->num_members--;
+	if (p2p_group_remove_member(group, addr)) {
 		wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Remove "
 			"client " MACSTR " from group; num_members=%u/%u",
 			MAC2STR(addr), group->num_members,
@@ -499,11 +509,7 @@
 	} else {
 		if (group->noa) {
 			if (wpabuf_size(group->noa) >= noa_len) {
-			#ifdef ANDROID_BRCM_P2P_PATCH
 				group->noa->used = 0;
-			#else
-				group->noa->size = 0;
-			#endif
 				wpabuf_put_data(group->noa, noa, noa_len);
 			} else {
 				wpabuf_free(group->noa);
@@ -551,19 +557,19 @@
 	return NULL;
 }
 
-#ifdef ANDROID_BRCM_P2P_PATCH
-u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr)
+
+const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr)
 {
 	struct p2p_group_member *m;
 
-	m = p2p_group_get_client_iface(group, addr);
-
-	if (m)
-		return m->dev_addr;
-	else
+	if (group == NULL)
 		return NULL;
+	m = p2p_group_get_client_iface(group, addr);
+	if (m && !is_zero_ether_addr(m->dev_addr))
+		return m->dev_addr;
+	return NULL;
 }
-#endif /* ANDROID_BRCM_P2P_PATCH */
+
 
 static struct wpabuf * p2p_build_go_disc_req(void)
 {
@@ -662,11 +668,11 @@
 	else
 		wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa,
 			    curr_noa_len);
-#ifndef ANDROID_BRCM_P2P_PATCH
+
 	/* TODO: properly process request and store copy */
-	if (curr_noa_len > 0)
+	if (curr_noa_len > 0 || curr_noa_len == -1)
 		return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
-#endif
+
 	return P2P_SC_SUCCESS;
 }
 
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index afb891e..0dc33e7 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -18,8 +18,6 @@
 #include "utils/list.h"
 #include "p2p.h"
 
-/* TODO: add removal of expired P2P device entries */
-
 enum p2p_go_state {
 	UNKNOWN_GO,
 	LOCAL_GO,
@@ -69,10 +67,18 @@
 	size_t oper_ssid_len;
 
 	/**
-	 * req_config_methods - Pending provisioning discovery methods
+	 * req_config_methods - Pending provision discovery methods
 	 */
 	u16 req_config_methods;
 
+	/**
+	 * wps_prov_info - Stored provisioning WPS config method
+	 *
+	 * This is used to store pending WPS config method between Provisioning
+	 * Discovery and connection to a running group.
+	 */
+	u16 wps_prov_info;
+
 #define P2P_DEV_PROBE_REQ_ONLY BIT(0)
 #define P2P_DEV_REPORTED BIT(1)
 #define P2P_DEV_NOT_YET_READY BIT(2)
@@ -89,6 +95,7 @@
 #define P2P_DEV_FORCE_FREQ BIT(13)
 #define P2P_DEV_PD_FOR_JOIN BIT(14)
 #define P2P_DEV_REPORTED_ONCE BIT(15)
+#define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16)
 	unsigned int flags;
 
 	int status; /* enum p2p_status_code */
@@ -200,6 +207,11 @@
 		 * P2P_INVITE_LISTEN - Listen during Invite
 		 */
 		P2P_INVITE_LISTEN,
+
+		/**
+		 * P2P_SEARCH_WHEN_READY - Waiting to start Search
+		 */
+		P2P_SEARCH_WHEN_READY,
 	} state;
 
 	/**
@@ -273,6 +285,11 @@
 	size_t ssid_len;
 
 	/**
+	 * ssid_set - Whether SSID is already set for GO Negotiation
+	 */
+	int ssid_set;
+
+	/**
 	 * Regulatory class for own operational channel
 	 */
 	u8 op_reg_class;
@@ -349,6 +366,7 @@
 	int inv_persistent;
 
 	enum p2p_discovery_type find_type;
+	unsigned int last_p2p_find_timeout;
 	u8 last_prog_scan_class;
 	u8 last_prog_scan_chan;
 	int p2p_scan_running;
@@ -532,11 +550,6 @@
 
 /* p2p_group.c */
 const u8 * p2p_group_get_interface_addr(struct p2p_group *group);
-
-#ifdef ANDROID_BRCM_P2P_PATCH
-void p2p_get_group_noa(struct p2p_group *group, u8 *noa, size_t* noa_len);
-#endif
-
 u8 p2p_group_presence_req(struct p2p_group *group,
 			  const u8 *client_interface_addr,
 			  const u8 *noa, size_t noa_len);
@@ -606,7 +619,7 @@
 void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
 				const u8 *data, size_t len);
 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
-			   int join);
+			   int join, int force_freq);
 void p2p_reset_pending_pd(struct p2p_data *p2p);
 
 /* p2p_invitation.c */
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 42015ad..bb2767d 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -55,11 +55,7 @@
 	else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT)
 		dev_addr = peer->info.p2p_device_addr;
 	else
-#ifdef ANDROID_BRCM_P2P_PATCH
-		dev_addr = p2p->cfg->p2p_dev_addr;
-#else
 		dev_addr = p2p->cfg->dev_addr;
-#endif
 	p2p_buf_add_group_id(buf, dev_addr, p2p->inv_ssid, p2p->inv_ssid_len);
 	p2p_buf_add_device_info(buf, p2p, peer);
 	p2p_buf_update_ie_hdr(buf, len);
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 32d82f6..1ee59c5 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -112,7 +112,7 @@
 		MAC2STR(sa), msg.wps_config_methods, rx_freq);
 
 	dev = p2p_get_device(p2p, sa);
-	if (dev == NULL || !(dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
+	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Provision Discovery Request from "
 			"unknown peer " MACSTR, MAC2STR(sa));
@@ -191,8 +191,8 @@
 					msg.device_name, msg.config_methods,
 					msg.capability ? msg.capability[0] : 0,
 					msg.capability ? msg.capability[1] :
-					0);
-
+					0,
+					msg.group_id, msg.group_id_len);
 	}
 	p2p_parse_free(&msg);
 }
@@ -209,14 +209,14 @@
 		return;
 
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received Provisioning Discovery Response from " MACSTR
+		"P2P: Received Provision Discovery Response from " MACSTR
 		" with config methods 0x%x",
 		MAC2STR(sa), msg.wps_config_methods);
 
 	dev = p2p_get_device(p2p, sa);
 	if (dev == NULL || !dev->req_config_methods) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore Provisioning Discovery Response from "
+			"P2P: Ignore Provision Discovery Response from "
 			MACSTR " with no pending request", MAC2STR(sa));
 		p2p_parse_free(&msg);
 		return;
@@ -229,7 +229,7 @@
 
 	if (dev->dialog_token != msg.dialog_token) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore Provisioning Discovery Response with "
+			"P2P: Ignore Provision Discovery Response with "
 			"unexpected Dialog Token %u (expected %u)",
 			msg.dialog_token, dev->dialog_token);
 		p2p_parse_free(&msg);
@@ -246,7 +246,7 @@
 
 	if (msg.wps_config_methods != dev->req_config_methods) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
-			"our Provisioning Discovery Request");
+			"our Provision Discovery Request");
 		if (p2p->cfg->prov_disc_fail)
 			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
 						 P2P_PROV_DISC_REJECTED);
@@ -267,6 +267,10 @@
 			MAC2STR(sa));
 		dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
 	}
+
+	/* Store the provisioning info */
+	dev->wps_prov_info = msg.wps_config_methods;
+
 	p2p_parse_free(&msg);
 
 out:
@@ -279,25 +283,16 @@
 
 
 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
-			   int join)
+			   int join, int force_freq)
 {
 	struct wpabuf *req;
 	int freq;
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if(dev->go_state == REMOTE_GO) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: GO Sending it to oper_freq %d", dev->oper_freq);
-		freq= dev->oper_freq;
-	}
-	else {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: NOT GO oper_freq %d listen_freq %d", dev->oper_freq, dev->listen_freq);
-		freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
-	}
-#else
-	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
-#endif
 
+	if (force_freq > 0)
+		freq = force_freq;
+	else
+		freq = dev->listen_freq > 0 ? dev->listen_freq :
+			dev->oper_freq;
 	if (freq <= 0) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: No Listen/Operating frequency known for the "
@@ -345,7 +340,7 @@
 
 
 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
-		      u16 config_methods, int join)
+		      u16 config_methods, int join, int force_freq)
 {
 	struct p2p_device *dev;
 
@@ -365,6 +360,9 @@
 	if (config_methods == 0)
 		return -1;
 
+	/* Reset provisioning info */
+	dev->wps_prov_info = 0;
+
 	dev->req_config_methods = config_methods;
 	if (join)
 		dev->flags |= P2P_DEV_PD_FOR_JOIN;
@@ -391,12 +389,26 @@
 	if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
 		p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
 
-	return p2p_send_prov_disc_req(p2p, dev, join);
+	return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
 }
 
 
 void p2p_reset_pending_pd(struct p2p_data *p2p)
 {
+	struct p2p_device *dev;
+
+	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+		if (os_memcmp(p2p->pending_pd_devaddr,
+			      dev->info.p2p_device_addr, ETH_ALEN))
+			continue;
+		if (!dev->req_config_methods)
+			continue;
+		if (dev->flags & P2P_DEV_PD_FOR_JOIN)
+			continue;
+		/* Reset the config methods of the device */
+		dev->req_config_methods = 0;
+	}
+
 	p2p->user_initiated_pd = 0;
 	os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
 	p2p->pd_retries = 0;
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 9e26873..f53d4b5 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -16,6 +16,7 @@
 
 #include "common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/gas.h"
 #include "p2p_i.h"
 #include "p2p.h"
 
@@ -26,7 +27,7 @@
 	struct p2p_sd_query *q;
 
 	if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
-		return 0; /* peer does not support SD */
+		return NULL; /* peer does not support SD */
 
 	for (q = p2p->sd_queries; q; q = q->next) {
 		if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO))
@@ -90,51 +91,21 @@
 					  struct wpabuf *tlvs)
 {
 	struct wpabuf *buf;
-	u8 *len_pos, *len_pos2;
+	u8 *len_pos;
 
-	buf = wpabuf_alloc(1000 + wpabuf_len(tlvs));
+	buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs));
 	if (buf == NULL)
 		return NULL;
 
-	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
-	wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ);
-	wpabuf_put_u8(buf, 0); /* Dialog Token */
-
-	/* Advertisement Protocol IE */
-	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
-	wpabuf_put_u8(buf, 2); /* Length */
-	wpabuf_put_u8(buf, 0); /* QueryRespLenLimit | PAME-BI */
-	wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */
-
-	/* Query Request */
-	len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
-	/* NQP Query Request Frame */
-	wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
-	len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
+	/* ANQP Query Request Frame */
+	len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
 	wpabuf_put_be24(buf, OUI_WFA);
 	wpabuf_put_u8(buf, P2P_OUI_TYPE);
 	wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */
 	wpabuf_put_buf(buf, tlvs);
+	gas_anqp_set_element_len(buf, len_pos);
 
-	WPA_PUT_LE16(len_pos2, (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
-	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
-
-	return buf;
-}
-
-
-static struct wpabuf * p2p_build_gas_comeback_req(u8 dialog_token)
-{
-	struct wpabuf *buf;
-
-	buf = wpabuf_alloc(3);
-	if (buf == NULL)
-		return NULL;
-
-	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
-	wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_REQ);
-	wpabuf_put_u8(buf, dialog_token);
+	gas_anqp_set_len(buf);
 
 	return buf;
 }
@@ -145,7 +116,7 @@
 {
 	struct wpabuf *req;
 
-	req = p2p_build_gas_comeback_req(dialog_token);
+	req = gas_build_comeback_req(dialog_token);
 	if (req == NULL)
 		return;
 
@@ -165,42 +136,26 @@
 					     const struct wpabuf *tlvs)
 {
 	struct wpabuf *buf;
-	u8 *len_pos, *len_pos2;
+	u8 *len_pos;
 
-	buf = wpabuf_alloc(1000 + (tlvs ? wpabuf_len(tlvs) : 0));
+	buf = gas_anqp_build_initial_resp(dialog_token, status_code,
+					  comeback_delay,
+					  100 + (tlvs ? wpabuf_len(tlvs) : 0));
 	if (buf == NULL)
 		return NULL;
 
-	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
-	wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
-	wpabuf_put_u8(buf, dialog_token);
-	wpabuf_put_le16(buf, status_code);
-	wpabuf_put_le16(buf, comeback_delay);
-
-	/* Advertisement Protocol IE */
-	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
-	wpabuf_put_u8(buf, 2); /* Length */
-	wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
-	wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */
-
-	/* Query Response */
-	len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
 	if (tlvs) {
-		/* NQP Query Response Frame */
-		wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
-		len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
+		/* ANQP Query Response Frame */
+		len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
 		wpabuf_put_be24(buf, OUI_WFA);
 		wpabuf_put_u8(buf, P2P_OUI_TYPE);
 		 /* Service Update Indicator */
 		wpabuf_put_le16(buf, update_indic);
 		wpabuf_put_buf(buf, tlvs);
-
-		WPA_PUT_LE16(len_pos2,
-			     (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
+		gas_anqp_set_element_len(buf, len_pos);
 	}
 
-	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+	gas_anqp_set_len(buf);
 
 	return buf;
 }
@@ -214,31 +169,15 @@
 						   u16 total_len)
 {
 	struct wpabuf *buf;
-	u8 *len_pos;
 
-	buf = wpabuf_alloc(1000 + len);
+	buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
+					   more, 0, 100 + len);
 	if (buf == NULL)
 		return NULL;
 
-	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
-	wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_RESP);
-	wpabuf_put_u8(buf, dialog_token);
-	wpabuf_put_le16(buf, status_code);
-	wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
-	wpabuf_put_le16(buf, 0); /* Comeback Delay */
-
-	/* Advertisement Protocol IE */
-	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
-	wpabuf_put_u8(buf, 2); /* Length */
-	wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
-	wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */
-
-	/* Query Response */
-	len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
 	if (frag_id == 0) {
-		/* NQP Query Response Frame */
-		wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
+		/* ANQP Query Response Frame */
+		wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
 		wpabuf_put_le16(buf, 3 + 1 + 2 + total_len);
 		wpabuf_put_be24(buf, OUI_WFA);
 		wpabuf_put_u8(buf, P2P_OUI_TYPE);
@@ -247,8 +186,7 @@
 	}
 
 	wpabuf_put_data(buf, data, len);
-
-	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+	gas_anqp_set_len(buf);
 
 	return buf;
 }
@@ -349,7 +287,7 @@
 	}
 	pos++; /* skip QueryRespLenLimit and PAME-BI */
 
-	if (*pos != NATIVE_QUERY_PROTOCOL) {
+	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Unsupported GAS advertisement protocol id %u",
 			*pos);
@@ -366,12 +304,12 @@
 		return;
 	end = pos + slen;
 
-	/* NQP Query Request */
+	/* ANQP Query Request */
 	if (pos + 4 > end)
 		return;
-	if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) {
+	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos));
+			"P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
 		return;
 	}
 	pos += 2;
@@ -380,20 +318,20 @@
 	pos += 2;
 	if (pos + slen > end || slen < 3 + 1) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid NQP Query Request length");
+			"P2P: Invalid ANQP Query Request length");
 		return;
 	}
 
 	if (WPA_GET_BE24(pos) != OUI_WFA) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos));
+			"P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
 		return;
 	}
 	pos += 3;
 
 	if (*pos != P2P_OUI_TYPE) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP vendor type %u", *pos);
+			"P2P: Unsupported ANQP vendor type %u", *pos);
 		return;
 	}
 	pos++;
@@ -451,11 +389,7 @@
 
 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 	if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
-		#ifdef ANDROID_BRCM_P2P_PATCH
-			   p2p->cfg->p2p_dev_addr,
-		#else
 			    p2p->cfg->dev_addr,
-		#endif
 			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Failed to send Action frame");
@@ -529,7 +463,7 @@
 	}
 	pos++; /* skip QueryRespLenLimit and PAME-BI */
 
-	if (*pos != NATIVE_QUERY_PROTOCOL) {
+	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Unsupported GAS advertisement protocol id %u",
 			*pos);
@@ -567,12 +501,12 @@
 		return;
 	}
 
-	/* NQP Query Response */
+	/* ANQP Query Response */
 	if (pos + 4 > end)
 		return;
-	if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) {
+	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos));
+			"P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
 		return;
 	}
 	pos += 2;
@@ -581,20 +515,20 @@
 	pos += 2;
 	if (pos + slen > end || slen < 3 + 1) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid NQP Query Response length");
+			"P2P: Invalid ANQP Query Response length");
 		return;
 	}
 
 	if (WPA_GET_BE24(pos) != OUI_WFA) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos));
+			"P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
 		return;
 	}
 	pos += 3;
 
 	if (*pos != P2P_OUI_TYPE) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP vendor type %u", *pos);
+			"P2P: Unsupported ANQP vendor type %u", *pos);
 		return;
 	}
 	pos++;
@@ -776,7 +710,7 @@
 	}
 	pos++; /* skip QueryRespLenLimit and PAME-BI */
 
-	if (*pos != NATIVE_QUERY_PROTOCOL) {
+	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Unsupported GAS advertisement protocol id %u",
 			*pos);
@@ -808,29 +742,29 @@
 
 	if (p2p->sd_rx_resp) {
 		 /*
-		  * NQP header is only included in the first fragment; rest of
+		  * ANQP header is only included in the first fragment; rest of
 		  * the fragments start with continue TLVs.
 		  */
 		goto skip_nqp_header;
 	}
 
-	/* NQP Query Response */
+	/* ANQP Query Response */
 	if (pos + 4 > end)
 		return;
-	if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) {
+	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos));
+			"P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
 		return;
 	}
 	pos += 2;
 
 	slen = WPA_GET_LE16(pos);
 	pos += 2;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: NQP Query Response "
+	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: ANQP Query Response "
 		"length: %u", slen);
 	if (slen < 3 + 1) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid NQP Query Response length");
+			"P2P: Invalid ANQP Query Response length");
 		return;
 	}
 	if (pos + 4 > end)
@@ -838,14 +772,14 @@
 
 	if (WPA_GET_BE24(pos) != OUI_WFA) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos));
+			"P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
 		return;
 	}
 	pos += 3;
 
 	if (*pos != P2P_OUI_TYPE) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP vendor type %u", *pos);
+			"P2P: Unsupported ANQP vendor type %u", *pos);
 		return;
 	}
 	pos++;
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 70754ef..3ead847 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -218,6 +218,8 @@
 	{ RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
 	{ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
 	  RADIUS_ATTR_HEXDUMP },
+	{ RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password",
+	  RADIUS_ATTR_UNDIST },
 	{ RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
 	{ RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
 	{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
@@ -1090,8 +1092,7 @@
 				  const u8 *secret, size_t secret_len)
 {
 	u8 buf[128];
-	int padlen, i;
-	size_t buf_len, pos;
+	size_t padlen, i, buf_len, pos;
 	const u8 *addr[2];
 	size_t len[2];
 	u8 hash[16];
@@ -1103,7 +1104,7 @@
 	buf_len = data_len;
 
 	padlen = data_len % 16;
-	if (padlen) {
+	if (padlen && data_len < sizeof(buf)) {
 		padlen = 16 - padlen;
 		os_memset(buf + data_len, 0, padlen);
 		buf_len += padlen;
@@ -1276,6 +1277,120 @@
 }
 
 
+/**
+ * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password
+ * @msg: Received RADIUS message
+ * @keylen: Length of returned password
+ * @secret: RADIUS shared secret
+ * @secret_len: Length of secret
+ * @sent_msg: Sent RADIUS message
+ * Returns: pointer to password (free with os_free) or %NULL
+ */
+char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
+				      const u8 *secret, size_t secret_len,
+				      struct radius_msg *sent_msg)
+{
+	u8 *buf = NULL;
+	size_t buflen;
+	const u8 *salt;
+	u8 *str;
+	const u8 *addr[3];
+	size_t len[3];
+	u8 hash[16];
+	u8 *pos;
+	size_t i;
+	struct radius_attr_hdr *attr;
+	const u8 *data;
+	size_t dlen;
+	const u8 *fdata = NULL; /* points to found item */
+	size_t fdlen = -1;
+	char *ret = NULL;
+
+	/* find attribute with lowest tag and check it */
+	for (i = 0; i < msg->attr_used; i++) {
+		attr = radius_get_attr_hdr(msg, i);
+		if (attr == NULL ||
+		    attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) {
+			continue;
+		}
+		if (attr->length <= 5)
+			continue;
+		data = (const u8 *) (attr + 1);
+		dlen = attr->length - sizeof(*attr);
+		if (dlen <= 3 || dlen % 16 != 3)
+			continue;
+		if (fdata != NULL && fdata[0] <= data[0])
+			continue;
+
+		fdata = data;
+		fdlen = dlen;
+	}
+	if (fdata == NULL)
+		goto out;
+
+	/* alloc writable memory for decryption */
+	buf = os_malloc(fdlen);
+	if (buf == NULL)
+		goto out;
+	os_memcpy(buf, fdata, fdlen);
+	buflen = fdlen;
+
+	/* init pointers */
+	salt = buf + 1;
+	str = buf + 3;
+
+	/* decrypt blocks */
+	pos = buf + buflen - 16; /* last block */
+	while (pos >= str + 16) { /* all but the first block */
+		addr[0] = secret;
+		len[0] = secret_len;
+		addr[1] = pos - 16;
+		len[1] = 16;
+		md5_vector(2, addr, len, hash);
+
+		for (i = 0; i < 16; i++)
+			pos[i] ^= hash[i];
+
+		pos -= 16;
+	}
+
+	/* decrypt first block */
+	if (str != pos)
+		goto out;
+	addr[0] = secret;
+	len[0] = secret_len;
+	addr[1] = sent_msg->hdr->authenticator;
+	len[1] = 16;
+	addr[2] = salt;
+	len[2] = 2;
+	md5_vector(3, addr, len, hash);
+
+	for (i = 0; i < 16; i++)
+		pos[i] ^= hash[i];
+
+	/* derive plaintext length from first subfield */
+	*keylen = (unsigned char) str[0];
+	if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) {
+		/* decryption error - invalid key length */
+		goto out;
+	}
+	if (*keylen == 0) {
+		/* empty password */
+		goto out;
+	}
+
+	/* copy passphrase into new buffer */
+	ret = os_malloc(*keylen);
+	if (ret)
+		os_memcpy(ret, str + 1, *keylen);
+
+out:
+	/* return new buffer */
+	os_free(buf);
+	return ret;
+}
+
+
 void radius_free_class(struct radius_class_data *c)
 {
 	size_t i;
diff --git a/src/radius/radius.h b/src/radius/radius.h
index a3cdac0..e69a047 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -82,6 +82,7 @@
        RADIUS_ATTR_NAS_PORT_TYPE = 61,
        RADIUS_ATTR_TUNNEL_TYPE = 64,
        RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
+       RADIUS_ATTR_TUNNEL_PASSWORD = 69,
        RADIUS_ATTR_CONNECT_INFO = 77,
        RADIUS_ATTR_EAP_MESSAGE = 79,
        RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
@@ -231,6 +232,9 @@
 				  const u8 *secret, size_t secret_len);
 int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
 int radius_msg_get_vlanid(struct radius_msg *msg);
+char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
+				      const u8 *secret, size_t secret_len,
+				      struct radius_msg *sent_msg);
 
 static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
 					    u32 value)
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 6f1c3a5..47948bc 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -1,6 +1,6 @@
 /*
  * RADIUS authentication server
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2009, 2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -292,6 +292,10 @@
 	 * msg_ctx - Context data for wpa_msg() calls
 	 */
 	void *msg_ctx;
+
+#ifdef CONFIG_RADIUS_TEST
+	char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
 };
 
 
@@ -574,6 +578,24 @@
 
 	if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {
 		int len;
+#ifdef CONFIG_RADIUS_TEST
+		if (data->dump_msk_file) {
+			FILE *f;
+			char buf[2 * 64 + 1];
+			f = fopen(data->dump_msk_file, "a");
+			if (f) {
+				len = sess->eap_if->eapKeyDataLen;
+				if (len > 64)
+					len = 64;
+				len = wpa_snprintf_hex(
+					buf, sizeof(buf),
+					sess->eap_if->eapKeyData, len);
+				buf[len] = '\0';
+				fprintf(f, "%s\n", buf);
+				fclose(f);
+			}
+		}
+#endif /* CONFIG_RADIUS_TEST */
 		if (sess->eap_if->eapKeyDataLen > 64) {
 			len = 32;
 		} else {
@@ -1277,6 +1299,11 @@
 		}
 	}
 
+#ifdef CONFIG_RADIUS_TEST
+	if (conf->dump_msk_file)
+		data->dump_msk_file = os_strdup(conf->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
+
 	data->clients = radius_server_read_clients(conf->client_file,
 						   conf->ipv6);
 	if (data->clients == NULL) {
@@ -1328,6 +1355,9 @@
 	os_free(data->eap_fast_a_id);
 	os_free(data->eap_fast_a_id_info);
 	os_free(data->eap_req_id_text);
+#ifdef CONFIG_RADIUS_TEST
+	os_free(data->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
 	os_free(data);
 }
 
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 126e314..8d6e2ab 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -1,6 +1,6 @@
 /*
  * RADIUS authentication server
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2009, 2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -201,6 +201,10 @@
 	 * msg_ctx - Context data for wpa_msg() calls
 	 */
 	void *msg_ctx;
+
+#ifdef CONFIG_RADIUS_TEST
+	const char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
 };
 
 
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index cac8c83..3877efb 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -49,6 +49,7 @@
 				   struct rsn_pmksa_cache_entry *entry,
 				   int replace)
 {
+	wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
 	pmksa->pmksa_count--;
 	pmksa->free_cb(entry, pmksa->ctx, replace);
 	_pmksa_cache_free_entry(entry);
@@ -185,6 +186,14 @@
 			wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
 				   "the current AP");
 			pmksa_cache_free_entry(pmksa, pos, 1);
+
+			/*
+			 * If OKC is used, there may be other PMKSA cache
+			 * entries based on the same PMK. These needs to be
+			 * flushed so that a new entry can be created based on
+			 * the new PMK.
+			 */
+			pmksa_cache_flush(pmksa, network_ctx);
 			break;
 		}
 		prev = pos;
@@ -198,7 +207,6 @@
 		wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
 			   "entry (for " MACSTR ") to make room for new one",
 			   MAC2STR(pos->aa));
-		wpa_sm_remove_pmkid(pmksa->sm, pos->aa, pos->pmkid);
 		pmksa_cache_free_entry(pmksa, pos, 0);
 	}
 
@@ -229,6 +237,39 @@
 
 
 /**
+ * pmksa_cache_flush - Flush PMKSA cache entries for a specific network
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @network_ctx: Network configuration context or %NULL to flush all entries
+ */
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
+{
+	struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
+	int removed = 0;
+
+	entry = pmksa->pmksa;
+	while (entry) {
+		if (entry->network_ctx == network_ctx || network_ctx == NULL) {
+			wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
+				   "for " MACSTR, MAC2STR(entry->aa));
+			if (prev)
+				prev->next = entry->next;
+			else
+				pmksa->pmksa = entry->next;
+			tmp = entry;
+			entry = entry->next;
+			pmksa_cache_free_entry(pmksa, tmp, 0);
+			removed++;
+		} else {
+			prev = entry;
+			entry = entry->next;
+		}
+	}
+	if (removed)
+		pmksa_cache_set_expiration(pmksa);
+}
+
+
+/**
  * pmksa_cache_deinit - Free all entries in PMKSA cache
  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  */
@@ -273,22 +314,6 @@
 }
 
 
-/**
- * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache
- * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
- *
- * Clear references to old data structures when wpa_supplicant is reconfigured.
- */
-void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
-{
-	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
-	while (entry) {
-		entry->network_ctx = NULL;
-		entry = entry->next;
-	}
-}
-
-
 static struct rsn_pmksa_cache_entry *
 pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
 			const struct rsn_pmksa_cache_entry *old_entry,
@@ -327,6 +352,7 @@
 {
 	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
 
+	wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa));
 	if (network_ctx == NULL)
 		return NULL;
 	while (entry) {
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index a1447e5..840827d 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -57,7 +57,6 @@
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 		const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
-void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa);
 struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
 void pmksa_cache_clear_current(struct wpa_sm *sm);
 int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
@@ -66,6 +65,7 @@
 struct rsn_pmksa_cache_entry *
 pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
 			      void *network_ctx, const u8 *aa);
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx);
 
 #else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
 
@@ -106,10 +106,6 @@
 	return NULL;
 }
 
-static inline void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
-{
-}
-
 static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
 {
 }
@@ -122,6 +118,11 @@
 	return -1;
 }
 
+static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
+				     void *network_ctx)
+{
+}
+
 #endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
 
 #endif /* PMKSA_CACHE_H */
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index 6109f5e..fefca83 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -22,7 +22,6 @@
 #include "preauth.h"
 #include "pmksa_cache.h"
 #include "wpa_i.h"
-#include "common/ieee802_11_defs.h"
 
 
 #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index e751867..27090e3 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -88,6 +88,8 @@
 
 
 #define TDLS_MAX_IE_LEN 80
+#define IEEE80211_MAX_SUPP_RATES 32
+
 struct wpa_tdls_peer {
 	struct wpa_tdls_peer *next;
 	int initiator; /* whether this end was initiator for TDLS setup */
@@ -119,6 +121,11 @@
 		int buf_len;    /* length of TPK message for retransmission */
 		u8 *buf;        /* buffer for TPK message */
 	} sm_tmr;
+
+	u16 capability;
+
+	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+	size_t supp_rates_len;
 };
 
 
@@ -214,7 +221,9 @@
 	}
 
 	if (action_code == WLAN_TDLS_SETUP_CONFIRM ||
-	    action_code == WLAN_TDLS_TEARDOWN)
+	    action_code == WLAN_TDLS_TEARDOWN ||
+	    action_code == WLAN_TDLS_DISCOVERY_REQUEST ||
+	    action_code == WLAN_TDLS_DISCOVERY_RESPONSE)
 		return 0; /* No retries */
 
 	for (peer = sm->tdls; peer; peer = peer->next) {
@@ -253,6 +262,27 @@
 }
 
 
+static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
+				u16 reason_code, int free_peer)
+{
+	int ret;
+
+	if (sm->tdls_external_setup) {
+		ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code);
+
+		/* disable the link after teardown was sent */
+		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+	} else {
+		ret = wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+	}
+
+	if (sm->tdls_external_setup || free_peer)
+		wpa_tdls_peer_free(sm, peer);
+
+	return ret;
+}
+
+
 static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 
@@ -291,15 +321,11 @@
 		eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
 				       wpa_tdls_tpk_retry_timeout, sm, peer);
 	} else {
-		wpa_printf(MSG_INFO, "Sending Tear_Down Request");
-		wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
-
-		wpa_printf(MSG_INFO, "Clearing SM: Peerkey(" MACSTR ")",
-			   MAC2STR(peer->addr));
 		eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
 
-		/* clear the Peerkey statemachine */
-		wpa_tdls_peer_free(sm, peer);
+		wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request");
+		wpa_tdls_do_teardown(sm, peer,
+				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
 	}
 }
 
@@ -576,7 +602,8 @@
 	} else {
 		wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
 			   " - tear down", MAC2STR(peer->addr));
-		wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+		wpa_tdls_do_teardown(sm, peer,
+				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
 	}
 }
 
@@ -615,8 +642,7 @@
 }
 
 
-int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr,
-				  u16 reason_code)
+int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
 {
 	struct wpa_tdls_peer *peer;
 	struct wpa_tdls_ftie *ftie;
@@ -625,7 +651,7 @@
 	u8 *rbuf, *pos;
 	int ielen;
 
-	if (sm->tdls_disabled)
+	if (sm->tdls_disabled || !sm->tdls_supported)
 		return -1;
 
 	/* Find the node and free from the list */
@@ -677,10 +703,11 @@
 		ftie->ie_len += 170;
 		*pos++ = 255; /* FTIE subelem */
 		*pos++ = 168; /* FTIE subelem length */
+		pos += 168;
 	}
 #endif /* CONFIG_TDLS_TESTING */
 	wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TDLS Teardown handshake",
-		    (u8 *) ftie, sizeof(*ftie));
+		    (u8 *) ftie, pos - (u8 *) ftie);
 
 	/* compute MIC before sending */
 	wpa_tdls_linkid(sm, peer, &lnkid);
@@ -705,6 +732,50 @@
 }
 
 
+int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
+{
+	struct wpa_tdls_peer *peer;
+
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return -1;
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer == NULL) {
+		wpa_printf(MSG_DEBUG, "TDLS: Could not find peer " MACSTR
+		   " for link Teardown", MAC2STR(addr));
+		return -1;
+	}
+
+	if (!peer->tpk_success) {
+		wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+		   " not connected - cannot Teardown link", MAC2STR(addr));
+		return -1;
+	}
+
+	return wpa_tdls_do_teardown(sm, peer, reason_code, 0);
+}
+
+
+void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr)
+{
+	struct wpa_tdls_peer *peer;
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer) {
+		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
+		wpa_tdls_peer_free(sm, peer);
+	}
+}
+
+
 static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
 				  const u8 *buf, size_t len)
 {
@@ -802,6 +873,26 @@
 }
 
 
+static struct wpa_tdls_peer *
+wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr)
+{
+	struct wpa_tdls_peer *peer;
+
+	wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR,
+		   MAC2STR(addr));
+
+	peer = os_zalloc(sizeof(*peer));
+	if (peer == NULL)
+		return NULL;
+
+	os_memcpy(peer->addr, addr, ETH_ALEN);
+	peer->next = sm->tdls;
+	sm->tdls = peer;
+
+	return peer;
+}
+
+
 static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm,
 				struct wpa_tdls_peer *peer)
 {
@@ -972,7 +1063,7 @@
 		   "Handshake Message 1 (peer " MACSTR ")",
 		   MAC2STR(peer->addr));
 
-	wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 0, 0,
+	wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 1, 0,
 			  rbuf, pos - rbuf);
 	os_free(rbuf);
 
@@ -1144,6 +1235,105 @@
 }
 
 
+static int wpa_tdls_send_discovery_response(struct wpa_sm *sm,
+					    struct wpa_tdls_peer *peer,
+					    u8 dialog_token)
+{
+	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response "
+		   "(peer " MACSTR ")", MAC2STR(peer->addr));
+
+	return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
+				 dialog_token, 0, NULL, 0);
+}
+
+
+static int
+wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr,
+				   const u8 *buf, size_t len)
+{
+	struct wpa_eapol_ie_parse kde;
+	const struct wpa_tdls_lnkid *lnkid;
+	struct wpa_tdls_peer *peer;
+	size_t min_req_len = sizeof(struct wpa_tdls_frame) +
+		1 /* dialog token */ + sizeof(struct wpa_tdls_lnkid);
+	u8 dialog_token;
+
+	wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from " MACSTR,
+		   MAC2STR(addr));
+
+	if (len < min_req_len) {
+		wpa_printf(MSG_DEBUG, "TDLS Discovery Request is too short: "
+			   "%d", (int) len);
+		return -1;
+	}
+
+	dialog_token = buf[sizeof(struct wpa_tdls_frame)];
+
+	if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1,
+				     len - (sizeof(struct wpa_tdls_frame) + 1),
+				     &kde) < 0)
+		return -1;
+
+	if (!kde.lnkid) {
+		wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery "
+			   "Request");
+		return -1;
+	}
+
+	lnkid = (const struct wpa_tdls_lnkid *) kde.lnkid;
+
+	if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from different "
+			   " BSS " MACSTR, MAC2STR(lnkid->bssid));
+		return -1;
+	}
+
+	peer = wpa_tdls_add_peer(sm, addr);
+	if (peer == NULL)
+		return -1;
+
+	return wpa_tdls_send_discovery_response(sm, peer, dialog_token);
+}
+
+
+int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr)
+{
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer "
+		   MACSTR, MAC2STR(addr));
+	return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST,
+				 1, 0, NULL, 0);
+}
+
+
+static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde,
+			   struct wpa_tdls_peer *peer)
+{
+	if (!kde->supp_rates) {
+		wpa_printf(MSG_DEBUG, "TDLS: No supported rates received");
+		return -1;
+	}
+
+	peer->supp_rates_len = kde->supp_rates_len - 2;
+	if (peer->supp_rates_len > IEEE80211_MAX_SUPP_RATES)
+		peer->supp_rates_len = IEEE80211_MAX_SUPP_RATES;
+	os_memcpy(peer->supp_rates, kde->supp_rates + 2, peer->supp_rates_len);
+
+	if (kde->ext_supp_rates) {
+		int clen = kde->ext_supp_rates_len - 2;
+		if (peer->supp_rates_len + clen > IEEE80211_MAX_SUPP_RATES)
+			clen = IEEE80211_MAX_SUPP_RATES - peer->supp_rates_len;
+		os_memcpy(peer->supp_rates + peer->supp_rates_len,
+			  kde->ext_supp_rates + 2, clen);
+		peer->supp_rates_len += clen;
+	}
+
+	return 0;
+}
+
+
 static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
 				   const u8 *buf, size_t len)
 {
@@ -1166,6 +1356,7 @@
 	u16 ielen;
 	u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
 	int tdls_prohibited = sm->tdls_prohibited;
+	int existing_peer = 0;
 
 	if (len < 3 + 3)
 		return -1;
@@ -1178,7 +1369,22 @@
 
 	wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken);
 
-	cpos += 2; /* capability information */
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) {
+			existing_peer = 1;
+			break;
+		}
+	}
+
+	if (peer == NULL) {
+		peer = wpa_tdls_add_peer(sm, src_addr);
+		if (peer == NULL)
+			goto error;
+	}
+
+	/* capability information */
+	peer->capability = WPA_GET_LE16(cpos);
+	cpos += 2;
 
 	ielen = len - (cpos - buf); /* start of IE in buf */
 	if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) {
@@ -1203,6 +1409,9 @@
 	wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR,
 		   MAC2STR(src_addr));
 
+	if (copy_supp_rates(&kde, peer) < 0)
+		goto error;
+
 #ifdef CONFIG_TDLS_TESTING
 	if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
 		for (peer = sm->tdls; peer; peer = peer->next) {
@@ -1210,12 +1419,9 @@
 				break;
 		}
 		if (peer == NULL) {
-			peer = os_zalloc(sizeof(*peer));
+			peer = wpa_tdls_add_peer(sm, src_addr);
 			if (peer == NULL)
 				goto error;
-			os_memcpy(peer->addr, src_addr, ETH_ALEN);
-			peer->next = sm->tdls;
-			sm->tdls = peer;
 		}
 		wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of "
 			   "TDLS setup - send own request");
@@ -1302,26 +1508,10 @@
 	}
 
 skip_rsn:
-	/* Find existing entry and if found, use that instead of adding
-	 * a new one; how to handle the case where both ends initiate at the
+	/* If found, use existing entry instead of adding a new one;
+	 * how to handle the case where both ends initiate at the
 	 * same time? */
-	for (peer = sm->tdls; peer; peer = peer->next) {
-		if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
-			break;
-	}
-
-	if (peer == NULL) {
-		wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
-			   "peer, creating one for " MACSTR,
-			   MAC2STR(src_addr));
-		peer = os_malloc(sizeof(*peer));
-		if (peer == NULL)
-			goto error;
-		os_memset(peer, 0, sizeof(*peer));
-		os_memcpy(peer->addr, src_addr, ETH_ALEN);
-		peer->next = sm->tdls;
-		sm->tdls = peer;
-	} else {
+	if (existing_peer) {
 		if (peer->tpk_success) {
 			wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
 				   "direct link is enabled - tear down the "
@@ -1332,7 +1522,11 @@
 			 * some drivers handling the new request frame. */
 			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
 #else
-			wpa_tdls_del_key(sm, peer);
+			if (sm->tdls_external_setup)
+				wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+						 src_addr);
+			else
+				wpa_tdls_del_key(sm, peer);
 #endif
 			wpa_tdls_peer_free(sm, peer);
 		}
@@ -1360,6 +1554,19 @@
 		}
 	}
 
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
+		if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) {
+			/*
+			 * The request frame from us is going to win, so do not
+			 * replace information based on this request frame from
+			 * the peer.
+			 */
+			goto skip_rsn_check;
+		}
+	}
+#endif /* CONFIG_TDLS_TESTING */
+
 	peer->initiator = 0; /* Need to check */
 	peer->dtoken = dtoken;
 
@@ -1433,8 +1640,14 @@
 	wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
 
 skip_rsn_check:
+	/* add the peer to the driver as a "setup in progress" peer */
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+
 	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
-	wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer);
+	if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
+		wpa_tdls_disable_link(sm, peer->addr);
+		goto error;
+	}
 
 	return 0;
 
@@ -1467,6 +1680,11 @@
 	}
 #endif /* CONFIG_TDLS_TESTING */
 	}
+
+	/* add supported rates and capabilities to the TDLS peer */
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability,
+				peer->supp_rates, peer->supp_rates_len);
+
 	wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
 }
 
@@ -1510,6 +1728,8 @@
 	if (status != WLAN_STATUS_SUCCESS) {
 		wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u",
 			   status);
+		if (sm->tdls_external_setup)
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
 		return -1;
 	}
 
@@ -1522,7 +1742,10 @@
 
 	if (len < 3 + 2 + 1 + 2)
 		return -1;
-	pos += 2; /* capability information */
+
+	/* capability information */
+	peer->capability = WPA_GET_LE16(pos);
+	pos += 2;
 
 	ielen = len - (pos - buf); /* start of IE in buf */
 	if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) {
@@ -1553,6 +1776,9 @@
 		goto error;
 	}
 
+	if (copy_supp_rates(&kde, peer) < 0)
+		goto error;
+
 	if (!wpa_tdls_get_privacy(sm)) {
 		peer->rsnie_p_len = 0;
 		peer->cipher = WPA_CIPHER_NONE;
@@ -1644,6 +1870,8 @@
 		/* Discard the frame */
 		wpa_tdls_del_key(sm, peer);
 		wpa_tdls_peer_free(sm, peer);
+		if (sm->tdls_external_setup)
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
 		return -1;
 	}
 
@@ -1663,6 +1891,8 @@
 error:
 	wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken,
 			    status);
+	if (sm->tdls_external_setup)
+		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
 	return -1;
 }
 
@@ -1703,6 +1933,8 @@
 	if (status != 0) {
 		wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u",
 			   status);
+		if (sm->tdls_external_setup)
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
 		return -1;
 	}
 	pos += 2 /* status code */ + 1 /* dialog token */;
@@ -1775,6 +2007,8 @@
 	if (lifetime != peer->lifetime) {
 		wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in "
 			   "TPK M3 (expected %u)", lifetime, peer->lifetime);
+		if (sm->tdls_external_setup)
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
 		return -1;
 	}
 
@@ -1823,7 +2057,7 @@
 	struct wpa_tdls_peer *peer;
 	int tdls_prohibited = sm->tdls_prohibited;
 
-	if (sm->tdls_disabled)
+	if (sm->tdls_disabled || !sm->tdls_supported)
 		return -1;
 
 #ifdef CONFIG_TDLS_TESTING
@@ -1849,20 +2083,22 @@
 	}
 
 	if (peer == NULL) {
-		wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
-			   "peer, creating one for " MACSTR, MAC2STR(addr));
-		peer = os_malloc(sizeof(*peer));
+		peer = wpa_tdls_add_peer(sm, addr);
 		if (peer == NULL)
 			return -1;
-		os_memset(peer, 0, sizeof(*peer));
-		os_memcpy(peer->addr, addr, ETH_ALEN);
-		peer->next = sm->tdls;
-		sm->tdls = peer;
 	}
 
 	peer->initiator = 1;
 
-	return wpa_tdls_send_tpk_m1(sm, peer);
+	/* add the peer to the driver as a "setup in progress" peer */
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+
+	if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
+		wpa_tdls_disable_link(sm, peer->addr);
+		return -1;
+	}
+
+	return 0;
 }
 
 
@@ -1870,7 +2106,7 @@
 {
 	struct wpa_tdls_peer *peer;
 
-	if (sm->tdls_disabled)
+	if (sm->tdls_disabled || !sm->tdls_supported)
 		return -1;
 
 	for (peer = sm->tdls; peer; peer = peer->next) {
@@ -1881,6 +2117,14 @@
 	if (peer == NULL || !peer->tpk_success)
 		return -1;
 
+	if (sm->tdls_external_setup) {
+		/*
+		 * Disable previous link to allow renegotiation to be completed
+		 * on AP path.
+		 */
+		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+	}
+
 	return wpa_tdls_start(sm, addr);
 }
 
@@ -1899,8 +2143,9 @@
 	wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation",
 		    buf, len);
 
-	if (sm->tdls_disabled) {
-		wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled");
+	if (sm->tdls_disabled || !sm->tdls_supported) {
+		wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled "
+			   "or unsupported by driver");
 		return;
 	}
 
@@ -1937,6 +2182,9 @@
 	case WLAN_TDLS_TEARDOWN:
 		wpa_tdls_recv_teardown(sm, src_addr, buf, len);
 		break;
+	case WLAN_TDLS_DISCOVERY_REQUEST:
+		wpa_tdls_process_discovery_request(sm, src_addr, buf, len);
+		break;
 	default:
 		/* Kernel code will process remaining frames */
 		wpa_printf(MSG_DEBUG, "TDLS: Ignore TDLS frame action code %u",
@@ -1969,6 +2217,21 @@
 		return -1;
 	}
 
+	/*
+	 * Drivers that support TDLS but don't implement the get_capa callback
+	 * are assumed to perform everything internally
+	 */
+	if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported,
+				 &sm->tdls_external_setup) < 0) {
+		sm->tdls_supported = 1;
+		sm->tdls_external_setup = 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "TDLS: TDLS operation%s supported by "
+		   "driver", sm->tdls_supported ? "" : " not");
+	wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup",
+		   sm->tdls_external_setup ? "external" : "internal");
+
 	return 0;
 }
 
@@ -2067,3 +2330,9 @@
 	wpa_printf(MSG_DEBUG, "TDLS: %s", enabled ? "enabled" : "disabled");
 	sm->tdls_disabled = !enabled;
 }
+
+
+int wpa_tdls_is_external_setup(struct wpa_sm *sm)
+{
+	return sm->tdls_external_setup;
+}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 7c0ac87..f35f9ee 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -396,7 +396,8 @@
 		const u8 *_buf = (const u8 *) (key + 1);
 		size_t len = WPA_GET_BE16(key->key_data_length);
 		wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len);
-		wpa_supplicant_parse_ies(_buf, len, &ie);
+		if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0)
+			goto failed;
 		if (ie.pmkid) {
 			wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
 				    "Authenticator", ie.pmkid, PMKID_LEN);
@@ -476,7 +477,7 @@
 		 * Start preauthentication after a short wait to avoid a
 		 * possible race condition between the data receive and key
 		 * configuration after the 4-Way Handshake. This increases the
-		 * likelyhood of the first preauth EAPOL-Start frame getting to
+		 * likelihood of the first preauth EAPOL-Start frame getting to
 		 * the target AP.
 		 */
 		eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL);
@@ -1085,7 +1086,8 @@
 	pos = (const u8 *) (key + 1);
 	len = WPA_GET_BE16(key->key_data_length);
 	wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
-	wpa_supplicant_parse_ies(pos, len, &ie);
+	if (wpa_supplicant_parse_ies(pos, len, &ie) < 0)
+		goto failed;
 	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: GTK IE in unencrypted key data");
@@ -1174,6 +1176,8 @@
 		goto failed;
 	}
 
+	wpa_sm_set_rekey_offload(sm);
+
 	return;
 
 failed:
@@ -1191,7 +1195,8 @@
 	struct wpa_eapol_ie_parse ie;
 
 	wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen);
-	wpa_supplicant_parse_ies(keydata, keydatalen, &ie);
+	if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0)
+		return -1;
 	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: GTK IE in unencrypted key data");
@@ -1392,6 +1397,8 @@
 			MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
 		wpa_sm_cancel_auth_timeout(sm);
 		wpa_sm_set_state(sm, WPA_COMPLETED);
+
+		wpa_sm_set_rekey_offload(sm);
 	} else {
 		wpa_supplicant_key_neg_complete(sm, sm->bssid,
 						key_info &
@@ -2265,8 +2272,6 @@
 		sm->ssid_len = 0;
 		sm->wpa_ptk_rekey = 0;
 	}
-	if (config == NULL || config->network_ctx != sm->network_ctx)
-		pmksa_cache_notify_reconfig(sm->pmksa);
 }
 
 
@@ -2644,3 +2649,17 @@
 		return 0;
 	return sm->ptk_set;
 }
+
+
+void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
+{
+	os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
+}
+
+
+void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
+{
+#ifndef CONFIG_NO_WPA2
+	pmksa_cache_flush(sm->pmksa, network_ctx);
+#endif /* CONFIG_NO_WPA2 */
+}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 111597c..4c1750f 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -56,11 +56,18 @@
 			      const u8 *ies, size_t ies_len);
 	int (*mark_authenticated)(void *ctx, const u8 *target_ap);
 #ifdef CONFIG_TDLS
+	int (*tdls_get_capa)(void *ctx, int *tdls_supported,
+			     int *tdls_ext_setup);
 	int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
 			      u8 action_code, u8 dialog_token,
 			      u16 status_code, const u8 *buf, size_t len);
 	int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
+	int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
+				u16 capability, const u8 *supp_rates,
+				size_t supp_rates_len);
 #endif /* CONFIG_TDLS */
+	void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
+				  const u8 *replay_ctr);
 };
 
 
@@ -132,6 +139,10 @@
 void wpa_sm_drop_sa(struct wpa_sm *sm);
 int wpa_sm_has_ptk(struct wpa_sm *sm);
 
+void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
+
+void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
+
 #else /* CONFIG_NO_WPA */
 
 static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
@@ -277,6 +288,16 @@
 	return 0;
 }
 
+static inline void wpa_sm_update_replay_ctr(struct wpa_sm *sm,
+					    const u8 *replay_ctr)
+{
+}
+
+static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm,
+					    void *network_ctx)
+{
+}
+
 #endif /* CONFIG_NO_WPA */
 
 #ifdef CONFIG_PEERKEY
@@ -342,10 +363,13 @@
 void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
 int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr);
 int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr);
-int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr,
-				  u16 reason_code);
+int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr);
 int wpa_tdls_init(struct wpa_sm *sm);
 void wpa_tdls_deinit(struct wpa_sm *sm);
 void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
+void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_is_external_setup(struct wpa_sm *sm);
 
 #endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index da6e966..dbf5996 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -21,35 +21,9 @@
 #include "common/ieee802_11_common.h"
 #include "wpa.h"
 #include "wpa_i.h"
-#include "wpa_ie.h"
 
 #ifdef CONFIG_IEEE80211R
 
-struct wpa_ft_ies {
-	const u8 *mdie;
-	size_t mdie_len;
-	const u8 *ftie;
-	size_t ftie_len;
-	const u8 *r1kh_id;
-	const u8 *gtk;
-	size_t gtk_len;
-	const u8 *r0kh_id;
-	size_t r0kh_id_len;
-	const u8 *rsn;
-	size_t rsn_len;
-	const u8 *rsn_pmkid;
-	const u8 *tie;
-	size_t tie_len;
-	const u8 *igtk;
-	size_t igtk_len;
-	const u8 *ric;
-	size_t ric_len;
-};
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-			    struct wpa_ft_ies *parse);
-
-
 int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
 		      const struct wpa_eapol_key *key,
 		      struct wpa_ptk *ptk, size_t ptk_len)
@@ -347,155 +321,6 @@
 }
 
 
-static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
-			     struct wpa_ft_ies *parse)
-{
-	const u8 *end, *pos;
-
-	parse->ftie = ie;
-	parse->ftie_len = ie_len;
-
-	pos = ie + sizeof(struct rsn_ftie);
-	end = ie + ie_len;
-
-	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-		switch (pos[0]) {
-		case FTIE_SUBELEM_R1KH_ID:
-			if (pos[1] != FT_R1KH_ID_LEN) {
-				wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
-					   "length in FTIE: %d", pos[1]);
-				return -1;
-			}
-			parse->r1kh_id = pos + 2;
-			break;
-		case FTIE_SUBELEM_GTK:
-			parse->gtk = pos + 2;
-			parse->gtk_len = pos[1];
-			break;
-		case FTIE_SUBELEM_R0KH_ID:
-			if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
-				wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
-					   "length in FTIE: %d", pos[1]);
-				return -1;
-			}
-			parse->r0kh_id = pos + 2;
-			parse->r0kh_id_len = pos[1];
-			break;
-#ifdef CONFIG_IEEE80211W
-		case FTIE_SUBELEM_IGTK:
-			parse->igtk = pos + 2;
-			parse->igtk_len = pos[1];
-			break;
-#endif /* CONFIG_IEEE80211W */
-		}
-
-		pos += 2 + pos[1];
-	}
-
-	return 0;
-}
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-			    struct wpa_ft_ies *parse)
-{
-	const u8 *end, *pos;
-	struct wpa_ie_data data;
-	int ret;
-	const struct rsn_ftie *ftie;
-	int prot_ie_count = 0;
-
-	os_memset(parse, 0, sizeof(*parse));
-	if (ies == NULL)
-		return 0;
-
-	pos = ies;
-	end = ies + ies_len;
-	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-		switch (pos[0]) {
-		case WLAN_EID_RSN:
-			parse->rsn = pos + 2;
-			parse->rsn_len = pos[1];
-			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
-						   parse->rsn_len + 2,
-						   &data);
-			if (ret < 0) {
-				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
-					   "RSN IE: %d", ret);
-				return -1;
-			}
-			if (data.num_pmkid == 1 && data.pmkid)
-				parse->rsn_pmkid = data.pmkid;
-			break;
-		case WLAN_EID_MOBILITY_DOMAIN:
-			parse->mdie = pos + 2;
-			parse->mdie_len = pos[1];
-			break;
-		case WLAN_EID_FAST_BSS_TRANSITION:
-			if (pos[1] < sizeof(*ftie))
-				return -1;
-			ftie = (const struct rsn_ftie *) (pos + 2);
-			prot_ie_count = ftie->mic_control[1];
-			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
-				return -1;
-			break;
-		case WLAN_EID_TIMEOUT_INTERVAL:
-			parse->tie = pos + 2;
-			parse->tie_len = pos[1];
-			break;
-		case WLAN_EID_RIC_DATA:
-			if (parse->ric == NULL)
-				parse->ric = pos;
-		}
-
-		pos += 2 + pos[1];
-	}
-
-	if (prot_ie_count == 0)
-		return 0; /* no MIC */
-
-	/*
-	 * Check that the protected IE count matches with IEs included in the
-	 * frame.
-	 */
-	if (parse->rsn)
-		prot_ie_count--;
-	if (parse->mdie)
-		prot_ie_count--;
-	if (parse->ftie)
-		prot_ie_count--;
-	if (parse->tie)
-		prot_ie_count--;
-	if (prot_ie_count < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
-			   "the protected IE count");
-		return -1;
-	}
-
-	if (prot_ie_count == 0 && parse->ric) {
-		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
-			   "included in protected IE count");
-		return -1;
-	}
-
-	/* Determine the end of the RIC IE(s) */
-	pos = parse->ric;
-	while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
-	       prot_ie_count) {
-		prot_ie_count--;
-		pos += 2 + pos[1];
-	}
-	parse->ric_len = pos - parse->ric;
-	if (prot_ie_count) {
-		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
-			   "frame", (int) prot_ie_count);
-		return -1;
-	}
-
-	return 0;
-}
-
-
 static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
 {
 	int keylen;
@@ -950,8 +775,8 @@
 	}
 
 	count = 3;
-	if (parse.tie)
-		count++;
+	if (parse.ric)
+		count += ieee802_11_ie_count(parse.ric, parse.ric_len);
 	if (ftie->mic_control[1] != count) {
 		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
 			   "Control: received %u expected %u",
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 09a2e4f..39124c4 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -98,6 +98,15 @@
 	struct wpa_tdls_peer *tdls;
 	int tdls_prohibited;
 	int tdls_disabled;
+
+	/* The driver supports TDLS */
+	int tdls_supported;
+
+	/*
+	 * The driver requires explicit discovery/setup/teardown frames sent
+	 * to it via tdls_mgmt.
+	 */
+	int tdls_external_setup;
 #endif /* CONFIG_TDLS */
 
 #ifdef CONFIG_IEEE80211R
@@ -244,7 +253,25 @@
 	return -1;
 }
 
+static inline void wpa_sm_set_rekey_offload(struct wpa_sm *sm)
+{
+	if (!sm->ctx->set_rekey_offload)
+		return;
+	sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek,
+				   sm->ptk.kck, sm->rx_replay_counter);
+}
+
 #ifdef CONFIG_TDLS
+static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm,
+				       int *tdls_supported,
+				       int *tdls_ext_setup)
+{
+	if (sm->ctx->tdls_get_capa)
+		return sm->ctx->tdls_get_capa(sm->ctx->ctx, tdls_supported,
+					      tdls_ext_setup);
+	return -1;
+}
+
 static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
 					u8 action_code, u8 dialog_token,
 					u16 status_code, const u8 *buf,
@@ -264,6 +291,18 @@
 		return sm->ctx->tdls_oper(sm->ctx->ctx, oper, peer);
 	return -1;
 }
+
+static inline int
+wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
+			u16 capability, const u8 *supp_rates,
+			size_t supp_rates_len)
+{
+	if (sm->ctx->tdls_peer_addset)
+		return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
+						 capability, supp_rates,
+						 supp_rates_len);
+	return -1;
+}
 #endif /* CONFIG_TDLS */
 
 void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 654cc1f..cbbc54f 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -424,11 +424,19 @@
 					    pos, 2 + pos[1]);
 			}
 		} else if (*pos == WLAN_EID_LINK_ID) {
-			ie->lnkid = pos;
-			ie->lnkid_len = pos[1] + 2;
+			if (pos[1] >= 18) {
+				ie->lnkid = pos;
+				ie->lnkid_len = pos[1] + 2;
+			}
 		} else if (*pos == WLAN_EID_EXT_CAPAB) {
 			ie->ext_capab = pos;
 			ie->ext_capab_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_SUPP_RATES) {
+			ie->supp_rates = pos;
+			ie->supp_rates_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
+			ie->ext_supp_rates = pos;
+			ie->ext_supp_rates_len = pos[1] + 2;
 		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
 			ret = wpa_parse_generic(pos, end, ie);
 			if (ret < 0)
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index f939b13..c13d94c 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -51,6 +51,10 @@
 	size_t lnkid_len;
 	const u8 *ext_capab;
 	size_t ext_capab_len;
+	const u8 *supp_rates;
+	size_t supp_rates_len;
+	const u8 *ext_supp_rates;
+	size_t ext_supp_rates_len;
 };
 
 int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/src/tls/Makefile b/src/tls/Makefile
index a2da096..27cdfca 100644
--- a/src/tls/Makefile
+++ b/src/tls/Makefile
@@ -11,6 +11,8 @@
 
 CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
 CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+CFLAGS += -DCONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV12
 
 LIB_OBJS= \
 	asn1.o \
diff --git a/src/tls/libtommath.c b/src/tls/libtommath.c
index 1374264..7c9857f 100644
--- a/src/tls/libtommath.c
+++ b/src/tls/libtommath.c
@@ -572,7 +572,7 @@
 
 /* this is a shell function that calls either the normal or Montgomery
  * exptmod functions.  Originally the call to the montgomery code was
- * embedded in the normal function but that wasted alot of stack space
+ * embedded in the normal function but that wasted a lot of stack space
  * for nothing (since 99% of the time the Montgomery code would be called)
  */
 static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
@@ -2207,7 +2207,7 @@
   /* zero a as per default */
   mp_zero (a);
 
-  /* grow a to accomodate the single bit */
+  /* grow a to accommodate the single bit */
   if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
     return res;
   }
@@ -2319,7 +2319,7 @@
 }
 
 
-/* multiplies |a| * |b| and only computes upto digs digits of result
+/* multiplies |a| * |b| and only computes up to digs digits of result
  * HAC pp. 595, Algorithm 14.12  Modified so you can control how 
  * many digits of output are created.
  */
@@ -2678,7 +2678,7 @@
  *
  * Based on Algorithm 14.32 on pp.601 of HAC.
 */
-int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+static int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
 {
   int     ix, res, olduse;
   mp_word W[MP_WARRAY];
@@ -2829,7 +2829,7 @@
 {
   int     x, res, oldused;
 
-  /* grow to accomodate result */
+  /* grow to accommodate result */
   if (b->alloc < a->used + 1) {
     if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
       return res;
@@ -2891,8 +2891,8 @@
 /*
  * shifts with subtractions when the result is greater than b.
  *
- * The method is slightly modified to shift B unconditionally upto just under
- * the leading bit of b.  This saves alot of multiple precision shifting.
+ * The method is slightly modified to shift B unconditionally up to just under
+ * the leading bit of b.  This saves a lot of multiple precision shifting.
  */
 static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
 {
diff --git a/src/tls/pkcs5.c b/src/tls/pkcs5.c
index 4291b84..fd9e346 100644
--- a/src/tls/pkcs5.c
+++ b/src/tls/pkcs5.c
@@ -32,7 +32,7 @@
 };
 
 
-enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
+static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
 {
 	if (oid->len == 7 &&
 	    oid->oid[0] == 1 /* iso */ &&
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 8b7e26f..d0da588 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -1,5 +1,5 @@
 /*
- * TLSv1 client (RFC 2246)
+ * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -67,7 +67,8 @@
 		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
 		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
 			  TLS_RANDOM_LEN);
-		if (tls_prf(pre_master_secret, pre_master_secret_len,
+		if (tls_prf(conn->rl.tls_version,
+			    pre_master_secret, pre_master_secret_len,
 			    "master secret", seed, 2 * TLS_RANDOM_LEN,
 			    conn->master_secret, TLS_MASTER_SECRET_LEN)) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
@@ -80,9 +81,11 @@
 
 	os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
 	os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
-	key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
-			     conn->rl.iv_size);
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+	key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len);
+	if (conn->rl.tls_version == TLS_VERSION_1)
+		key_block_len += 2 * conn->rl.iv_size;
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
 		    "key expansion", seed, 2 * TLS_RANDOM_LEN,
 		    key_block, key_block_len)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
@@ -107,12 +110,21 @@
 	os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
 	pos += conn->rl.key_material_len;
 
-	/* client_write_IV */
-	os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
-	pos += conn->rl.iv_size;
-	/* server_write_IV */
-	os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
-	pos += conn->rl.iv_size;
+	if (conn->rl.tls_version == TLS_VERSION_1) {
+		/* client_write_IV */
+		os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
+		pos += conn->rl.iv_size;
+		/* server_write_IV */
+		os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
+		pos += conn->rl.iv_size;
+	} else {
+		/*
+		 * Use IV field to set the mask value for TLS v1.1. A fixed
+		 * mask of zero is used per the RFC 4346, 6.2.3.2 CBC Block
+		 * Cipher option 2a.
+		 */
+		os_memset(conn->rl.write_iv, 0, conn->rl.iv_size);
+	}
 
 	return 0;
 }
@@ -126,17 +138,23 @@
  * @out_len: Length of the output buffer.
  * @appl_data: Pointer to application data pointer, or %NULL if dropped
  * @appl_data_len: Pointer to variable that is set to appl_data length
+ * @need_more_data: Set to 1 if more data would be needed to complete
+ *	processing
  * Returns: Pointer to output data, %NULL on failure
  */
 u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
 			    const u8 *in_data, size_t in_len,
 			    size_t *out_len, u8 **appl_data,
-			    size_t *appl_data_len)
+			    size_t *appl_data_len, int *need_more_data)
 {
 	const u8 *pos, *end;
-	u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
+	u8 *msg = NULL, *in_msg = NULL, *in_pos, *in_end, alert, ct;
 	size_t in_msg_len;
 	int no_appl_data;
+	int used;
+
+	if (need_more_data)
+		*need_more_data = 0;
 
 	if (conn->state == CLIENT_HELLO) {
 		if (in_len)
@@ -144,6 +162,19 @@
 		return tls_send_client_hello(conn, out_len);
 	}
 
+	if (conn->partial_input) {
+		if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+				   "memory for pending record");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			goto failed;
+		}
+		wpabuf_put_data(conn->partial_input, in_data, in_len);
+		in_data = wpabuf_head(conn->partial_input);
+		in_len = wpabuf_len(conn->partial_input);
+	}
+
 	if (in_data == NULL || in_len == 0)
 		return NULL;
 
@@ -156,13 +187,33 @@
 	/* Each received packet may include multiple records */
 	while (pos < end) {
 		in_msg_len = in_len;
-		if (tlsv1_record_receive(&conn->rl, pos, end - pos,
-					 in_msg, &in_msg_len, &alert)) {
+		used = tlsv1_record_receive(&conn->rl, pos, end - pos,
+					    in_msg, &in_msg_len, &alert);
+		if (used < 0) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
 				   "record failed");
 			tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
 			goto failed;
 		}
+		if (used == 0) {
+			struct wpabuf *partial;
+			wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
+			partial = wpabuf_alloc_copy(pos, end - pos);
+			wpabuf_free(conn->partial_input);
+			conn->partial_input = partial;
+			if (conn->partial_input == NULL) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
+					   "allocate memory for pending "
+					   "record");
+				tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					  TLS_ALERT_INTERNAL_ERROR);
+				goto failed;
+			}
+			os_free(in_msg);
+			if (need_more_data)
+				*need_more_data = 1;
+			return NULL;
+		}
 		ct = pos[0];
 
 		in_pos = in_msg;
@@ -180,7 +231,7 @@
 			in_pos += in_msg_len;
 		}
 
-		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+		pos += used;
 	}
 
 	os_free(in_msg);
@@ -192,6 +243,8 @@
 failed:
 	os_free(in_msg);
 	if (conn->alert_level) {
+		wpabuf_free(conn->partial_input);
+		conn->partial_input = NULL;
 		conn->state = FAILED;
 		os_free(msg);
 		msg = tlsv1_client_send_alert(conn, conn->alert_level,
@@ -202,6 +255,11 @@
 		*out_len = 0;
 	}
 
+	if (need_more_data == NULL || !(*need_more_data)) {
+		wpabuf_free(conn->partial_input);
+		conn->partial_input = NULL;
+	}
+
 	return msg;
 }
 
@@ -227,10 +285,8 @@
 	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
 			in_data, in_len);
 
-	os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
-
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
-			      out_data, out_len, in_len, &rlen) < 0) {
+			      out_data, out_len, in_data, in_len, &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
@@ -246,58 +302,116 @@
  * @conn: TLSv1 client connection data from tlsv1_client_init()
  * @in_data: Pointer to input buffer (encrypted TLS data)
  * @in_len: Input buffer length
- * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
- * @out_len: Maximum out_data length
- * Returns: Number of bytes written to out_data, -1 on failure
+ * @need_more_data: Set to 1 if more data would be needed to complete
+ *	processing
+ * Returns: Decrypted data or %NULL on failure
  *
  * This function is used after TLS handshake has been completed successfully to
  * receive data from the encrypted tunnel.
  */
-int tlsv1_client_decrypt(struct tlsv1_client *conn,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t out_len)
+struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
+				     const u8 *in_data, size_t in_len,
+				     int *need_more_data)
 {
 	const u8 *in_end, *pos;
-	int res;
-	u8 alert, *out_end, *out_pos;
+	int used;
+	u8 alert, *out_pos, ct;
 	size_t olen;
+	struct wpabuf *buf = NULL;
+
+	if (need_more_data)
+		*need_more_data = 0;
+
+	if (conn->partial_input) {
+		if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+				   "memory for pending record");
+			alert = TLS_ALERT_INTERNAL_ERROR;
+			goto fail;
+		}
+		wpabuf_put_data(conn->partial_input, in_data, in_len);
+		in_data = wpabuf_head(conn->partial_input);
+		in_len = wpabuf_len(conn->partial_input);
+	}
 
 	pos = in_data;
 	in_end = in_data + in_len;
-	out_pos = out_data;
-	out_end = out_data + out_len;
 
 	while (pos < in_end) {
-		if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
-				   "0x%x", pos[0]);
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_UNEXPECTED_MESSAGE);
-			return -1;
+		ct = pos[0];
+		if (wpabuf_resize(&buf, in_end - pos) < 0) {
+			alert = TLS_ALERT_INTERNAL_ERROR;
+			goto fail;
 		}
-
-		olen = out_end - out_pos;
-		res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
-					   out_pos, &olen, &alert);
-		if (res < 0) {
+		out_pos = wpabuf_put(buf, 0);
+		olen = wpabuf_tailroom(buf);
+		used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+					    out_pos, &olen, &alert);
+		if (used < 0) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
 				   "failed");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
-			return -1;
+			goto fail;
 		}
-		out_pos += olen;
-		if (out_pos > out_end) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
-				   "for processing the received record");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_INTERNAL_ERROR);
-			return -1;
+		if (used == 0) {
+			struct wpabuf *partial;
+			wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
+			partial = wpabuf_alloc_copy(pos, in_end - pos);
+			wpabuf_free(conn->partial_input);
+			conn->partial_input = partial;
+			if (conn->partial_input == NULL) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
+					   "allocate memory for pending "
+					   "record");
+				alert = TLS_ALERT_INTERNAL_ERROR;
+				goto fail;
+			}
+			if (need_more_data)
+				*need_more_data = 1;
+			return buf;
 		}
 
-		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+		if (ct == TLS_CONTENT_TYPE_ALERT) {
+			if (olen < 2) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Alert "
+					   "underflow");
+				alert = TLS_ALERT_DECODE_ERROR;
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+				   out_pos[0], out_pos[1]);
+			if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
+				/* Continue processing */
+				pos += used;
+				continue;
+			}
+
+			alert = out_pos[1];
+			goto fail;
+		}
+
+		if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
+				   "0x%x when decrypting application data",
+				   pos[0]);
+			alert = TLS_ALERT_UNEXPECTED_MESSAGE;
+			goto fail;
+		}
+
+		wpabuf_put(buf, olen);
+
+		pos += used;
 	}
 
-	return out_pos - out_data;
+	wpabuf_free(conn->partial_input);
+	conn->partial_input = NULL;
+	return buf;
+
+fail:
+	wpabuf_free(buf);
+	wpabuf_free(conn->partial_input);
+	conn->partial_input = NULL;
+	tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+	return NULL;
 }
 
 
@@ -352,14 +466,18 @@
 	count = 0;
 	suites = conn->cipher_suites;
 #ifndef CONFIG_CRYPTO_INTERNAL
+	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
 	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
 #endif /* CONFIG_CRYPTO_INTERNAL */
+	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
 	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
 	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
 	conn->num_cipher_suites = count;
 
+	conn->rl.tls_version = TLS_VERSION;
+
 	return conn;
 }
 
@@ -378,6 +496,7 @@
 	os_free(conn->client_hello_ext);
 	tlsv1_client_free_dh(conn);
 	tlsv1_cred_free(conn->cred);
+	wpabuf_free(conn->partial_input);
 	os_free(conn);
 }
 
@@ -421,7 +540,8 @@
 			  TLS_RANDOM_LEN);
 	}
 
-	return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+	return tls_prf(conn->rl.tls_version,
+		       conn->master_secret, TLS_MASTER_SECRET_LEN,
 		       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
 }
 
@@ -453,15 +573,24 @@
 	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
 		cipher = "DES-CBC3-SHA";
 		break;
+	case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+		cipher = "ADH-AES-128-SHA256";
+		break;
 	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
 		cipher = "ADH-AES-128-SHA";
 		break;
 	case TLS_RSA_WITH_AES_256_CBC_SHA:
 		cipher = "AES-256-SHA";
 		break;
+	case TLS_RSA_WITH_AES_256_CBC_SHA256:
+		cipher = "AES-256-SHA256";
+		break;
 	case TLS_RSA_WITH_AES_128_CBC_SHA:
 		cipher = "AES-128-SHA";
 		break;
+	case TLS_RSA_WITH_AES_128_CBC_SHA256:
+		cipher = "AES-128-SHA256";
+		break;
 	default:
 		return -1;
 	}
@@ -613,8 +742,10 @@
 		count = 0;
 		suites = conn->cipher_suites;
 #ifndef CONFIG_CRYPTO_INTERNAL
+		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA256;
 		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
 #endif /* CONFIG_CRYPTO_INTERNAL */
+		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA256;
 		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
 		suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
 		suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
diff --git a/src/tls/tlsv1_client.h b/src/tls/tlsv1_client.h
index a620d62..ef5e694 100644
--- a/src/tls/tlsv1_client.h
+++ b/src/tls/tlsv1_client.h
@@ -1,5 +1,5 @@
 /*
- * TLSv1 client (RFC 2246)
+ * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -29,13 +29,13 @@
 u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
 			    const u8 *in_data, size_t in_len,
 			    size_t *out_len, u8 **appl_data,
-			    size_t *appl_data_len);
+			    size_t *appl_data_len, int *need_more_data);
 int tlsv1_client_encrypt(struct tlsv1_client *conn,
 			 const u8 *in_data, size_t in_len,
 			 u8 *out_data, size_t out_len);
-int tlsv1_client_decrypt(struct tlsv1_client *conn,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t out_len);
+struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
+				     const u8 *in_data, size_t in_len,
+				     int *need_more_data);
 int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
 			    size_t buflen);
 int tlsv1_client_shutdown(struct tlsv1_client *conn);
diff --git a/src/tls/tlsv1_client_i.h b/src/tls/tlsv1_client_i.h
index f091bcf..92912ca 100644
--- a/src/tls/tlsv1_client_i.h
+++ b/src/tls/tlsv1_client_i.h
@@ -68,6 +68,8 @@
 
 	tlsv1_client_session_ticket_cb session_ticket_cb;
 	void *session_ticket_cb_ctx;
+
+	struct wpabuf *partial_input;
 };
 
 
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index faa891a..eb0cbef 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 client - read handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "crypto/tls.h"
 #include "x509v3.h"
 #include "tlsv1_common.h"
@@ -38,6 +39,7 @@
 	const u8 *pos, *end;
 	size_t left, len, i;
 	u16 cipher_suite;
+	u16 tls_version;
 
 	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
@@ -79,15 +81,20 @@
 	/* ProtocolVersion server_version */
 	if (end - pos < 2)
 		goto decode_error;
-	if (WPA_GET_BE16(pos) != TLS_VERSION) {
+	tls_version = WPA_GET_BE16(pos);
+	if (!tls_version_ok(tls_version)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
-			   "ServerHello");
+			   "ServerHello %u.%u", pos[0], pos[1]);
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_PROTOCOL_VERSION);
 		return -1;
 	}
 	pos += 2;
 
+	wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
+		   tls_version_str(tls_version));
+	conn->rl.tls_version = tls_version;
+
 	/* Random random */
 	if (end - pos < TLS_RANDOM_LEN)
 		goto decode_error;
@@ -816,6 +823,21 @@
 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
 		    pos, TLS_VERIFY_DATA_LEN);
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_server == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
+		    < 0) {
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			conn->verify.sha256_server = NULL;
+			return -1;
+		}
+		conn->verify.sha256_server = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
 	hlen = MD5_MAC_LEN;
 	if (conn->verify.md5_server == NULL ||
 	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
@@ -837,9 +859,15 @@
 		return -1;
 	}
 	conn->verify.sha1_server = NULL;
+	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
 
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "server finished", hash, hlen,
 		    verify_data, TLS_VERIFY_DATA_LEN)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index 0898df9..35a238b 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 client - write handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "crypto/tls.h"
 #include "crypto/random.h"
 #include "x509v3.h"
@@ -116,7 +117,8 @@
 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, out_len) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      out_len) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
@@ -192,7 +194,8 @@
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
@@ -413,7 +416,8 @@
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
@@ -433,7 +437,7 @@
 {
 	u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
 	size_t rlen, hlen, clen;
-	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
+	u8 hash[100], *hpos;
 	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
 
 	pos = *msgpos;
@@ -473,6 +477,40 @@
 
 	hpos = hash;
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version == TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_cert == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
+		    0) {
+			conn->verify.sha256_cert = NULL;
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		conn->verify.sha256_cert = NULL;
+
+		/*
+		 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+		 *
+		 * DigestInfo ::= SEQUENCE {
+		 *   digestAlgorithm DigestAlgorithm,
+		 *   digest OCTET STRING
+		 * }
+		 *
+		 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+		 *
+		 * DER encoded DigestInfo for SHA256 per RFC 3447:
+		 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+		 * H
+		 */
+		os_memmove(hash + 19, hash, hlen);
+		hlen += 19;
+		os_memcpy(hash, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
+			  "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
+	} else {
+#endif /* CONFIG_TLSV12 */
+
 	if (alg == SIGN_ALG_RSA) {
 		hlen = MD5_MAC_LEN;
 		if (conn->verify.md5_cert == NULL ||
@@ -503,8 +541,29 @@
 	if (alg == SIGN_ALG_RSA)
 		hlen += MD5_MAC_LEN;
 
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		/*
+		 * RFC 5246, 4.7:
+		 * TLS v1.2 adds explicit indication of the used signature and
+		 * hash algorithms.
+		 *
+		 * struct {
+		 *   HashAlgorithm hash;
+		 *   SignatureAlgorithm signature;
+		 * } SignatureAndHashAlgorithm;
+		 */
+		*pos++ = TLS_HASH_ALG_SHA256;
+		*pos++ = TLS_SIGN_ALG_RSA;
+	}
+#endif /* CONFIG_TLSV12 */
+
 	/*
 	 * RFC 2246, 4.7:
 	 * In digital signing, one-way hash functions are used as input for a
@@ -534,7 +593,8 @@
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
@@ -553,17 +613,16 @@
 static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
 					       u8 **msgpos, u8 *end)
 {
-	u8 *pos, *rhdr;
 	size_t rlen;
-
-	pos = *msgpos;
+	u8 payload[1];
 
 	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-	*pos = TLS_CHANGE_CIPHER_SPEC;
+
+	payload[0] = TLS_CHANGE_CIPHER_SPEC;
+
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
-			      rhdr, end - rhdr, 1, &rlen) < 0) {
+			      *msgpos, end - *msgpos, payload, sizeof(payload),
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
@@ -578,7 +637,7 @@
 		return -1;
 	}
 
-	*msgpos = rhdr + rlen;
+	*msgpos += rlen;
 
 	return 0;
 }
@@ -587,17 +646,30 @@
 static int tls_write_client_finished(struct tlsv1_client *conn,
 				     u8 **msgpos, u8 *end)
 {
-	u8 *pos, *rhdr, *hs_start, *hs_length;
+	u8 *pos, *hs_start;
 	size_t rlen, hlen;
-	u8 verify_data[TLS_VERIFY_DATA_LEN];
+	u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
 	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
 
-	pos = *msgpos;
-
 	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
 
 	/* Encrypted Handshake Message: Finished */
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_client == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
+		    < 0) {
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			conn->verify.sha256_client = NULL;
+			return -1;
+		}
+		conn->verify.sha256_client = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
 	hlen = MD5_MAC_LEN;
 	if (conn->verify.md5_client == NULL ||
 	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
@@ -619,43 +691,44 @@
 		return -1;
 	}
 	conn->verify.sha1_client = NULL;
+	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
 
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
-		    verify_data, TLS_VERIFY_DATA_LEN)) {
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "client finished", hash, hlen,
+		    verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
 		return -1;
 	}
 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
-			verify_data, TLS_VERIFY_DATA_LEN);
+			verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
 
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
 	/* Handshake */
-	hs_start = pos;
+	pos = hs_start = verify_data;
 	/* HandshakeType msg_type */
 	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
+	/* uint24 length */
+	WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
 	pos += 3;
-	os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
-	pos += TLS_VERIFY_DATA_LEN;
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+	pos += TLS_VERIFY_DATA_LEN; /* verify_data already in place */
 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      *msgpos, end - *msgpos, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
 		return -1;
 	}
 
-	pos = rhdr + rlen;
-
-	*msgpos = pos;
+	*msgpos += rlen;
 
 	return 0;
 }
@@ -778,7 +851,8 @@
 	/* ContentType type */
 	*pos++ = TLS_CONTENT_TYPE_ALERT;
 	/* ProtocolVersion version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
+	WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
+		     TLS_VERSION);
 	pos += 2;
 	/* uint16 length (to be filled) */
 	length = pos;
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index 2f9dd0f..871359a 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 common routines
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -15,6 +15,8 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "x509v3.h"
 #include "tlsv1_common.h"
 
@@ -50,7 +52,15 @@
 	{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
 	  TLS_HASH_SHA },
 	{ TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
-	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA }
+	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
+	{ TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
+	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+	{ TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
+	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
+	{ TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon,
+	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+	{ TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
+	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }
 };
 
 #define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
@@ -202,6 +212,19 @@
 		tls_verify_hash_free(verify);
 		return -1;
 	}
+#ifdef CONFIG_TLSV12
+	verify->sha256_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+						 0);
+	verify->sha256_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+						 0);
+	verify->sha256_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+					       0);
+	if (verify->sha256_client == NULL || verify->sha256_server == NULL ||
+	    verify->sha256_cert == NULL) {
+		tls_verify_hash_free(verify);
+		return -1;
+	}
+#endif /* CONFIG_TLSV12 */
 	return 0;
 }
 
@@ -221,6 +244,14 @@
 		crypto_hash_update(verify->md5_cert, buf, len);
 		crypto_hash_update(verify->sha1_cert, buf, len);
 	}
+#ifdef CONFIG_TLSV12
+	if (verify->sha256_client)
+		crypto_hash_update(verify->sha256_client, buf, len);
+	if (verify->sha256_server)
+		crypto_hash_update(verify->sha256_server, buf, len);
+	if (verify->sha256_cert)
+		crypto_hash_update(verify->sha256_cert, buf, len);
+#endif /* CONFIG_TLSV12 */
 }
 
 
@@ -238,4 +269,60 @@
 	verify->sha1_client = NULL;
 	verify->sha1_server = NULL;
 	verify->sha1_cert = NULL;
+#ifdef CONFIG_TLSV12
+	crypto_hash_finish(verify->sha256_client, NULL, NULL);
+	crypto_hash_finish(verify->sha256_server, NULL, NULL);
+	crypto_hash_finish(verify->sha256_cert, NULL, NULL);
+	verify->sha256_client = NULL;
+	verify->sha256_server = NULL;
+	verify->sha256_cert = NULL;
+#endif /* CONFIG_TLSV12 */
+}
+
+
+int tls_version_ok(u16 ver)
+{
+	if (ver == TLS_VERSION_1)
+		return 1;
+#ifdef CONFIG_TLSV11
+	if (ver == TLS_VERSION_1_1)
+		return 1;
+#endif /* CONFIG_TLSV11 */
+#ifdef CONFIG_TLSV12
+	if (ver == TLS_VERSION_1_2)
+		return 1;
+#endif /* CONFIG_TLSV12 */
+
+	return 0;
+}
+
+
+const char * tls_version_str(u16 ver)
+{
+	switch (ver) {
+	case TLS_VERSION_1:
+		return "1.0";
+	case TLS_VERSION_1_1:
+		return "1.1";
+	case TLS_VERSION_1_2:
+		return "1.2";
+	}
+
+	return "?";
+}
+
+
+int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
+	    const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+#ifdef CONFIG_TLSV12
+	if (ver >= TLS_VERSION_1_2) {
+		tls_prf_sha256(secret, secret_len, label, seed, seed_len,
+			       out, outlen);
+		return 0;
+	}
+#endif /* CONFIG_TLSV12 */
+
+	return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
+				outlen);
 }
diff --git a/src/tls/tlsv1_common.h b/src/tls/tlsv1_common.h
index 763a4af..027daa4 100644
--- a/src/tls/tlsv1_common.h
+++ b/src/tls/tlsv1_common.h
@@ -1,6 +1,6 @@
 /*
  * TLSv1 common definitions
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,7 +17,18 @@
 
 #include "crypto/crypto.h"
 
-#define TLS_VERSION 0x0301 /* TLSv1 */
+#define TLS_VERSION_1 0x0301 /* TLSv1 */
+#define TLS_VERSION_1_1 0x0302 /* TLSv1.1 */
+#define TLS_VERSION_1_2 0x0303 /* TLSv1.2 */
+#ifdef CONFIG_TLSV12
+#define TLS_VERSION TLS_VERSION_1_2
+#else /* CONFIG_TLSV12 */
+#ifdef CONFIG_TLSV11
+#define TLS_VERSION TLS_VERSION_1_1
+#else /* CONFIG_TLSV11 */
+#define TLS_VERSION TLS_VERSION_1
+#endif /* CONFIG_TLSV11 */
+#endif /* CONFIG_TLSV12 */
 #define TLS_RANDOM_LEN 32
 #define TLS_PRE_MASTER_SECRET_LEN 48
 #define TLS_MASTER_SECRET_LEN 48
@@ -82,10 +93,42 @@
 #define TLS_DHE_DSS_WITH_AES_256_CBC_SHA	0x0038 /* RFC 3268 */
 #define TLS_DHE_RSA_WITH_AES_256_CBC_SHA	0x0039 /* RFC 3268 */
 #define TLS_DH_anon_WITH_AES_256_CBC_SHA	0x003A /* RFC 3268 */
+#define TLS_RSA_WITH_NULL_SHA256		0x003B /* RFC 5246 */
+#define TLS_RSA_WITH_AES_128_CBC_SHA256		0x003C /* RFC 5246 */
+#define TLS_RSA_WITH_AES_256_CBC_SHA256		0x003D /* RFC 5246 */
+#define TLS_DH_DSS_WITH_AES_128_CBC_SHA256	0x003E /* RFC 5246 */
+#define TLS_DH_RSA_WITH_AES_128_CBC_SHA256	0x003F /* RFC 5246 */
+#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA256	0x0040 /* RFC 5246 */
+#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256	0x0067 /* RFC 5246 */
+#define TLS_DH_DSS_WITH_AES_256_CBC_SHA256	0x0068 /* RFC 5246 */
+#define TLS_DH_RSA_WITH_AES_256_CBC_SHA256	0x0069 /* RFC 5246 */
+#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA256	0x006A /* RFC 5246 */
+#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256	0x006B /* RFC 5246 */
+#define TLS_DH_anon_WITH_AES_128_CBC_SHA256	0x006C /* RFC 5246 */
+#define TLS_DH_anon_WITH_AES_256_CBC_SHA256	0x006D /* RFC 5246 */
 
 /* CompressionMethod */
 #define TLS_COMPRESSION_NULL 0
 
+/* HashAlgorithm */
+enum {
+	TLS_HASH_ALG_NONE = 0,
+	TLS_HASH_ALG_MD5 = 1,
+	TLS_HASH_ALG_SHA1 = 2,
+	TLS_HASH_ALG_SHA224 = 3,
+	TLS_HASH_ALG_SHA256 = 4,
+	TLS_HASH_ALG_SHA384 = 5,
+	TLS_HASH_ALG_SHA512 = 6
+};
+
+/* SignatureAlgorithm */
+enum {
+	TLS_SIGN_ALG_ANONYMOUS = 0,
+	TLS_SIGN_ALG_RSA = 1,
+	TLS_SIGN_ALG_DSA = 2,
+	TLS_SIGN_ALG_ECDSA = 3,
+};
+
 /* AlertLevel */
 #define TLS_ALERT_LEVEL_WARNING 1
 #define TLS_ALERT_LEVEL_FATAL 2
@@ -169,7 +212,8 @@
 typedef enum {
 	TLS_HASH_NULL,
 	TLS_HASH_MD5,
-	TLS_HASH_SHA
+	TLS_HASH_SHA,
+	TLS_HASH_SHA256
 } tls_hash;
 
 struct tls_cipher_suite {
@@ -197,10 +241,13 @@
 struct tls_verify_hash {
 	struct crypto_hash *md5_client;
 	struct crypto_hash *sha1_client;
+	struct crypto_hash *sha256_client;
 	struct crypto_hash *md5_server;
 	struct crypto_hash *sha1_server;
+	struct crypto_hash *sha256_server;
 	struct crypto_hash *md5_cert;
 	struct crypto_hash *sha1_cert;
+	struct crypto_hash *sha256_cert;
 };
 
 
@@ -212,5 +259,9 @@
 void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
 			 size_t len);
 void tls_verify_hash_free(struct tls_verify_hash *verify);
+int tls_version_ok(u16 ver);
+const char * tls_version_str(u16 ver);
+int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
+	    const u8 *seed, size_t seed_len, u8 *out, size_t outlen);
 
 #endif /* TLSV1_COMMON_H */
diff --git a/src/tls/tlsv1_cred.c b/src/tls/tlsv1_cred.c
index aa467ef..d846480 100644
--- a/src/tls/tlsv1_cred.c
+++ b/src/tls/tlsv1_cred.c
@@ -46,7 +46,7 @@
 static int tlsv1_add_cert_der(struct x509_certificate **chain,
 			      const u8 *buf, size_t len)
 {
-	struct x509_certificate *cert;
+	struct x509_certificate *cert, *p;
 	char name[128];
 
 	cert = x509_certificate_parse(buf, len);
@@ -56,8 +56,20 @@
 		return -1;
 	}
 
-	cert->next = *chain;
-	*chain = cert;
+	p = *chain;
+	while (p && p->next)
+		p = p->next;
+	if (p && x509_name_compare(&cert->subject, &p->issuer) == 0) {
+		/*
+		 * The new certificate is the issuer of the last certificate in
+		 * the chain - add the new certificate to the end.
+		 */
+		p->next = cert;
+	} else {
+		/* Add to the beginning of the chain */
+		cert->next = *chain;
+		*chain = cert;
+	}
 
 	x509_name_string(&cert->subject, name, sizeof(name));
 	wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
@@ -232,10 +244,17 @@
 		if (!end)
 			return NULL;
 	} else {
+		const u8 *pos2;
 		pos += os_strlen(pem_key_begin);
 		end = search_tag(pem_key_end, pos, key + len - pos);
 		if (!end)
 			return NULL;
+		pos2 = search_tag("Proc-Type: 4,ENCRYPTED", pos, end - pos);
+		if (pos2) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unsupported private key "
+				   "format (Proc-Type/DEK-Info)");
+			return NULL;
+		}
 	}
 
 	der = base64_decode(pos, end - pos, &der_len);
diff --git a/src/tls/tlsv1_record.c b/src/tls/tlsv1_record.c
index e811f0e..0314551 100644
--- a/src/tls/tlsv1_record.c
+++ b/src/tls/tlsv1_record.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 Record Protocol
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "tlsv1_common.h"
 #include "tlsv1_record.h"
 
@@ -52,6 +53,9 @@
 	} else if (suite->hash == TLS_HASH_SHA) {
 		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
 		rl->hash_size = SHA1_MAC_LEN;
+	} else if (suite->hash == TLS_HASH_SHA256) {
+		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA256;
+		rl->hash_size = SHA256_MAC_LEN;
 	}
 
 	data = tls_get_cipher_data(suite->cipher);
@@ -138,10 +142,10 @@
  * tlsv1_record_send - TLS record layer: Send a message
  * @rl: Pointer to TLS record layer data
  * @content_type: Content type (TLS_CONTENT_TYPE_*)
- * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the
- * beginning for record layer to fill in; payload filled in after this and
- * extra space in the end for HMAC).
+ * @buf: Buffer for the generated TLS message (needs to have extra space for
+ * header, IV (TLS v1.1), and HMAC)
  * @buf_size: Maximum buf size
+ * @payload: Payload to be sent
  * @payload_len: Length of the payload
  * @out_len: Buffer for returning the used buf length
  * Returns: 0 on success, -1 on failure
@@ -150,29 +154,62 @@
  * the data using the current write cipher.
  */
 int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
-		      size_t buf_size, size_t payload_len, size_t *out_len)
+		      size_t buf_size, const u8 *payload, size_t payload_len,
+		      size_t *out_len)
 {
-	u8 *pos, *ct_start, *length, *payload;
+	u8 *pos, *ct_start, *length, *cpayload;
 	struct crypto_hash *hmac;
 	size_t clen;
+	int explicit_iv;
 
 	pos = buf;
+	if (pos + TLS_RECORD_HEADER_LEN > buf + buf_size)
+		return -1;
+
 	/* ContentType type */
 	ct_start = pos;
 	*pos++ = content_type;
 	/* ProtocolVersion version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
+	WPA_PUT_BE16(pos, rl->tls_version);
 	pos += 2;
 	/* uint16 length */
 	length = pos;
 	WPA_PUT_BE16(length, payload_len);
 	pos += 2;
 
-	/* opaque fragment[TLSPlaintext.length] */
-	payload = pos;
+	cpayload = pos;
+	explicit_iv = rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL &&
+		rl->iv_size && rl->tls_version >= TLS_VERSION_1_1;
+	if (explicit_iv) {
+		/* opaque IV[Cipherspec.block_length] */
+		if (pos + rl->iv_size > buf + buf_size)
+			return -1;
+
+		/*
+		 * Use random number R per the RFC 4346, 6.2.3.2 CBC Block
+		 * Cipher option 2a.
+		 */
+
+		if (os_get_random(pos, rl->iv_size))
+			return -1;
+		pos += rl->iv_size;
+	}
+
+	/*
+	 * opaque fragment[TLSPlaintext.length]
+	 * (opaque content[TLSCompressed.length] in GenericBlockCipher)
+	 */
+	if (pos + payload_len > buf + buf_size)
+		return -1;
+	os_memmove(pos, payload, payload_len);
 	pos += payload_len;
 
 	if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
+		/*
+		 * MAC calculated over seq_num + TLSCompressed.type +
+		 * TLSCompressed.version + TLSCompressed.length +
+		 * TLSCompressed.fragment
+		 */
 		hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
 					rl->hash_size);
 		if (hmac == NULL) {
@@ -182,7 +219,8 @@
 		}
 		crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
 		/* type + version + length + fragment */
-		crypto_hash_update(hmac, ct_start, pos - ct_start);
+		crypto_hash_update(hmac, ct_start, TLS_RECORD_HEADER_LEN);
+		crypto_hash_update(hmac, payload, payload_len);
 		clen = buf + buf_size - pos;
 		if (clen < rl->hash_size) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
@@ -200,7 +238,7 @@
 			    pos, clen);
 		pos += clen;
 		if (rl->iv_size) {
-			size_t len = pos - payload;
+			size_t len = pos - cpayload;
 			size_t pad;
 			pad = (len + 1) % rl->iv_size;
 			if (pad)
@@ -214,8 +252,8 @@
 			pos += pad + 1;
 		}
 
-		if (crypto_cipher_encrypt(rl->write_cbc, payload,
-					  payload, pos - payload) < 0)
+		if (crypto_cipher_encrypt(rl->write_cbc, cpayload,
+					  cpayload, pos - cpayload) < 0)
 			return -1;
 	}
 
@@ -237,7 +275,8 @@
  * @out_len: Set to maximum out_data length by caller; used to return the
  * length of the used data
  * @alert: Buffer for returning an alert value on failure
- * Returns: 0 on success, -1 on failure
+ * Returns: Number of bytes used from in_data on success, 0 if record was not
+ *	complete (more data needed), or -1 on failure
  *
  * This function decrypts the received message, verifies HMAC and TLS record
  * layer header.
@@ -250,40 +289,35 @@
 	u8 padlen;
 	struct crypto_hash *hmac;
 	u8 len[2], hash[100];
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
-		    in_data, in_len);
+	int force_mac_error = 0;
+	u8 ct;
 
 	if (in_len < TLS_RECORD_HEADER_LEN) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu) - "
+			   "need more data",
 			   (unsigned long) in_len);
-		*alert = TLS_ALERT_DECODE_ERROR;
-		return -1;
+		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+			    in_data, in_len);
+		return 0;
 	}
 
+	ct = in_data[0];
+	rlen = WPA_GET_BE16(in_data + 3);
 	wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
-		   "length %d", in_data[0], in_data[1], in_data[2],
-		   WPA_GET_BE16(in_data + 3));
+		   "length %d", ct, in_data[1], in_data[2], (int) rlen);
 
-	if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
-	    in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
-	    in_data[0] != TLS_CONTENT_TYPE_ALERT &&
-	    in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
-			   in_data[0]);
-		*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
-		return -1;
-	}
-
-	if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
+	/*
+	 * TLS v1.0 and v1.1 RFCs were not exactly clear on the use of the
+	 * protocol version in record layer. As such, accept any {03,xx} value
+	 * to remain compatible with existing implementations.
+	 */
+	if (in_data[1] != 0x03) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
-			   "%d.%d", in_data[1], in_data[2]);
+			   "%u.%u", in_data[1], in_data[2]);
 		*alert = TLS_ALERT_PROTOCOL_VERSION;
 		return -1;
 	}
 
-	rlen = WPA_GET_BE16(in_data + 3);
-
 	/* TLSCiphertext must not be more than 2^14+2048 bytes */
 	if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
@@ -299,7 +333,19 @@
 		wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
 			   "(rlen=%lu > in_len=%lu)",
 			   (unsigned long) rlen, (unsigned long) in_len);
-		*alert = TLS_ALERT_DECODE_ERROR;
+		return 0;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+		    in_data, rlen);
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE &&
+	    ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
+	    ct != TLS_CONTENT_TYPE_ALERT &&
+	    ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Ignore record with unknown "
+			   "content type 0x%x", ct);
+		*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
 		return -1;
 	}
 
@@ -312,58 +358,86 @@
 		return -1;
 	}
 
-	os_memcpy(out_data, in_data, in_len);
-	*out_len = in_len;
-
 	if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
-		if (crypto_cipher_decrypt(rl->read_cbc, out_data,
+		size_t plen;
+		if (crypto_cipher_decrypt(rl->read_cbc, in_data,
 					  out_data, in_len) < 0) {
 			*alert = TLS_ALERT_DECRYPTION_FAILED;
 			return -1;
 		}
+		plen = in_len;
+		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
+				"data", out_data, plen);
+
 		if (rl->iv_size) {
-			if (in_len == 0) {
+			/*
+			 * TLS v1.0 defines different alert values for various
+			 * failures. That may information to aid in attacks, so
+			 * use the same bad_record_mac alert regardless of the
+			 * issues.
+			 *
+			 * In addition, instead of returning immediately on
+			 * error, run through the MAC check to make timing
+			 * attacks more difficult.
+			 */
+
+			if (rl->tls_version >= TLS_VERSION_1_1) {
+				/* Remove opaque IV[Cipherspec.block_length] */
+				if (plen < rl->iv_size) {
+					wpa_printf(MSG_DEBUG, "TLSv1.1: Not "
+						   "enough room for IV");
+					force_mac_error = 1;
+					goto check_mac;
+				}
+				os_memmove(out_data, out_data + rl->iv_size,
+					   plen - rl->iv_size);
+				plen -= rl->iv_size;
+			}
+
+			/* Verify and remove padding */
+			if (plen == 0) {
 				wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
 					   " (no pad)");
-				*alert = TLS_ALERT_DECODE_ERROR;
-				return -1;
+				force_mac_error = 1;
+				goto check_mac;
 			}
-			padlen = out_data[in_len - 1];
-			if (padlen >= in_len) {
+			padlen = out_data[plen - 1];
+			if (padlen >= plen) {
 				wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
-					   "length (%u, in_len=%lu) in "
+					   "length (%u, plen=%lu) in "
 					   "received record",
-					   padlen, (unsigned long) in_len);
-				*alert = TLS_ALERT_DECRYPTION_FAILED;
-				return -1;
+					   padlen, (unsigned long) plen);
+				force_mac_error = 1;
+				goto check_mac;
 			}
-			for (i = in_len - padlen; i < in_len; i++) {
+			for (i = plen - padlen - 1; i < plen - 1; i++) {
 				if (out_data[i] != padlen) {
 					wpa_hexdump(MSG_DEBUG,
 						    "TLSv1: Invalid pad in "
 						    "received record",
-						    out_data + in_len - padlen,
-						    padlen);
-					*alert = TLS_ALERT_DECRYPTION_FAILED;
-					return -1;
+						    out_data + plen - padlen -
+						    1, padlen + 1);
+					force_mac_error = 1;
+					goto check_mac;
 				}
 			}
 
-			*out_len -= padlen + 1;
+			plen -= padlen + 1;
+
+			wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - "
+					"Decrypted data with IV and padding "
+					"removed", out_data, plen);
 		}
 
-		wpa_hexdump(MSG_MSGDUMP,
-			    "TLSv1: Record Layer - Decrypted data",
-			    out_data, in_len);
-
-		if (*out_len < rl->hash_size) {
+	check_mac:
+		if (plen < rl->hash_size) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
 				   "hash value");
-			*alert = TLS_ALERT_INTERNAL_ERROR;
+			*alert = TLS_ALERT_BAD_RECORD_MAC;
 			return -1;
 		}
 
-		*out_len -= rl->hash_size;
+		plen -= rl->hash_size;
 
 		hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
 					rl->hash_size);
@@ -377,22 +451,30 @@
 		crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
 		/* type + version + length + fragment */
 		crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
-		WPA_PUT_BE16(len, *out_len);
+		WPA_PUT_BE16(len, plen);
 		crypto_hash_update(hmac, len, 2);
-		crypto_hash_update(hmac, out_data, *out_len);
+		crypto_hash_update(hmac, out_data, plen);
 		hlen = sizeof(hash);
 		if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
 				   "to calculate HMAC");
+			*alert = TLS_ALERT_INTERNAL_ERROR;
 			return -1;
 		}
 		if (hlen != rl->hash_size ||
-		    os_memcmp(hash, out_data + *out_len, hlen) != 0) {
+		    os_memcmp(hash, out_data + plen, hlen) != 0 ||
+		    force_mac_error) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
-				   "received message");
+				   "received message (force_mac_error=%d)",
+				   force_mac_error);
 			*alert = TLS_ALERT_BAD_RECORD_MAC;
 			return -1;
 		}
+
+		*out_len = plen;
+	} else {
+		os_memcpy(out_data, in_data, in_len);
+		*out_len = in_len;
 	}
 
 	/* TLSCompressed must not be more than 2^14+1024 bytes */
@@ -405,5 +487,5 @@
 
 	inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
 
-	return 0;
+	return TLS_RECORD_HEADER_LEN + rlen;
 }
diff --git a/src/tls/tlsv1_record.h b/src/tls/tlsv1_record.h
index 9c7c0a4..9eb9bfd 100644
--- a/src/tls/tlsv1_record.h
+++ b/src/tls/tlsv1_record.h
@@ -1,6 +1,6 @@
 /*
  * TLSv1 Record Protocol
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,7 +17,7 @@
 
 #include "crypto/crypto.h"
 
-#define TLS_MAX_WRITE_MAC_SECRET_LEN 20
+#define TLS_MAX_WRITE_MAC_SECRET_LEN 32
 #define TLS_MAX_WRITE_KEY_LEN 32
 #define TLS_MAX_IV_LEN 16
 #define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \
@@ -35,6 +35,8 @@
 };
 
 struct tlsv1_record_layer {
+	u16 tls_version;
+
 	u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
 	u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
 	u8 write_key[TLS_MAX_WRITE_KEY_LEN];
@@ -66,7 +68,8 @@
 int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl);
 int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl);
 int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
-		      size_t buf_size, size_t payload_len, size_t *out_len);
+		      size_t buf_size, const u8 *payload, size_t payload_len,
+		      size_t *out_len);
 int tlsv1_record_receive(struct tlsv1_record_layer *rl,
 			 const u8 *in_data, size_t in_len,
 			 u8 *out_data, size_t *out_len, u8 *alert);
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index 6a61235..96e160c 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -1,6 +1,6 @@
 /*
- * TLSv1 server (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -49,7 +49,8 @@
 		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
 		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
 			  TLS_RANDOM_LEN);
-		if (tls_prf(pre_master_secret, pre_master_secret_len,
+		if (tls_prf(conn->rl.tls_version,
+			    pre_master_secret, pre_master_secret_len,
 			    "master secret", seed, 2 * TLS_RANDOM_LEN,
 			    conn->master_secret, TLS_MASTER_SECRET_LEN)) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
@@ -64,7 +65,8 @@
 	os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
 	key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
 			     conn->rl.iv_size);
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
 		    "key expansion", seed, 2 * TLS_RANDOM_LEN,
 		    key_block, key_block_len)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
@@ -115,6 +117,7 @@
 	const u8 *pos, *end;
 	u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
 	size_t in_msg_len;
+	int used;
 
 	if (in_data == NULL || in_len == 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: No input data to server");
@@ -130,13 +133,21 @@
 	/* Each received packet may include multiple records */
 	while (pos < end) {
 		in_msg_len = in_len;
-		if (tlsv1_record_receive(&conn->rl, pos, end - pos,
-					 in_msg, &in_msg_len, &alert)) {
+		used = tlsv1_record_receive(&conn->rl, pos, end - pos,
+					    in_msg, &in_msg_len, &alert);
+		if (used < 0) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
 				   "record failed");
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
 			goto failed;
 		}
+		if (used == 0) {
+			/* need more data */
+			wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+				   "yet supported");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			goto failed;
+		}
 		ct = pos[0];
 
 		in_pos = in_msg;
@@ -152,7 +163,7 @@
 			in_pos += in_msg_len;
 		}
 
-		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+		pos += used;
 	}
 
 	os_free(in_msg);
@@ -201,10 +212,8 @@
 	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
 			in_data, in_len);
 
-	os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
-
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
-			      out_data, out_len, in_len, &rlen) < 0) {
+			      out_data, out_len, in_data, in_len, &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
@@ -232,8 +241,8 @@
 			 u8 *out_data, size_t out_len)
 {
 	const u8 *in_end, *pos;
-	int res;
-	u8 alert, *out_end, *out_pos;
+	int used;
+	u8 alert, *out_end, *out_pos, ct;
 	size_t olen;
 
 	pos = in_data;
@@ -242,7 +251,46 @@
 	out_end = out_data + out_len;
 
 	while (pos < in_end) {
-		if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+		ct = pos[0];
+		olen = out_end - out_pos;
+		used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+					    out_pos, &olen, &alert);
+		if (used < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
+				   "failed");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			return -1;
+		}
+		if (used == 0) {
+			/* need more data */
+			wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+				   "yet supported");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			return -1;
+		}
+
+		if (ct == TLS_CONTENT_TYPE_ALERT) {
+			if (olen < 2) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Alert "
+					   "underflow");
+				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+						   TLS_ALERT_DECODE_ERROR);
+				return -1;
+			}
+			wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+				   out_pos[0], out_pos[1]);
+			if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
+				/* Continue processing */
+				pos += used;
+				continue;
+			}
+
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   out_pos[1]);
+			return -1;
+		}
+
+		if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
 				   "0x%x", pos[0]);
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -250,15 +298,6 @@
 			return -1;
 		}
 
-		olen = out_end - out_pos;
-		res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
-					   out_pos, &olen, &alert);
-		if (res < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
-				   "failed");
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
-			return -1;
-		}
 		out_pos += olen;
 		if (out_pos > out_end) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
@@ -268,7 +307,7 @@
 			return -1;
 		}
 
-		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+		pos += used;
 	}
 
 	return out_pos - out_data;
@@ -412,7 +451,8 @@
 			  TLS_RANDOM_LEN);
 	}
 
-	return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+	return tls_prf(conn->rl.tls_version,
+		       conn->master_secret, TLS_MASTER_SECRET_LEN,
 		       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
 }
 
diff --git a/src/tls/tlsv1_server.h b/src/tls/tlsv1_server.h
index 00c536c..daa4353 100644
--- a/src/tls/tlsv1_server.h
+++ b/src/tls/tlsv1_server.h
@@ -1,6 +1,6 @@
 /*
- * TLSv1 server (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index fd74436..443c028 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 server - read handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "crypto/tls.h"
 #include "x509v3.h"
 #include "tlsv1_common.h"
@@ -85,15 +86,30 @@
 	conn->client_version = WPA_GET_BE16(pos);
 	wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
 		   conn->client_version >> 8, conn->client_version & 0xff);
-	if (conn->client_version < TLS_VERSION) {
+	if (conn->client_version < TLS_VERSION_1) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
-			   "ClientHello");
+			   "ClientHello %u.%u",
+			   conn->client_version >> 8,
+			   conn->client_version & 0xff);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_PROTOCOL_VERSION);
 		return -1;
 	}
 	pos += 2;
 
+	if (TLS_VERSION == TLS_VERSION_1)
+		conn->rl.tls_version = TLS_VERSION_1;
+#ifdef CONFIG_TLSV12
+	else if (conn->client_version >= TLS_VERSION_1_2)
+		conn->rl.tls_version = TLS_VERSION_1_2;
+#endif /* CONFIG_TLSV12 */
+	else if (conn->client_version > TLS_VERSION_1_1)
+		conn->rl.tls_version = TLS_VERSION_1_1;
+	else
+		conn->rl.tls_version = conn->client_version;
+	wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
+		   tls_version_str(conn->rl.tls_version));
+
 	/* Random random */
 	if (end - pos < TLS_RANDOM_LEN)
 		goto decode_error;
@@ -483,6 +499,14 @@
 
 	encr_len = WPA_GET_BE16(pos);
 	pos += 2;
+	if (pos + encr_len > end) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientKeyExchange "
+			   "format: encr_len=%u left=%u",
+			   encr_len, (unsigned int) (end - pos));
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
 
 	outbuflen = outlen = end - pos;
 	out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ?
@@ -512,21 +536,21 @@
 	 */
 
 	if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key,
-						 pos, end - pos,
+						 pos, encr_len,
 						 out, &outlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
-			   "PreMasterSecret (encr_len=%d outlen=%lu)",
-			   (int) (end - pos), (unsigned long) outlen);
+			   "PreMasterSecret (encr_len=%u outlen=%lu)",
+			   encr_len, (unsigned long) outlen);
 		use_random = 1;
 	}
 
-	if (outlen != TLS_PRE_MASTER_SECRET_LEN) {
+	if (!use_random && outlen != TLS_PRE_MASTER_SECRET_LEN) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
 			   "length %lu", (unsigned long) outlen);
 		use_random = 1;
 	}
 
-	if (WPA_GET_BE16(out) != conn->client_version) {
+	if (!use_random && WPA_GET_BE16(out) != conn->client_version) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
 			   "ClientKeyExchange does not match with version in "
 			   "ClientHello");
@@ -822,6 +846,47 @@
 
 	hpos = hash;
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version == TLS_VERSION_1_2) {
+		/*
+		 * RFC 5246, 4.7:
+		 * TLS v1.2 adds explicit indication of the used signature and
+		 * hash algorithms.
+		 *
+		 * struct {
+		 *   HashAlgorithm hash;
+		 *   SignatureAlgorithm signature;
+		 * } SignatureAndHashAlgorithm;
+		 */
+		if (end - pos < 2) {
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_DECODE_ERROR);
+			return -1;
+		}
+		if (pos[0] != TLS_HASH_ALG_SHA256 ||
+		    pos[1] != TLS_SIGN_ALG_RSA) {
+			wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/"
+				   "signature(%u) algorithm",
+				   pos[0], pos[1]);
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		pos += 2;
+
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_cert == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
+		    0) {
+			conn->verify.sha256_cert = NULL;
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		conn->verify.sha256_cert = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
 	if (alg == SIGN_ALG_RSA) {
 		hlen = MD5_MAC_LEN;
 		if (conn->verify.md5_cert == NULL ||
@@ -852,6 +917,10 @@
 	if (alg == SIGN_ALG_RSA)
 		hlen += MD5_MAC_LEN;
 
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
 
 	if (end - pos < 2) {
@@ -891,6 +960,41 @@
 	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
 			buf, buflen);
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		/*
+		 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+		 *
+		 * DigestInfo ::= SEQUENCE {
+		 *   digestAlgorithm DigestAlgorithm,
+		 *   digest OCTET STRING
+		 * }
+		 *
+		 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+		 *
+		 * DER encoded DigestInfo for SHA256 per RFC 3447:
+		 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+		 * H
+		 */
+		if (buflen >= 19 + 32 &&
+		    os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
+			      "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
+		{
+			wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = "
+				   "SHA-256");
+			os_memmove(buf, buf + 19, buflen - 19);
+			buflen -= 19;
+		} else {
+			wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized "
+				   "DigestInfo");
+			os_free(buf);
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_DECRYPT_ERROR);
+			return -1;
+		}
+	}
+#endif /* CONFIG_TLSV12 */
+
 	if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
 			   "CertificateVerify - did not match with calculated "
@@ -1022,6 +1126,21 @@
 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
 		    pos, TLS_VERIFY_DATA_LEN);
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_client == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
+		    < 0) {
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			conn->verify.sha256_client = NULL;
+			return -1;
+		}
+		conn->verify.sha256_client = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
 	hlen = MD5_MAC_LEN;
 	if (conn->verify.md5_client == NULL ||
 	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
@@ -1043,9 +1162,15 @@
 		return -1;
 	}
 	conn->verify.sha1_client = NULL;
+	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
 
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "client finished", hash, hlen,
 		    verify_data, TLS_VERIFY_DATA_LEN)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c
index e89e52e..0ca3b23 100644
--- a/src/tls/tlsv1_server_write.c
+++ b/src/tls/tlsv1_server_write.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 server - write handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "crypto/tls.h"
 #include "crypto/random.h"
 #include "x509v3.h"
@@ -87,7 +88,7 @@
 	pos += 3;
 	/* body - ServerHello */
 	/* ProtocolVersion server_version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
+	WPA_PUT_BE16(pos, conn->rl.tls_version);
 	pos += 2;
 	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
 	os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
@@ -143,7 +144,8 @@
 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
@@ -227,7 +229,8 @@
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
@@ -418,7 +421,8 @@
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
@@ -483,7 +487,8 @@
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
@@ -502,40 +507,35 @@
 static int tls_write_server_hello_done(struct tlsv1_server *conn,
 				       u8 **msgpos, u8 *end)
 {
-	u8 *pos, *rhdr, *hs_start, *hs_length;
+	u8 *pos;
 	size_t rlen;
-
-	pos = *msgpos;
+	u8 payload[4];
 
 	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
 
 	/* opaque fragment[TLSPlaintext.length] */
 
 	/* Handshake */
-	hs_start = pos;
+	pos = payload;
 	/* HandshakeType msg_type */
 	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
+	/* uint24 length */
+	WPA_PUT_BE24(pos, 0);
 	pos += 3;
 	/* body - ServerHelloDone (empty) */
 
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      *msgpos, end - *msgpos, payload, pos - payload,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
 		return -1;
 	}
-	pos = rhdr + rlen;
 
-	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+	tls_verify_hash_add(&conn->verify, payload, pos - payload);
 
-	*msgpos = pos;
+	*msgpos += rlen;
 
 	return 0;
 }
@@ -544,17 +544,16 @@
 static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
 					       u8 **msgpos, u8 *end)
 {
-	u8 *pos, *rhdr;
 	size_t rlen;
-
-	pos = *msgpos;
+	u8 payload[1];
 
 	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-	*pos = TLS_CHANGE_CIPHER_SPEC;
+
+	payload[0] = TLS_CHANGE_CIPHER_SPEC;
+
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
-			      rhdr, end - rhdr, 1, &rlen) < 0) {
+			      *msgpos, end - *msgpos, payload, sizeof(payload),
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
@@ -569,7 +568,7 @@
 		return -1;
 	}
 
-	*msgpos = rhdr + rlen;
+	*msgpos += rlen;
 
 	return 0;
 }
@@ -578,9 +577,9 @@
 static int tls_write_server_finished(struct tlsv1_server *conn,
 				     u8 **msgpos, u8 *end)
 {
-	u8 *pos, *rhdr, *hs_start, *hs_length;
+	u8 *pos, *hs_start;
 	size_t rlen, hlen;
-	u8 verify_data[TLS_VERIFY_DATA_LEN];
+	u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
 	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
 
 	pos = *msgpos;
@@ -589,6 +588,21 @@
 
 	/* Encrypted Handshake Message: Finished */
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_server == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
+		    < 0) {
+			conn->verify.sha256_server = NULL;
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		conn->verify.sha256_server = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
 	hlen = MD5_MAC_LEN;
 	if (conn->verify.md5_server == NULL ||
 	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
@@ -610,43 +624,44 @@
 		return -1;
 	}
 	conn->verify.sha1_server = NULL;
+	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
 
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
-		    verify_data, TLS_VERIFY_DATA_LEN)) {
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "server finished", hash, hlen,
+		    verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
 		return -1;
 	}
 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
-			verify_data, TLS_VERIFY_DATA_LEN);
+			verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
 
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
 	/* Handshake */
-	hs_start = pos;
+	pos = hs_start = verify_data;
 	/* HandshakeType msg_type */
 	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
+	/* uint24 length */
+	WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
 	pos += 3;
-	os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
 	pos += TLS_VERIFY_DATA_LEN;
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      *msgpos, end - *msgpos, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
 		return -1;
 	}
 
-	pos = rhdr + rlen;
-
-	*msgpos = pos;
+	*msgpos += rlen;
 
 	return 0;
 }
@@ -771,7 +786,8 @@
 	/* ContentType type */
 	*pos++ = TLS_CONTENT_TYPE_ALERT;
 	/* ProtocolVersion version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
+	WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
+		     TLS_VERSION);
 	pos += 2;
 	/* uint16 length (to be filled) */
 	length = pos;
diff --git a/src/utils/base64.c b/src/utils/base64.c
index 155bfce..fb1224b 100644
--- a/src/utils/base64.c
+++ b/src/utils/base64.c
@@ -1,6 +1,6 @@
 /*
  * Base64 encoding/decoding (RFC1341)
- * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -103,8 +103,9 @@
 unsigned char * base64_decode(const unsigned char *src, size_t len,
 			      size_t *out_len)
 {
-	unsigned char dtable[256], *out, *pos, in[4], block[4], tmp;
+	unsigned char dtable[256], *out, *pos, block[4], tmp;
 	size_t i, count, olen;
+	int pad = 0;
 
 	os_memset(dtable, 0x80, 256);
 	for (i = 0; i < sizeof(base64_table) - 1; i++)
@@ -131,7 +132,8 @@
 		if (tmp == 0x80)
 			continue;
 
-		in[count] = src[i];
+		if (src[i] == '=')
+			pad++;
 		block[count] = tmp;
 		count++;
 		if (count == 4) {
@@ -139,16 +141,21 @@
 			*pos++ = (block[1] << 4) | (block[2] >> 2);
 			*pos++ = (block[2] << 6) | block[3];
 			count = 0;
+			if (pad) {
+				if (pad == 1)
+					pos--;
+				else if (pad == 2)
+					pos -= 2;
+				else {
+					/* Invalid padding */
+					os_free(out);
+					return NULL;
+				}
+				break;
+			}
 		}
 	}
 
-	if (pos > out) {
-		if (in[2] == '=')
-			pos -= 2;
-		else if (in[3] == '=')
-			pos--;
-	}
-
 	*out_len = pos - out;
 	return out;
 }
diff --git a/src/utils/edit.c b/src/utils/edit.c
index 8f9e4ed..c5b17ac 100644
--- a/src/utils/edit.c
+++ b/src/utils/edit.c
@@ -1,6 +1,6 @@
 /*
  * Command line editing and history
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -24,6 +24,8 @@
 static char cmdbuf[CMD_BUF_LEN];
 static int cmdbuf_pos = 0;
 static int cmdbuf_len = 0;
+static char currbuf[CMD_BUF_LEN];
+static int currbuf_valid = 0;
 
 #define HISTORY_MAX 100
 
@@ -231,18 +233,22 @@
 
 	if (history_curr ==
 	    dl_list_first(&history_list, struct edit_history, list)) {
-		cmdbuf[cmdbuf_len] = '\0';
-		history_add(cmdbuf);
+		if (!currbuf_valid) {
+			cmdbuf[cmdbuf_len] = '\0';
+			os_memcpy(currbuf, cmdbuf, cmdbuf_len + 1);
+			currbuf_valid = 1;
+			history_use();
+			return;
+		}
 	}
 
-	history_use();
-
 	if (history_curr ==
 	    dl_list_last(&history_list, struct edit_history, list))
 		return;
 
 	history_curr = dl_list_entry(history_curr->list.next,
 				     struct edit_history, list);
+	history_use();
 }
 
 
@@ -250,8 +256,16 @@
 {
 	if (history_curr == NULL ||
 	    history_curr ==
-	    dl_list_first(&history_list, struct edit_history, list))
+	    dl_list_first(&history_list, struct edit_history, list)) {
+		if (currbuf_valid) {
+			currbuf_valid = 0;
+			edit_clear_line();
+			cmdbuf_len = cmdbuf_pos = os_strlen(currbuf);
+			os_memcpy(cmdbuf, currbuf, cmdbuf_len);
+			edit_redraw();
+		}
 		return;
+	}
 
 	history_curr = dl_list_entry(history_curr->list.prev,
 				     struct edit_history, list);
@@ -309,6 +323,8 @@
 	printf("\r");
 	dl_list_for_each_reverse(h, &history_list, struct edit_history, list)
 		printf("%s%s\n", h == history_curr ? "[C]" : "", h->str);
+	if (currbuf_valid)
+		printf("{%s}\n", currbuf);
 	edit_redraw();
 }
 
@@ -1104,6 +1120,7 @@
 	      char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
 	      void *ctx, const char *history_file)
 {
+	currbuf[0] = '\0';
 	dl_list_init(&history_list);
 	history_curr = NULL;
 	if (history_file)
diff --git a/src/utils/eloop.h b/src/utils/eloop.h
index 1228f24..a656bf8 100644
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
@@ -144,7 +144,7 @@
  * Returns: 0 on success, -1 on failure
  *
  * Register an event handler for the given event. This function is used to
- * register eloop implementation specific events which are mainly targetted for
+ * register eloop implementation specific events which are mainly targeted for
  * operating system specific code (driver interface and l2_packet) since the
  * portable code will not be able to use such an OS-specific call. The handler
  * function will be called whenever the event is triggered. The handler
diff --git a/src/utils/includes.h b/src/utils/includes.h
index 63b5c23..cf2a42b 100644
--- a/src/utils/includes.h
+++ b/src/utils/includes.h
@@ -34,7 +34,6 @@
 #include <errno.h>
 #endif /* _WIN32_WCE */
 #include <ctype.h>
-#include <time.h>
 
 #ifndef CONFIG_TI_COMPILER
 #ifndef _MSC_VER
diff --git a/src/utils/list.h b/src/utils/list.h
index ded7846..c8dccee 100644
--- a/src/utils/list.h
+++ b/src/utils/list.h
@@ -95,4 +95,7 @@
 	     &item->member != (list); \
 	     item = dl_list_entry(item->member.prev, type, member))
 
+#define DEFINE_DL_LIST(name) \
+	struct dl_list name = { &(name), &(name) }
+
 #endif /* LIST_H */
diff --git a/src/utils/os.h b/src/utils/os.h
index f4723d8..f69478a 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -70,6 +70,16 @@
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
 	      os_time_t *t);
 
+struct os_tm {
+	int sec; /* 0..59 or 60 for leap seconds */
+	int min; /* 0..59 */
+	int hour; /* 0..23 */
+	int day; /* 1..31 */
+	int month; /* 1..12 */
+	int year; /* Four digit year */
+};
+
+int os_gmtime(os_time_t t, struct os_tm *tm);
 
 /**
  * os_daemonize - Run in the background (detach from the controlling terminal)
diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c
index 5260e23..8024a30 100644
--- a/src/utils/os_internal.c
+++ b/src/utils/os_internal.c
@@ -70,6 +70,24 @@
 }
 
 
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+	struct tm *tm2;
+	time_t t2 = t;
+
+	tm2 = gmtime(&t2);
+	if (tm2 == NULL)
+		return -1;
+	tm->sec = tm2->tm_sec;
+	tm->min = tm2->tm_min;
+	tm->hour = tm2->tm_hour;
+	tm->day = tm2->tm_mday;
+	tm->month = tm2->tm_mon + 1;
+	tm->year = tm2->tm_year + 1900;
+	return 0;
+}
+
+
 int os_daemonize(const char *pid_file)
 {
 	if (daemon(0, 0)) {
diff --git a/src/utils/os_none.c b/src/utils/os_none.c
index bab8f17..3fbb777 100644
--- a/src/utils/os_none.c
+++ b/src/utils/os_none.c
@@ -38,6 +38,11 @@
 	return -1;
 }
 
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+	return -1;
+}
+
 
 int os_daemonize(const char *pid_file)
 {
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 4e11758..9b16b33 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -14,6 +14,8 @@
 
 #include "includes.h"
 
+#include <time.h>
+
 #ifdef ANDROID
 #include <linux/capability.h>
 #include <linux/prctl.h>
@@ -25,9 +27,9 @@
 #ifdef WPA_TRACE
 
 #include "common.h"
-#include "list.h"
 #include "wpa_debug.h"
 #include "trace.h"
+#include "list.h"
 
 static struct dl_list alloc_list;
 
@@ -104,6 +106,24 @@
 }
 
 
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+	struct tm *tm2;
+	time_t t2 = t;
+
+	tm2 = gmtime(&t2);
+	if (tm2 == NULL)
+		return -1;
+	tm->sec = tm2->tm_sec;
+	tm->min = tm2->tm_min;
+	tm->hour = tm2->tm_hour;
+	tm->day = tm2->tm_mday;
+	tm->month = tm2->tm_mon + 1;
+	tm->year = tm2->tm_year + 1900;
+	return 0;
+}
+
+
 #ifdef __APPLE__
 #include <fcntl.h>
 static int os_daemon(int nochdir, int noclose)
diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c
index 0740964..51bd545 100644
--- a/src/utils/os_win32.c
+++ b/src/utils/os_win32.c
@@ -13,6 +13,7 @@
  */
 
 #include "includes.h"
+#include <time.h>
 #include <winsock2.h>
 #include <wincrypt.h>
 
@@ -92,6 +93,24 @@
 }
 
 
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+	struct tm *tm2;
+	time_t t2 = t;
+
+	tm2 = gmtime(&t2);
+	if (tm2 == NULL)
+		return -1;
+	tm->sec = tm2->tm_sec;
+	tm->min = tm2->tm_min;
+	tm->hour = tm2->tm_hour;
+	tm->day = tm2->tm_mday;
+	tm->month = tm2->tm_mon + 1;
+	tm->year = tm2->tm_year + 1900;
+	return 0;
+}
+
+
 int os_daemonize(const char *pid_file)
 {
 	/* TODO */
diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c
index bf9f04a..c36193e 100644
--- a/src/utils/pcsc_funcs.c
+++ b/src/utils/pcsc_funcs.c
@@ -812,7 +812,7 @@
 	wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response",
 		    buf, blen);
 
-	if (blen < 2 || buf[0] != 0x6c) {
+	if (blen < 2 || (buf[0] != 0x6c && buf[0] != 0x67)) {
 		wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file "
 			   "length determination");
 		return -1;
diff --git a/src/utils/radiotap.h b/src/utils/radiotap.h
index 508264c..137288f 100644
--- a/src/utils/radiotap.h
+++ b/src/utils/radiotap.h
@@ -238,5 +238,6 @@
 						 * retries */
 #define IEEE80211_RADIOTAP_F_TX_CTS	0x0002	/* used cts 'protection' */
 #define IEEE80211_RADIOTAP_F_TX_RTS	0x0004	/* used rts/cts handshake */
+#define IEEE80211_RADIOTAP_F_TX_NOACK	0x0008	/* don't expect an ACK */
 
 #endif				/* IEEE80211_RADIOTAP_H */
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index 0588fc6..5b56d83 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -34,7 +34,7 @@
 
 #ifndef ANDROID_LOG_NAME
 #define ANDROID_LOG_NAME	"wpa_supplicant"
-#endif
+#endif /* ANDROID_LOG_NAME */
 
 void android_printf(int level, char *format, ...)
 {
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index ae36afe..64ada57 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -136,7 +136,7 @@
 static inline void wpa_hexdump_buf_key(int level, const char *title,
 				       const struct wpabuf *buf)
 {
-	wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : 0,
+	wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL,
 			buf ? wpabuf_len(buf) : 0);
 }
 
diff --git a/src/wps/upnp_xml.c b/src/wps/upnp_xml.c
index b1b1e2b..a9958ee 100644
--- a/src/wps/upnp_xml.c
+++ b/src/wps/upnp_xml.c
@@ -75,8 +75,8 @@
  * Note that angle brackets present in the original data must have been encoded
  * as &lt; and &gt; so they will not trouble us.
  */
-static int xml_next_tag(const char *in, const char **out,
-			const char **out_tagname, const char **end)
+int xml_next_tag(const char *in, const char **out,
+		 const char **out_tagname, const char **end)
 {
 	while (*in && *in != '<')
 		in++;
diff --git a/src/wps/upnp_xml.h b/src/wps/upnp_xml.h
index 62dbe60..616af3d 100644
--- a/src/wps/upnp_xml.h
+++ b/src/wps/upnp_xml.h
@@ -16,6 +16,8 @@
 void xml_data_encode(struct wpabuf *buf, const char *data, int len);
 void xml_add_tagged_data(struct wpabuf *buf, const char *tag,
 			 const char *data);
+int xml_next_tag(const char *in, const char **out,
+		 const char **out_tagname, const char **end);
 char * xml_get_first_item(const char *doc, const char *item);
 struct wpabuf * xml_get_base64_item(const char *data, const char *name,
 				    enum http_reply_code *ret);
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 5c8c25f..2ba3d4b 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -67,12 +67,11 @@
 		/* Use special PIN '00000000' for PBC */
 		data->dev_pw_id = DEV_PW_PUSHBUTTON;
 		os_free(data->dev_password);
-		data->dev_password = os_malloc(8);
+		data->dev_password = (u8 *) os_strdup("00000000");
 		if (data->dev_password == NULL) {
 			os_free(data);
 			return NULL;
 		}
-		os_memset(data->dev_password, '0', 8);
 		data->dev_password_len = 8;
 	}
 
@@ -355,6 +354,19 @@
 
 
 /**
+ * wps_is_20 - Check whether WPS attributes claim support for WPS 2.0
+ */
+int wps_is_20(const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	if (msg == NULL || wps_parse_msg(msg, &attr) < 0)
+		return 0;
+	return attr.version2 != NULL;
+}
+
+
+/**
  * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request
  * @req_type: Value for Request Type attribute
  * Returns: WPS IE or %NULL on failure
@@ -443,7 +455,6 @@
 				       const u8 *req_dev_types)
 {
 	struct wpabuf *ie;
-	u16 methods = 0;
 
 	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request");
 
@@ -451,35 +462,9 @@
 	if (ie == NULL)
 		return NULL;
 
-	methods |= WPS_CONFIG_PUSHBUTTON;
-#ifdef CONFIG_WPS2
-	/*
-	 * TODO: Should figure out whether this device has a physical or
-	 * virtual pushbutton.
-	 */
-	methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
-#endif /* CONFIG_WPS2 */
-
-	/*
-	 * TODO: Should figure out whether this Probe Request was triggered
-	 * using physical or virtual display. Also, if the device has a PIN on
-	 * a label, that should be indicated here.
-	 */
-	methods |= WPS_CONFIG_DISPLAY |
-#ifdef CONFIG_WPS2
-		WPS_CONFIG_VIRT_DISPLAY |
-#endif /* CONFIG_WPS2 */
-		WPS_CONFIG_KEYPAD;
-#ifdef CONFIG_WPS_UFD
-	methods |= WPS_CONFIG_USBA;
-#endif /* CONFIG_WPS_UFD */
-#ifdef CONFIG_WPS_NFC
-	methods |= WPS_CONFIG_NFC_INTERFACE;
-#endif /* CONFIG_WPS_NFC */
-
 	if (wps_build_version(ie) ||
 	    wps_build_req_type(ie, req_type) ||
-	    wps_build_config_methods(ie, methods) ||
+	    wps_build_config_methods(ie, dev->config_methods) ||
 	    wps_build_uuid_e(ie, uuid) ||
 	    wps_build_primary_dev_type(dev, ie) ||
 	    wps_build_rf_bands(dev, ie) ||
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 3e4c218..4986881 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -99,6 +99,7 @@
 	u8 num_sec_dev_types;
 	u32 os_version;
 	u8 rf_bands;
+	u16 config_methods;
 	struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
 
 	int p2p;
@@ -239,6 +240,7 @@
 int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
 			   int ver1_compat);
 const u8 * wps_get_uuid_e(const struct wpabuf *msg);
+int wps_is_20(const struct wpabuf *msg);
 
 struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);
 struct wpabuf * wps_build_assoc_resp_ie(void);
@@ -782,6 +784,7 @@
 int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
 int wps_registrar_button_pushed(struct wps_registrar *reg,
 				const u8 *p2p_dev_addr);
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e);
 void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
 				const struct wpabuf *wps_data,
 				int p2p_wildcard);
@@ -791,6 +794,9 @@
 int wps_registrar_config_ap(struct wps_registrar *reg,
 			    struct wps_credential *cred);
 
+int wps_build_credential_wrap(struct wpabuf *msg,
+			      const struct wps_credential *cred);
+
 unsigned int wps_pin_checksum(unsigned int pin);
 unsigned int wps_pin_valid(unsigned int pin);
 unsigned int wps_generate_pin(void);
diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c
index 7b462d3..55b5573 100644
--- a/src/wps/wps_attr_parse.c
+++ b/src/wps/wps_attr_parse.c
@@ -557,7 +557,9 @@
 {
 	const u8 *pos, *end;
 	u16 type, len;
+#ifdef WPS_WORKAROUNDS
 	u16 prev_type = 0;
+#endif /* WPS_WORKAROUNDS */
 
 	os_memset(attr, 0, sizeof(*attr));
 	pos = wpabuf_head(msg);
@@ -622,7 +624,9 @@
 		if (wps_set_attr(attr, type, pos, len) < 0)
 			return -1;
 
+#ifdef WPS_WORKAROUNDS
 		prev_type = type;
+#endif /* WPS_WORKAROUNDS */
 		pos += len;
 	}
 
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 5d0508c..505837b 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -22,7 +22,6 @@
 #include "crypto/sha256.h"
 #include "crypto/random.h"
 #include "wps_i.h"
-#include "wps_dev_attr.h"
 
 
 void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 5b3c045..0fbaa3f 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -967,7 +967,7 @@
 		return WPS_CONTINUE;
 	}
 
-	if (wps_validate_m4_encr(decrypted, attr->version2 != 0) < 0) {
+	if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) {
 		wpabuf_free(decrypted);
 		wps->state = SEND_WSC_NACK;
 		return WPS_CONTINUE;
@@ -1020,7 +1020,7 @@
 		return WPS_CONTINUE;
 	}
 
-	if (wps_validate_m6_encr(decrypted, attr->version2 != 0) < 0) {
+	if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) {
 		wpabuf_free(decrypted);
 		wps->state = SEND_WSC_NACK;
 		return WPS_CONTINUE;
@@ -1086,8 +1086,8 @@
 		return WPS_CONTINUE;
 	}
 
-	if (wps_validate_m8_encr(decrypted, wps->wps->ap, attr->version2 != 0)
-	    < 0) {
+	if (wps_validate_m8_encr(decrypted, wps->wps->ap,
+				 attr->version2 != NULL) < 0) {
 		wpabuf_free(decrypted);
 		wps->state = SEND_WSC_NACK;
 		return WPS_CONTINUE;
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index a461836..856e9fb 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -502,16 +502,61 @@
 }
 
 
+static const char * wps_er_find_wfadevice(const char *data)
+{
+	const char *tag, *tagname, *end;
+	char *val;
+	int found = 0;
+
+	while (!found) {
+		/* Find next <device> */
+		for (;;) {
+			if (xml_next_tag(data, &tag, &tagname, &end))
+				return NULL;
+			data = end;
+			if (!os_strncasecmp(tagname, "device", 6) &&
+			    *tag != '/' &&
+			    (tagname[6] == '>' || !isgraph(tagname[6]))) {
+				break;
+			}
+		}
+
+		/* Check whether deviceType is WFADevice */
+		val = xml_get_first_item(data, "deviceType");
+		if (val == NULL)
+			return NULL;
+		wpa_printf(MSG_DEBUG, "WPS ER: Found deviceType '%s'", val);
+		found = os_strcasecmp(val, "urn:schemas-wifialliance-org:"
+				      "device:WFADevice:1") == 0;
+		os_free(val);
+	}
+
+	return data;
+}
+
+
 static void wps_er_parse_device_description(struct wps_er_ap *ap,
 					    struct wpabuf *reply)
 {
 	/* Note: reply includes null termination after the buffer data */
-	const char *data = wpabuf_head(reply);
+	const char *tmp, *data = wpabuf_head(reply);
 	char *pos;
 
 	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info",
 			  wpabuf_head(reply), wpabuf_len(reply));
 
+	/*
+	 * The root device description may include multiple devices, so first
+	 * find the beginning of the WFADevice description to allow the
+	 * simplistic parser to pick the correct entries.
+	 */
+	tmp = wps_er_find_wfadevice(data);
+	if (tmp == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: WFADevice:1 device not found - "
+			   "trying to parse invalid data");
+	} else
+		data = tmp;
+
 	ap->friendly_name = xml_get_first_item(data, "friendlyName");
 	wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name);
 
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 65ff40d..eda1c70 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -310,13 +310,17 @@
 
 
 static void wps_registrar_remove_pbc_session(struct wps_registrar *reg,
-					     const u8 *uuid_e)
+					     const u8 *uuid_e,
+					     const u8 *p2p_dev_addr)
 {
 	struct wps_pbc_session *pbc, *prev = NULL, *tmp;
 
 	pbc = reg->pbc_sessions;
 	while (pbc) {
-		if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) {
+		if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0 ||
+		    (p2p_dev_addr && !is_zero_ether_addr(reg->p2p_dev_addr) &&
+		     os_memcmp(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
+		     0)) {
 			if (prev)
 				prev->next = pbc->next;
 			else
@@ -485,10 +489,8 @@
 		*methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
 	if (conf_methods & WPS_CONFIG_PHY_PUSHBUTTON)
 		*methods |= WPS_CONFIG_PHY_PUSHBUTTON;
-	if ((*methods & WPS_CONFIG_VIRT_PUSHBUTTON) !=
-	    WPS_CONFIG_VIRT_PUSHBUTTON ||
-	    (*methods & WPS_CONFIG_PHY_PUSHBUTTON) !=
-	    WPS_CONFIG_PHY_PUSHBUTTON) {
+	if (!(*methods & (WPS_CONFIG_VIRT_PUSHBUTTON |
+			  WPS_CONFIG_PHY_PUSHBUTTON))) {
 		/*
 		 * Required to include virtual/physical flag, but we were not
 		 * configured with push button type, so have to default to one
@@ -549,15 +551,7 @@
 static int wps_build_config_methods_r(struct wps_registrar *reg,
 				      struct wpabuf *msg)
 {
-	u16 methods;
-	methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
-#ifdef CONFIG_WPS2
-	methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
-		     WPS_CONFIG_PHY_PUSHBUTTON);
-#endif /* CONFIG_WPS2 */
-	if (reg->pbc)
-		wps_set_pushbutton(&methods, reg->wps->config_methods);
-	return wps_build_config_methods(msg, methods);
+	return wps_build_config_methods(msg, reg->wps->config_methods);
 }
 
 
@@ -901,8 +895,8 @@
  * PBC mode. The PBC mode will be stopped after walk time (2 minutes) timeout
  * or when a PBC registration is completed. If more than one Enrollee in active
  * PBC mode has been detected during the monitor time (previous 2 minutes), the
- * PBC mode is not actived and -2 is returned to indicate session overlap. This
- * is skipped if a specific Enrollee is selected.
+ * PBC mode is not activated and -2 is returned to indicate session overlap.
+ * This is skipped if a specific Enrollee is selected.
  */
 int wps_registrar_button_pushed(struct wps_registrar *reg,
 				const u8 *p2p_dev_addr)
@@ -951,6 +945,18 @@
 }
 
 
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e)
+{
+	if (registrar->pbc) {
+		wps_registrar_remove_pbc_session(registrar,
+						 uuid_e, NULL);
+		wps_registrar_pbc_completed(registrar);
+	} else {
+		wps_registrar_pin_completed(registrar);
+	}
+}
+
+
 int wps_registrar_wps_cancel(struct wps_registrar *reg)
 {
 	if (reg->pbc) {
@@ -1420,6 +1426,25 @@
 }
 
 
+int wps_build_credential_wrap(struct wpabuf *msg,
+			      const struct wps_credential *cred)
+{
+	struct wpabuf *wbuf;
+	wbuf = wpabuf_alloc(200);
+	if (wbuf == NULL)
+		return -1;
+	if (wps_build_credential(wbuf, cred)) {
+		wpabuf_free(wbuf);
+		return -1;
+	}
+	wpabuf_put_be16(msg, ATTR_CRED);
+	wpabuf_put_be16(msg, wpabuf_len(wbuf));
+	wpabuf_put_buf(msg, wbuf);
+	wpabuf_free(wbuf);
+	return 0;
+}
+
+
 int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
 {
 	struct wpabuf *cred;
@@ -1593,6 +1618,35 @@
 }
 
 
+static struct wpabuf * wps_build_ap_cred(struct wps_data *wps)
+{
+	struct wpabuf *msg, *plain;
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	plain = wpabuf_alloc(200);
+	if (plain == NULL) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	if (wps_build_ap_settings(wps, plain)) {
+		wpabuf_free(plain);
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	wpabuf_put_be16(msg, ATTR_CRED);
+	wpabuf_put_be16(msg, wpabuf_len(plain));
+	wpabuf_put_buf(msg, plain);
+	wpabuf_free(plain);
+
+	return msg;
+}
+
+
 static struct wpabuf * wps_build_m2(struct wps_data *wps)
 {
 	struct wpabuf *msg;
@@ -2551,6 +2605,8 @@
 static int wps_process_ap_settings_r(struct wps_data *wps,
 				     struct wps_parse_attr *attr)
 {
+	struct wpabuf *msg;
+
 	if (wps->wps->ap || wps->er)
 		return 0;
 
@@ -2577,12 +2633,24 @@
 		 */
 		wps_registrar_pin_completed(wps->wps->registrar);
 
+		msg = wps_build_ap_cred(wps);
+		if (msg == NULL)
+			return -1;
+		wps->cred.cred_attr = wpabuf_head(msg);
+		wps->cred.cred_attr_len = wpabuf_len(msg);
+
 		if (wps->ap_settings_cb) {
 			wps->ap_settings_cb(wps->ap_settings_cb_ctx,
 					    &wps->cred);
+			wpabuf_free(msg);
 			return 1;
 		}
 		wps_sta_cred_cb(wps);
+
+		wps->cred.cred_attr = NULL;
+		wps->cred.cred_attr_len = 0;
+		wpabuf_free(msg);
+
 		return 1;
 	}
 }
@@ -2983,7 +3051,8 @@
 
 	if (wps->pbc) {
 		wps_registrar_remove_pbc_session(wps->wps->registrar,
-						 wps->uuid_e);
+						 wps->uuid_e,
+						 wps->p2p_dev_addr);
 		wps_registrar_pbc_completed(wps->wps->registrar);
 	} else {
 		wps_registrar_pin_completed(wps->wps->registrar);
diff --git a/src/wps/wps_ufd.c b/src/wps/wps_ufd.c
index 1a911e1..61f6553 100644
--- a/src/wps/wps_ufd.c
+++ b/src/wps/wps_ufd.c
@@ -16,7 +16,6 @@
 #include "common.h"
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
 #include <fcntl.h>
 #include <dirent.h>
 
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index 763dcaf..06dcd20 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -47,7 +47,7 @@
  * -- Needs renaming with module prefix to avoid polluting the debugger
  * namespace and causing possible collisions with other static fncs
  * and structure declarations when using the debugger.
- * -- The http error code generation is pretty bogus, hopefully noone cares.
+ * -- The http error code generation is pretty bogus, hopefully no one cares.
  *
  * Author: Ted Merrill, Atheros Communications, based upon earlier work
  * as explained above and below.
@@ -172,7 +172,7 @@
 
 #include "includes.h"
 
-#include <assert.h>
+#include <time.h>
 #include <net/if.h>
 #include <netdb.h>
 #include <sys/ioctl.h>
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index c7fb158..4c4aebf 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -97,16 +97,6 @@
 }
 
 
-/* No. of chars excluding trailing whitespace */
-static int line_length_stripped(const char *l)
-{
-	const char *lp = l + line_length(l);
-	while (lp > l && !isgraph(lp[-1]))
-		lp--;
-	return lp - l;
-}
-
-
 static int str_starts(const char *str, const char *start)
 {
 	return os_strncmp(str, start, os_strlen(start)) == 0;
@@ -530,7 +520,6 @@
 #ifndef CONFIG_NO_STDOUT_DEBUG
 	const char *start = data;
 #endif /* CONFIG_NO_STDOUT_DEBUG */
-	const char *end;
 	int got_host = 0;
 	int got_st = 0, st_match = 0;
 	int got_man = 0;
@@ -545,7 +534,6 @@
 
 	/* Parse remaining lines */
 	for (; *data != '\0'; data += line_length(data)) {
-		end = data + line_length_stripped(data);
 		if (token_eq(data, "host")) {
 			/* The host line indicates who the packet
 			 * is addressed to... but do we really care?
diff --git a/src/wps/wps_upnp_web.c b/src/wps/wps_upnp_web.c
index 917f60b..ce0bede 100644
--- a/src/wps/wps_upnp_web.c
+++ b/src/wps/wps_upnp_web.c
@@ -956,7 +956,7 @@
 			break; /* no unterminated lines allowed */
 
 		/* NT assures that it is our type of subscription;
-		 * not used for a renewl.
+		 * not used for a renewal.
 		 **/
 		match = "NT:";
 		match_len = os_strlen(match);