Accumulative patch from commit 1075b2957169d8f9d6dddd7679339c751dc9515b

1075b29 P2P: Report group formation failure on error to start GO mode
b62b29e Do not block on ctrl_iface monitor events
eb7ddbf WPS: Stop SSDP service before freeing the pending entries
98cbc0a Remove forgotten Xcode defines
0b9d3b2 Interworking: Relax 3GPP info PLMN matching for MNC
c7a67a7 WPS: Disconnect when removing existing WPS network block
fe65847 EAP-EKE: Add server implementation
7e7610d EAP-EKE: Add peer implementation
489202d EAP-SAKE: Use configured server identity
a607b42 EAP-PSK: Use configured server identity
15b042b EAP-MSCHAPv2: Use configured server identity
162865b EAP-IKEv2 server: Use configured server identity
8f89d82 EAP-GPSK server: Use configured server identity
67fe933 Add server identity configuration for EAP server
06aeff5 dbus: Register the AutoScan method call at the right place
78f79fe P2P: Do not add ctrl interface for P2P_DEVICE (p2p-dev-*)
1c42b42 P2P: Fix TDLS and l2_packet init without P2P Device interface
9e6a321 Fix non-P2P build after the P2P_DEVICE changes
d53d259 Fix build with older OpenSSL versions
54d4ba4 nl80211: Silence a compiler warning with older gcc versions
2e5ba4b P2P: Derive group interface name bit more sensibly
c68f620 P2P: Create P2P Device interface if supported
851b0c5 nl80211: Do not indicate P2P_DEVICE support by default
bb4028f P2P: Ignore p2p_no_group_iface when driver advertizes P2P_DEVICE support
7940c79 nl80211: Use wdev id when cancelling wait for frame using P2P_DEVICE
f608081 nl80211: Verify P2P GO/client address with all interface addresses
5fbcb45 nl80211: Fix determining phy name for P2P Device
27ce1d6 nl80211: Fix nl80211_get_wiphy_index() for P2P Device
080585c Add support for OCSP stapling to validate server certificate
72950ed P2P: Remove a call to wpas_p2p_deinit_global()
ab7a1ad nl80211: Fix P2P group interface creating using P2P Device
fa93de4 nl80211: Use wdev_id in nl80211_create_iface_once()
fdc554b nl80211: Use wdev id to obtain P2P Device scan results
597b94f nl80211: Add .get_mac_addr() callback for P2P Device
8e12685 nl80211: Rework setting interface mode
91724d6 nl80211: Introduce i802_set_iface_flags()
eb4582f nl80211: Remove P2P Device interface upon .deinit()
f632e48 nl80211: Fix P2P Device interface initialization
e472e1b nl80211: Handle creation of P2P Device interface
01517c8 nl80211: Allow Android P2P functionality
6bae92e nl80211: Add support for P2P Device in add interface
d6dcfcd nl80211: Add a handler to create_interface
d3aaef8 nl80211: Hold wdev identification for P2P Device
7aad838 nl80211: Identify if nl80211 is capable of P2P Device abstraction
6a71413 nl80211: Rename is_p2p_interface
8393e1a nl80211: Print interface name on set_key()
80ebfd9 VLAN: Avoid access to non-existing interfaces
4345fe9 bridge: Track inter-BSS usage
459eee9 bridge: Use safe default bridge interface
2aaeedf bridge: Give bridge name in per-bss configuration
8a901d7 D-Bus: Emit signal when a station is authorized or deauthorized
9578329 Add AVG_RSSI report in signal_poll
2cc8d8f Add bandwidth and center freq info to signal_poll
1e0e943 Remove 802.11b rates only in case of P2P group operation
2090a0b nl80211: Add prints for kernel events
8743676 TDLS: Validate ext_supp_rates in copy_supp_rates
85b4eac P2P: Do not reply to 802.11b-only Probe Request frames as GO
ec7b97a Interworking: Add support for using eap_proxy offload
4331263 Fix session timeout after ANQP dummy STA entry with SME-in-driver
56cb4e1 wpadebug: Add option to ignore SSL errors
aa20e1a Remove CONFIG_NO_WPA2 build parameter
5d5c4ee Remove compiler warnings with CONFIG_NO_SCAN_PROCESSING
9aaa695 Remove compiler warnings if TDLS is enabled without WPA2
84ae1d4 Fix WNM build without WPA2
c33d5eb Fix build without WPA2 or EAP
1aef400 IBSS RSN: Implement disconnect() callback using sta_deauth()

Change-Id: I4593be5b1478f6532da917423b1d2afa95fb8020
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 7ab86fc..fbc1ee0 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -440,6 +440,7 @@
 	os_free(conf->server_cert);
 	os_free(conf->private_key);
 	os_free(conf->private_key_passwd);
+	os_free(conf->ocsp_stapling_response);
 	os_free(conf->dh_file);
 	os_free(conf->pac_opaque_encr_key);
 	os_free(conf->eap_fast_a_id);
@@ -531,6 +532,8 @@
 	wpabuf_free(conf->vendor_elements);
 
 	os_free(conf->sae_groups);
+
+	os_free(conf->server_id);
 }
 
 
@@ -606,11 +609,23 @@
 }
 
 
-const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id)
 {
 	struct hostapd_vlan *v = vlan;
 	while (v) {
 		if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
+			return 1;
+		v = v->next;
+	}
+	return 0;
+}
+
+
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+{
+	struct hostapd_vlan *v = vlan;
+	while (v) {
+		if (v->vlan_id == vlan_id)
 			return v->ifname;
 		v = v->next;
 	}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 7c9ea90..a744ba6 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -180,6 +180,7 @@
 struct hostapd_bss_config {
 	char iface[IFNAMSIZ + 1];
 	char bridge[IFNAMSIZ + 1];
+	char vlan_bridge[IFNAMSIZ + 1];
 	char wds_bridge[IFNAMSIZ + 1];
 
 	enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
@@ -294,6 +295,7 @@
 	char *private_key;
 	char *private_key_passwd;
 	int check_crl;
+	char *ocsp_stapling_response;
 	char *dh_file;
 	u8 *pac_opaque_encr_key;
 	u8 *eap_fast_a_id;
@@ -373,6 +375,7 @@
 	struct wpabuf *wps_nfc_dev_pw;
 #endif /* CONFIG_WPS */
 	int pbc_in_m1;
+	char *server_id;
 
 #define P2P_ENABLED BIT(0)
 #define P2P_GROUP_OWNER BIT(1)
@@ -546,6 +549,7 @@
 const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
 			   const u8 *addr, const u8 *prev_psk);
 int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
+int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id);
 const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
 					int vlan_id);
 struct hostapd_radius_attr *
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index d66d97e..68ad4dc 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -111,6 +111,7 @@
 	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;
+	srv.server_id = conf->server_id ? conf->server_id : "hostapd";
 #ifdef CONFIG_RADIUS_TEST
 	srv.dump_msk_file = conf->dump_msk_file;
 #endif /* CONFIG_RADIUS_TEST */
@@ -148,6 +149,8 @@
 		params.private_key = hapd->conf->private_key;
 		params.private_key_passwd = hapd->conf->private_key_passwd;
 		params.dh_file = hapd->conf->dh_file;
+		params.ocsp_stapling_response =
+			hapd->conf->ocsp_stapling_response;
 
 		if (tls_global_set_params(hapd->ssl_ctx, &params)) {
 			wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 0ef307d..2f4ba23 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -485,6 +485,17 @@
 	}
 #endif /* CONFIG_INTERWORKING */
 
+#ifdef CONFIG_P2P
+	if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+	    supp_rates_11b_only(&elems)) {
+		/* Indicates support for 11b rates only */
+		wpa_printf(MSG_EXCESSIVE, "P2P: Ignore Probe Request from "
+			   MACSTR " with only 802.11b rates",
+			   MAC2STR(mgmt->sa));
+		return;
+	}
+#endif /* CONFIG_P2P */
+
 	/* TODO: verify that supp_rates contains at least one matching rate
 	 * with AP configuration */
 
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 07fd11d..fa4b5e4 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -85,6 +85,7 @@
 
 	sta = ap_get_sta(hapd, addr);
 	if (sta) {
+		ap_sta_no_session_timeout(hapd, sta);
 		accounting_sta_stop(hapd, sta);
 
 		/*
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 55f6dd8..75d9c66 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -25,6 +25,7 @@
 union wps_event_data;
 
 struct hostapd_iface;
+struct hostapd_dynamic_iface;
 
 struct hapd_interfaces {
 	int (*reload_config)(struct hostapd_iface *iface);
@@ -37,11 +38,13 @@
 	int (*driver_init)(struct hostapd_iface *iface);
 
 	size_t count;
+	size_t count_dynamic;
 	int global_ctrl_sock;
 	char *global_iface_path;
 	char *global_iface_name;
 	gid_t ctrl_iface_group;
 	struct hostapd_iface **iface;
+	struct hostapd_dynamic_iface **dynamic_iface;
 };
 
 
@@ -275,6 +278,16 @@
 	void (*scan_cb)(struct hostapd_iface *iface);
 };
 
+/**
+ * struct hostapd_dynamic_iface - hostapd per dynamically allocated
+ * or added interface data structure
+ */
+struct hostapd_dynamic_iface {
+	char parent[IFNAMSIZ + 1];
+	char iface[IFNAMSIZ + 1];
+	unsigned int usage;
+};
+
 /* hostapd.c */
 int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
 			       int (*cb)(struct hostapd_iface *iface,
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 2e570c0..5503af1 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -650,8 +650,7 @@
 	}
 
 	if (vlan_id > 0) {
-		if (hostapd_get_vlan_id_ifname(hapd->conf->vlan,
-					       vlan_id) == NULL) {
+		if (!hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
 			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
 				       HOSTAPD_LEVEL_INFO, "Invalid VLAN ID "
 				       "%d received from RADIUS server",
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index a28c0f8..3554e8b 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1438,8 +1438,7 @@
 			sta->vlan_id = radius_msg_get_vlanid(msg);
 		}
 		if (sta->vlan_id > 0 &&
-		    hostapd_get_vlan_id_ifname(hapd->conf->vlan,
-					       sta->vlan_id)) {
+		    hostapd_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) {
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_RADIUS,
 				       HOSTAPD_LEVEL_INFO,
@@ -1829,6 +1828,13 @@
 	conf.fragment_size = hapd->conf->fragment_size;
 	conf.pwd_group = hapd->conf->pwd_group;
 	conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
+	if (hapd->conf->server_id) {
+		conf.server_id = (const u8 *) hapd->conf->server_id;
+		conf.server_id_len = os_strlen(hapd->conf->server_id);
+	} else {
+		conf.server_id = (const u8 *) "hostapd";
+		conf.server_id_len = 7;
+	}
 
 	os_memset(&cb, 0, sizeof(cb));
 	cb.eapol_send = ieee802_1x_eapol_send;
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 6390e8b..70affda 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -480,6 +480,123 @@
 #endif /* CONFIG_VLAN_NETLINK */
 
 
+/**
+ * Increase the usage counter for given parent/ifname combination.
+ * If create is set, then this iface is added to the global list.
+ * Returns
+ * 	-1 on error
+ * 	0 if iface is not in list
+ * 	1 if iface is in list (was there or has been added)
+ */
+static int hapd_get_dynamic_iface(const char *parent, const char *ifname,
+				  int create, struct hostapd_data *hapd)
+{
+	size_t i;
+	struct hostapd_dynamic_iface *j = NULL, **tmp;
+	struct hapd_interfaces *hapd_global = hapd->iface->interfaces;
+
+	if (!parent)
+		parent = "";
+
+	for (i = 0; i < hapd_global->count_dynamic; i++) {
+		j = hapd_global->dynamic_iface[i];
+		if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 &&
+		    os_strncmp(j->parent, parent, sizeof(j->parent)) == 0)
+			break;
+	}
+	if (i < hapd_global->count_dynamic) {
+		j->usage++;
+		return 1;
+	}
+
+	/* new entry required */
+	if (!create)
+		return 0;
+
+	j = os_zalloc(sizeof(*j));
+	if (!j)
+		return -1;
+	os_strlcpy(j->iface, ifname, sizeof(j->iface));
+	os_strlcpy(j->parent, parent, sizeof(j->parent));
+
+	tmp = os_realloc_array(hapd_global->dynamic_iface, i + 1,
+			       sizeof(*hapd_global->dynamic_iface));
+	if (!tmp) {
+		wpa_printf(MSG_ERROR, "VLAN: Failed to allocate memory in %s",
+			   __func__);
+		return -1;
+	}
+	hapd_global->count_dynamic++;
+	hapd_global->dynamic_iface = tmp;
+	hapd_global->dynamic_iface[i] = j;
+
+	return 1;
+}
+
+
+/**
+ * Decrease the usage counter for given ifname.
+ * Returns
+ *     -1 on error or if iface was not found
+ *     0 if iface was found and is still present
+ *     1 if iface was removed from global list
+ */
+static int hapd_put_dynamic_iface(const char *parent, const char *ifname,
+				  struct hostapd_data *hapd)
+{
+	size_t i;
+	struct hostapd_dynamic_iface *j = NULL, **tmp;
+	struct hapd_interfaces *hapd_glob = hapd->iface->interfaces;
+
+	if (!parent)
+		parent = "";
+
+	for (i = 0; i < hapd_glob->count_dynamic; i++) {
+		j = hapd_glob->dynamic_iface[i];
+		if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 &&
+		    os_strncmp(j->parent, parent, sizeof(j->parent)) == 0)
+			break;
+	}
+
+	if (i == hapd_glob->count_dynamic) {
+		/*
+		 * Interface not in global list. This can happen if alloc in
+		 * _get_ failed.
+		 */
+		return -1;
+	}
+
+	if (j->usage > 0) {
+		j->usage--;
+		return 0;
+	}
+
+	os_free(j);
+	for (; i < hapd_glob->count_dynamic - 1; i++)
+		hapd_glob->dynamic_iface[i] = hapd_glob->dynamic_iface[i + 1];
+	hapd_glob->dynamic_iface[hapd_glob->count_dynamic - 1] = NULL;
+	hapd_glob->count_dynamic--;
+
+	if (hapd_glob->count_dynamic == 0) {
+		os_free(hapd_glob->dynamic_iface);
+		hapd_glob->dynamic_iface = NULL;
+		return 1;
+	}
+
+	tmp = os_realloc_array(hapd_glob->dynamic_iface,
+			       hapd_glob->count_dynamic,
+			       sizeof(*hapd_glob->dynamic_iface));
+	if (!tmp) {
+		wpa_printf(MSG_ERROR, "VLAN: Failed to release memory in %s",
+			   __func__);
+		return -1;
+	}
+	hapd_glob->dynamic_iface = tmp;
+
+	return 1;
+}
+
+
 static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
 {
 	char vlan_ifname[IFNAMSIZ];
@@ -487,16 +604,29 @@
 	struct hostapd_vlan *vlan = hapd->conf->vlan;
 	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
 	int vlan_naming = hapd->conf->ssid.vlan_naming;
+	int ret;
 
 	wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
 
 	while (vlan) {
 		if (os_strcmp(ifname, vlan->ifname) == 0) {
 
-			os_snprintf(br_name, sizeof(br_name), "brvlan%d",
-				    vlan->vlan_id);
+			if (hapd->conf->vlan_bridge[0]) {
+				os_snprintf(br_name, sizeof(br_name), "%s%d",
+					    hapd->conf->vlan_bridge,
+					    vlan->vlan_id);
+			} else if (tagged_interface) {
+				os_snprintf(br_name, sizeof(br_name),
+				            "br%s.%d", tagged_interface,
+					    vlan->vlan_id);
+			} else {
+				os_snprintf(br_name, sizeof(br_name),
+				            "brvlan%d", vlan->vlan_id);
+			}
 
-			if (!br_addbr(br_name))
+			ret = br_addbr(br_name);
+			if (hapd_get_dynamic_iface(NULL, br_name, ret == 0,
+			                           hapd))
 				vlan->clean |= DVLAN_CLEAN_BR;
 
 			ifconfig_up(br_name);
@@ -514,17 +644,24 @@
 						    "vlan%d", vlan->vlan_id);
 
 				ifconfig_up(tagged_interface);
-				if (!vlan_add(tagged_interface, vlan->vlan_id,
-					      vlan_ifname))
+				ret = vlan_add(tagged_interface, vlan->vlan_id,
+					      vlan_ifname);
+				if (hapd_get_dynamic_iface(NULL, vlan_ifname,
+				                           ret == 0, hapd))
 					vlan->clean |= DVLAN_CLEAN_VLAN;
 
-				if (!br_addif(br_name, vlan_ifname))
+				ret = br_addif(br_name, vlan_ifname);
+				if (hapd_get_dynamic_iface(br_name,
+							   vlan_ifname,
+							   ret == 0, hapd))
 					vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
 
 				ifconfig_up(vlan_ifname);
 			}
 
-			if (!br_addif(br_name, ifname))
+			ret = br_addif(br_name, ifname);
+			if (hapd_get_dynamic_iface(br_name, ifname, ret == 0,
+						   hapd))
 				vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
 
 			ifconfig_up(ifname);
@@ -550,10 +687,21 @@
 
 	while (vlan) {
 		if (os_strcmp(ifname, vlan->ifname) == 0) {
-			os_snprintf(br_name, sizeof(br_name), "brvlan%d",
-				    vlan->vlan_id);
+			if (hapd->conf->vlan_bridge[0]) {
+				os_snprintf(br_name, sizeof(br_name), "%s%d",
+					    hapd->conf->vlan_bridge,
+					    vlan->vlan_id);
+			} else if (tagged_interface) {
+				os_snprintf(br_name, sizeof(br_name),
+				            "br%s.%d", tagged_interface,
+					    vlan->vlan_id);
+			} else {
+				os_snprintf(br_name, sizeof(br_name),
+				            "brvlan%d", vlan->vlan_id);
+			}
 
-			if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
+			if ((vlan->clean & DVLAN_CLEAN_WLAN_PORT) &&
+			    hapd_put_dynamic_iface(br_name, vlan->ifname, hapd))
 				br_delif(br_name, vlan->ifname);
 
 			if (tagged_interface) {
@@ -567,15 +715,20 @@
 					os_snprintf(vlan_ifname,
 						    sizeof(vlan_ifname),
 						    "vlan%d", vlan->vlan_id);
-				if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
+				if ((vlan->clean & DVLAN_CLEAN_VLAN_PORT) &&
+				    hapd_put_dynamic_iface(br_name, vlan_ifname,
+							   hapd))
 					br_delif(br_name, vlan_ifname);
 				ifconfig_down(vlan_ifname);
 
-				if (vlan->clean & DVLAN_CLEAN_VLAN)
+				if ((vlan->clean & DVLAN_CLEAN_VLAN) &&
+				    hapd_put_dynamic_iface(NULL, vlan_ifname,
+							   hapd))
 					vlan_rem(vlan_ifname);
 			}
 
 			if ((vlan->clean & DVLAN_CLEAN_BR) &&
+			    hapd_put_dynamic_iface(NULL, br_name, hapd) &&
 			    br_getnumports(br_name) == 0) {
 				ifconfig_down(br_name);
 				br_delbr(br_name);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 407b066..aab8ac6 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -512,3 +512,36 @@
 
 	return mode;
 }
+
+
+static int is_11b(u8 rate)
+{
+	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
+}
+
+
+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;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 7f59cf2..68c6b96 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -101,4 +101,6 @@
 			  const char *name, const char *val);
 enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
 
+int supp_rates_11b_only(struct ieee802_11_elems *elems);
+
 #endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index a8cf6be..c3afbfd 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -335,7 +335,6 @@
 #endif /* CONFIG_IEEE80211R */
 
 
-#ifndef CONFIG_NO_WPA2
 static int rsn_selector_to_bitfield(const u8 *s)
 {
 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
@@ -384,7 +383,6 @@
 #endif /* CONFIG_SAE */
 	return 0;
 }
-#endif /* CONFIG_NO_WPA2 */
 
 
 /**
@@ -397,7 +395,6 @@
 int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
 			 struct wpa_ie_data *data)
 {
-#ifndef CONFIG_NO_WPA2
 	const struct rsn_ie_hdr *hdr;
 	const u8 *pos;
 	int left;
@@ -551,9 +548,6 @@
 	}
 
 	return 0;
-#else /* CONFIG_NO_WPA2 */
-	return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index b61e439..2fdaa02 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -1,6 +1,6 @@
 /*
  * SSL/TLS interface definition
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -82,6 +82,8 @@
 #define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
 #define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
 #define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
+#define TLS_CONN_REQUEST_OCSP BIT(3)
+#define TLS_CONN_REQUIRE_OCSP BIT(4)
 
 /**
  * struct tls_connection_params - Parameters for TLS connection
@@ -117,6 +119,8 @@
  * @cert_id: the certificate's id when using engine
  * @ca_cert_id: the CA certificate's id when using engine
  * @flags: Parameter options (TLS_CONN_*)
+ * @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
+ *	or %NULL if OCSP is not enabled
  *
  * TLS connection parameters to be configured with tls_connection_set_params()
  * and tls_global_set_params().
@@ -153,6 +157,7 @@
 	const char *ca_cert_id;
 
 	unsigned int flags;
+	const char *ocsp_stapling_response;
 };
 
 
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index fec8e38..90acf84 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -1,6 +1,6 @@
 /*
  * SSL/TLS interface functions for OpenSSL
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -65,6 +65,13 @@
 }
 #endif /* ANDROID */
 
+#ifdef SSL_set_tlsext_status_type
+#ifndef OPENSSL_NO_TLSEXT
+#define HAVE_OCSP
+#include <openssl/ocsp.h>
+#endif /* OPENSSL_NO_TLSEXT */
+#endif /* SSL_set_tlsext_status_type */
+
 static int tls_openssl_ref_count = 0;
 
 struct tls_context {
@@ -72,6 +79,7 @@
 			 union tls_event_data *data);
 	void *cb_ctx;
 	int cert_in_cb;
+	char *ocsp_stapling_response;
 };
 
 static struct tls_context *tls_global = NULL;
@@ -102,6 +110,9 @@
 	u8 srv_cert_hash[32];
 
 	unsigned int flags;
+
+	X509 *peer_cert;
+	X509 *peer_issuer;
 };
 
 
@@ -841,6 +852,8 @@
 		ERR_remove_state(0);
 		ERR_free_strings();
 		EVP_cleanup();
+		os_free(tls_global->ocsp_stapling_response);
+		tls_global->ocsp_stapling_response = NULL;
 		os_free(tls_global);
 		tls_global = NULL;
 	}
@@ -1267,6 +1280,12 @@
 	conn = SSL_get_app_data(ssl);
 	if (conn == NULL)
 		return 0;
+
+	if (depth == 0)
+		conn->peer_cert = err_cert;
+	else if (depth == 1)
+		conn->peer_issuer = err_cert;
+
 	context = conn->context;
 	match = conn->subject_match;
 	altmatch = conn->altsubject_match;
@@ -2768,11 +2787,187 @@
 }
 
 
+#ifdef HAVE_OCSP
+
+static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	extern int wpa_debug_level;
+	BIO *out;
+	size_t rlen;
+	char *txt;
+	int res;
+
+	if (wpa_debug_level > MSG_DEBUG)
+		return;
+
+	out = BIO_new(BIO_s_mem());
+	if (!out)
+		return;
+
+	OCSP_RESPONSE_print(out, rsp, 0);
+	rlen = BIO_ctrl_pending(out);
+	txt = os_malloc(rlen + 1);
+	if (!txt) {
+		BIO_free(out);
+		return;
+	}
+
+	res = BIO_read(out, txt, rlen);
+	if (res > 0) {
+		txt[res] = '\0';
+		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt);
+	}
+	os_free(txt);
+	BIO_free(out);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static int ocsp_resp_cb(SSL *s, void *arg)
+{
+	struct tls_connection *conn = arg;
+	const unsigned char *p;
+	int len, status, reason;
+	OCSP_RESPONSE *rsp;
+	OCSP_BASICRESP *basic;
+	OCSP_CERTID *id;
+	ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update;
+
+	len = SSL_get_tlsext_status_ocsp_resp(s, &p);
+	if (!p) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
+		return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len);
+
+	rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
+	if (!rsp) {
+		wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response");
+		return 0;
+	}
+
+	ocsp_debug_print_resp(rsp);
+
+	status = OCSP_response_status(rsp);
+	if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+		wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)",
+			   status, OCSP_response_status_str(status));
+		return 0;
+	}
+
+	basic = OCSP_response_get1_basic(rsp);
+	if (!basic) {
+		wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse");
+		return 0;
+	}
+
+	status = OCSP_basic_verify(basic, NULL, SSL_CTX_get_cert_store(s->ctx),
+				   0);
+	if (status <= 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"OpenSSL: OCSP response failed verification");
+		OCSP_BASICRESP_free(basic);
+		OCSP_RESPONSE_free(rsp);
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded");
+
+	if (!conn->peer_cert || !conn->peer_issuer) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate or issue certificate not available for OCSP status check");
+		OCSP_BASICRESP_free(basic);
+		OCSP_RESPONSE_free(rsp);
+		return 0;
+	}
+
+	id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
+	if (!id) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier");
+		OCSP_BASICRESP_free(basic);
+		OCSP_RESPONSE_free(rsp);
+		return 0;
+	}
+
+	if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
+				   &this_update, &next_update)) {
+		wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
+			   (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
+			   " (OCSP not required)");
+		OCSP_BASICRESP_free(basic);
+		OCSP_RESPONSE_free(rsp);
+		return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
+	}
+
+	if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
+		tls_show_errors(MSG_INFO, __func__,
+				"OpenSSL: OCSP status times invalid");
+		OCSP_BASICRESP_free(basic);
+		OCSP_RESPONSE_free(rsp);
+		return 0;
+	}
+
+	OCSP_BASICRESP_free(basic);
+	OCSP_RESPONSE_free(rsp);
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s",
+		   OCSP_cert_status_str(status));
+
+	if (status == V_OCSP_CERTSTATUS_GOOD)
+		return 1;
+	if (status == V_OCSP_CERTSTATUS_REVOKED)
+		return 0;
+	if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
+		return 0;
+	}
+		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
+	return 1;
+}
+
+
+static int ocsp_status_cb(SSL *s, void *arg)
+{
+	char *tmp;
+	char *resp;
+	size_t len;
+
+	if (tls_global->ocsp_stapling_response == NULL) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured");
+		return SSL_TLSEXT_ERR_OK;
+	}
+
+	resp = os_readfile(tls_global->ocsp_stapling_response, &len);
+	if (resp == NULL) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file");
+		/* TODO: Build OCSPResponse with responseStatus = internalError
+		 */
+		return SSL_TLSEXT_ERR_OK;
+	}
+	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response");
+	tmp = OPENSSL_malloc(len);
+	if (tmp == NULL) {
+		os_free(resp);
+		return SSL_TLSEXT_ERR_ALERT_FATAL;
+	}
+
+	os_memcpy(tmp, resp, len);
+	os_free(resp);
+	SSL_set_tlsext_status_ocsp_resp(s, tmp, len);
+
+	return SSL_TLSEXT_ERR_OK;
+}
+
+#endif /* HAVE_OCSP */
+
+
 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 			      const struct tls_connection_params *params)
 {
 	int ret;
 	unsigned long err;
+	SSL_CTX *ssl_ctx = tls_ctx;
 
 	if (conn == NULL)
 		return -1;
@@ -2836,10 +3031,20 @@
 #ifdef SSL_OP_NO_TICKET
 	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
 		SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
+#ifdef SSL_clear_options
 	else
 		SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
+#endif /* SSL_clear_options */
 #endif /*  SSL_OP_NO_TICKET */
 
+#ifdef HAVE_OCSP
+	if (params->flags & TLS_CONN_REQUEST_OCSP) {
+		SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
+		SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
+		SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
+	}
+#endif /* HAVE_OCSP */
+
 	conn->flags = params->flags;
 
 	tls_get_errors(tls_ctx);
@@ -2878,10 +3083,23 @@
 #ifdef SSL_OP_NO_TICKET
 	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
 		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
+#ifdef SSL_CTX_clear_options
 	else
 		SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
+#endif /* SSL_clear_options */
 #endif /*  SSL_OP_NO_TICKET */
 
+#ifdef HAVE_OCSP
+	SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb);
+	SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx);
+	os_free(tls_global->ocsp_stapling_response);
+	if (params->ocsp_stapling_response)
+		tls_global->ocsp_stapling_response =
+			os_strdup(params->ocsp_stapling_response);
+	else
+		tls_global->ocsp_stapling_response = NULL;
+#endif /* HAVE_OCSP */
+
 	return 0;
 }
 
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 0f92b18..0604fef 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -830,7 +830,7 @@
  * it cannot be used for P2P group operations or non-P2P purposes.
  */
 #define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE	0x00000400
-/* This interface is P2P capable (P2P Device, GO, or P2P Client */
+/* This interface is P2P capable (P2P GO or P2P Client) */
 #define WPA_DRIVER_FLAGS_P2P_CAPABLE	0x00000800
 /* Driver supports concurrent operations on multiple channels */
 #define WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT	0x00001000
@@ -874,6 +874,8 @@
 #define WPA_DRIVER_FLAGS_IBSS				0x08000000
 /* Driver supports radar detection */
 #define WPA_DRIVER_FLAGS_RADAR				0x10000000
+/* Driver supports a dedicated interface for P2P Device */
+#define WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE		0x20000000
 	unsigned int flags;
 
 	int max_scan_ssids;
@@ -1013,7 +1015,13 @@
 	 * WPA_IF_P2P_GROUP - P2P Group interface (will become either
 	 * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known)
 	 */
-	WPA_IF_P2P_GROUP
+	WPA_IF_P2P_GROUP,
+
+	/**
+	 * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
+	 * abstracted P2P Device function in the driver
+	 */
+	WPA_IF_P2P_DEVICE
 };
 
 struct wpa_init_params {
@@ -1090,6 +1098,17 @@
 	WNM_SLEEP_TFS_IE_DEL        /* AP delete the TFS IE */
 };
 
+/* enum chan_width - Channel width definitions */
+enum chan_width {
+	CHAN_WIDTH_20_NOHT,
+	CHAN_WIDTH_20,
+	CHAN_WIDTH_40,
+	CHAN_WIDTH_80,
+	CHAN_WIDTH_80P80,
+	CHAN_WIDTH_160,
+	CHAN_WIDTH_UNKNOWN
+};
+
 /**
  * struct wpa_signal_info - Information about channel signal quality
  */
@@ -1097,8 +1116,12 @@
 	u32 frequency;
 	int above_threshold;
 	int current_signal;
+	int avg_signal;
 	int current_noise;
 	int current_txrate;
+	enum chan_width chanwidth;
+	int center_frq1;
+	int center_frq2;
 };
 
 /**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index cbc80e3..bcd0a94 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -157,6 +157,8 @@
 struct nl80211_global {
 	struct dl_list interfaces;
 	int if_add_ifindex;
+	u64 if_add_wdevid;
+	int if_add_wdevid_set;
 	struct netlink_data *netlink;
 	struct nl_cb *nl_cb;
 	struct nl_handle *nl;
@@ -183,12 +185,14 @@
 	struct wpa_driver_nl80211_data *drv;
 	struct i802_bss *next;
 	int ifindex;
+	u64 wdev_id;
 	char ifname[IFNAMSIZ + 1];
 	char brname[IFNAMSIZ];
 	unsigned int beacon_set:1;
 	unsigned int added_if_into_bridge:1;
 	unsigned int added_bridge:1;
 	unsigned int in_deinit:1;
+	unsigned int wdev_id_set:1;
 
 	u8 addr[ETH_ALEN];
 
@@ -249,6 +253,7 @@
 	unsigned int retry_auth:1;
 	unsigned int use_monitor:1;
 	unsigned int ignore_next_local_disconnect:1;
+	unsigned int allow_p2p_device:1;
 
 	u64 remain_on_chan_cookie;
 	u64 send_action_cookie;
@@ -357,6 +362,117 @@
 	struct wpa_driver_nl80211_data *drv);
 
 
+static const char * nl80211_command_to_string(enum nl80211_commands cmd)
+{
+#define C2S(x) case x: return #x;
+	switch (cmd) {
+	C2S(NL80211_CMD_UNSPEC)
+	C2S(NL80211_CMD_GET_WIPHY)
+	C2S(NL80211_CMD_SET_WIPHY)
+	C2S(NL80211_CMD_NEW_WIPHY)
+	C2S(NL80211_CMD_DEL_WIPHY)
+	C2S(NL80211_CMD_GET_INTERFACE)
+	C2S(NL80211_CMD_SET_INTERFACE)
+	C2S(NL80211_CMD_NEW_INTERFACE)
+	C2S(NL80211_CMD_DEL_INTERFACE)
+	C2S(NL80211_CMD_GET_KEY)
+	C2S(NL80211_CMD_SET_KEY)
+	C2S(NL80211_CMD_NEW_KEY)
+	C2S(NL80211_CMD_DEL_KEY)
+	C2S(NL80211_CMD_GET_BEACON)
+	C2S(NL80211_CMD_SET_BEACON)
+	C2S(NL80211_CMD_START_AP)
+	C2S(NL80211_CMD_STOP_AP)
+	C2S(NL80211_CMD_GET_STATION)
+	C2S(NL80211_CMD_SET_STATION)
+	C2S(NL80211_CMD_NEW_STATION)
+	C2S(NL80211_CMD_DEL_STATION)
+	C2S(NL80211_CMD_GET_MPATH)
+	C2S(NL80211_CMD_SET_MPATH)
+	C2S(NL80211_CMD_NEW_MPATH)
+	C2S(NL80211_CMD_DEL_MPATH)
+	C2S(NL80211_CMD_SET_BSS)
+	C2S(NL80211_CMD_SET_REG)
+	C2S(NL80211_CMD_REQ_SET_REG)
+	C2S(NL80211_CMD_GET_MESH_CONFIG)
+	C2S(NL80211_CMD_SET_MESH_CONFIG)
+	C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+	C2S(NL80211_CMD_GET_REG)
+	C2S(NL80211_CMD_GET_SCAN)
+	C2S(NL80211_CMD_TRIGGER_SCAN)
+	C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+	C2S(NL80211_CMD_SCAN_ABORTED)
+	C2S(NL80211_CMD_REG_CHANGE)
+	C2S(NL80211_CMD_AUTHENTICATE)
+	C2S(NL80211_CMD_ASSOCIATE)
+	C2S(NL80211_CMD_DEAUTHENTICATE)
+	C2S(NL80211_CMD_DISASSOCIATE)
+	C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+	C2S(NL80211_CMD_REG_BEACON_HINT)
+	C2S(NL80211_CMD_JOIN_IBSS)
+	C2S(NL80211_CMD_LEAVE_IBSS)
+	C2S(NL80211_CMD_TESTMODE)
+	C2S(NL80211_CMD_CONNECT)
+	C2S(NL80211_CMD_ROAM)
+	C2S(NL80211_CMD_DISCONNECT)
+	C2S(NL80211_CMD_SET_WIPHY_NETNS)
+	C2S(NL80211_CMD_GET_SURVEY)
+	C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+	C2S(NL80211_CMD_SET_PMKSA)
+	C2S(NL80211_CMD_DEL_PMKSA)
+	C2S(NL80211_CMD_FLUSH_PMKSA)
+	C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+	C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+	C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+	C2S(NL80211_CMD_REGISTER_FRAME)
+	C2S(NL80211_CMD_FRAME)
+	C2S(NL80211_CMD_FRAME_TX_STATUS)
+	C2S(NL80211_CMD_SET_POWER_SAVE)
+	C2S(NL80211_CMD_GET_POWER_SAVE)
+	C2S(NL80211_CMD_SET_CQM)
+	C2S(NL80211_CMD_NOTIFY_CQM)
+	C2S(NL80211_CMD_SET_CHANNEL)
+	C2S(NL80211_CMD_SET_WDS_PEER)
+	C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+	C2S(NL80211_CMD_JOIN_MESH)
+	C2S(NL80211_CMD_LEAVE_MESH)
+	C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+	C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+	C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+	C2S(NL80211_CMD_GET_WOWLAN)
+	C2S(NL80211_CMD_SET_WOWLAN)
+	C2S(NL80211_CMD_START_SCHED_SCAN)
+	C2S(NL80211_CMD_STOP_SCHED_SCAN)
+	C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+	C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+	C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+	C2S(NL80211_CMD_PMKSA_CANDIDATE)
+	C2S(NL80211_CMD_TDLS_OPER)
+	C2S(NL80211_CMD_TDLS_MGMT)
+	C2S(NL80211_CMD_UNEXPECTED_FRAME)
+	C2S(NL80211_CMD_PROBE_CLIENT)
+	C2S(NL80211_CMD_REGISTER_BEACONS)
+	C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+	C2S(NL80211_CMD_SET_NOACK_MAP)
+	C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+	C2S(NL80211_CMD_START_P2P_DEVICE)
+	C2S(NL80211_CMD_STOP_P2P_DEVICE)
+	C2S(NL80211_CMD_CONN_FAILED)
+	C2S(NL80211_CMD_SET_MCAST_RATE)
+	C2S(NL80211_CMD_SET_MAC_ACL)
+	C2S(NL80211_CMD_RADAR_DETECT)
+	C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+	C2S(NL80211_CMD_UPDATE_FT_IES)
+	C2S(NL80211_CMD_FT_EVENT)
+	C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+	C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+	default:
+		return "NL80211_CMD_UNKNOWN";
+	}
+#undef C2S
+}
+
+
 static int is_ap_interface(enum nl80211_iftype nlmode)
 {
 	return (nlmode == NL80211_IFTYPE_AP ||
@@ -371,7 +487,7 @@
 }
 
 
-static int is_p2p_interface(enum nl80211_iftype nlmode)
+static int is_p2p_net_interface(enum nl80211_iftype nlmode)
 {
 	return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
 		nlmode == NL80211_IFTYPE_P2P_GO);
@@ -491,6 +607,19 @@
 };
 
 
+static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
+{
+	if (bss->wdev_id_set)
+		NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+	else
+		NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+
 static int family_handler(struct nl_msg *msg, void *arg)
 {
 	struct family_data *res = arg;
@@ -557,6 +686,8 @@
 
 struct wiphy_idx_data {
 	int wiphy_idx;
+	enum nl80211_iftype nlmode;
+	u8 *macaddr;
 };
 
 
@@ -572,6 +703,13 @@
 	if (tb[NL80211_ATTR_WIPHY])
 		info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
 
+	if (tb[NL80211_ATTR_IFTYPE])
+		info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
+
+	if (tb[NL80211_ATTR_MAC] && info->macaddr)
+		os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+			  ETH_ALEN);
+
 	return NL_SKIP;
 }
 
@@ -581,15 +719,17 @@
 	struct nl_msg *msg;
 	struct wiphy_idx_data data = {
 		.wiphy_idx = -1,
+		.macaddr = NULL,
 	};
 
 	msg = nlmsg_alloc();
 	if (!msg)
-		return -1;
+		return NL80211_IFTYPE_UNSPECIFIED;
 
 	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
 
 	if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
 		return data.wiphy_idx;
@@ -600,6 +740,57 @@
 }
 
 
+static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
+{
+	struct nl_msg *msg;
+	struct wiphy_idx_data data = {
+		.nlmode = NL80211_IFTYPE_UNSPECIFIED,
+		.macaddr = NULL,
+	};
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
+
+	if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+		return data.nlmode;
+	msg = NULL;
+nla_put_failure:
+	nlmsg_free(msg);
+	return NL80211_IFTYPE_UNSPECIFIED;
+}
+
+
+#ifndef HOSTAPD
+static int nl80211_get_macaddr(struct i802_bss *bss)
+{
+	struct nl_msg *msg;
+	struct wiphy_idx_data data = {
+		.macaddr = bss->addr,
+	};
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return NL80211_IFTYPE_UNSPECIFIED;
+
+	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
+
+	return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return NL80211_IFTYPE_UNSPECIFIED;
+}
+#endif /* HOSTAPD */
+
+
 static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
 				    struct nl80211_wiphy_data *w)
 {
@@ -1532,22 +1723,26 @@
 	}
 
 	if (frame == NULL) {
-		wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
-			   "data", cmd);
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: MLME event %d (%s) without frame data",
+			   cmd, nl80211_command_to_string(cmd));
 		return;
 	}
 
 	data = nla_data(frame);
 	len = nla_len(frame);
 	if (len < 4 + 2 * ETH_ALEN) {
-		wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d on %s(" MACSTR
-			   ") - too short",
-			   cmd, bss->ifname, MAC2STR(bss->addr));
+		wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
+			   MACSTR ") - too short",
+			   cmd, nl80211_command_to_string(cmd), bss->ifname,
+			   MAC2STR(bss->addr));
 		return;
 	}
-	wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d on %s(" MACSTR ") A1="
-		   MACSTR " A2=" MACSTR, cmd, bss->ifname, MAC2STR(bss->addr),
-		   MAC2STR(data + 4), MAC2STR(data + 4 + ETH_ALEN));
+	wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
+		   ") A1=" MACSTR " A2=" MACSTR, cmd,
+		   nl80211_command_to_string(cmd), bss->ifname,
+		   MAC2STR(bss->addr), MAC2STR(data + 4),
+		   MAC2STR(data + 4 + ETH_ALEN));
 	if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
 	    os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
 	    os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
@@ -1780,6 +1975,7 @@
 	struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
 	static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
 		[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+		[NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
 	};
 	struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
 	static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -1802,6 +1998,12 @@
 	sig_change->current_signal =
 		(s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
 
+	if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
+		sig_change->avg_signal =
+			(s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
+	else
+		sig_change->avg_signal = 0;
+
 	if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
 		if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
 				     sinfo[NL80211_STA_INFO_TX_BITRATE],
@@ -2341,6 +2543,9 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
+	wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
+		   cmd, nl80211_command_to_string(cmd), bss->ifname);
+
 	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
 	    (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
 	     cmd == NL80211_CMD_SCAN_ABORTED)) {
@@ -2484,19 +2689,31 @@
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
-	if (tb[NL80211_ATTR_IFINDEX])
+	if (tb[NL80211_ATTR_IFINDEX]) {
 		ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
 
-	for (bss = &drv->first_bss; bss; bss = bss->next) {
-		if (ifidx == -1 || ifidx == bss->ifindex) {
-			do_process_drv_event(bss, gnlh->cmd, tb);
-			return NL_SKIP;
+		for (bss = &drv->first_bss; bss; bss = bss->next)
+			if (ifidx == -1 || ifidx == bss->ifindex) {
+				do_process_drv_event(bss, gnlh->cmd, tb);
+				return NL_SKIP;
+			}
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d)",
+			   gnlh->cmd, ifidx);
+	} else if (tb[NL80211_ATTR_WDEV]) {
+		u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+		wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device");
+		for (bss = &drv->first_bss; bss; bss = bss->next) {
+			if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
+				do_process_drv_event(bss, gnlh->cmd, tb);
+				return NL_SKIP;
+			}
 		}
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)",
+			   gnlh->cmd, (long long unsigned int) wdev_id);
 	}
 
-	wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d) for foreign "
-		   "interface (ifindex %d)", gnlh->cmd, ifidx);
-
 	return NL_SKIP;
 }
 
@@ -2509,17 +2726,26 @@
 	struct wpa_driver_nl80211_data *drv, *tmp;
 	int ifidx = -1;
 	struct i802_bss *bss;
+	u64 wdev_id = 0;
+	int wdev_id_set = 0;
 
 	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]);
+	else if (tb[NL80211_ATTR_WDEV]) {
+		wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+		wdev_id_set = 1;
+	}
 
 	dl_list_for_each_safe(drv, tmp, &global->interfaces,
 			      struct wpa_driver_nl80211_data, list) {
 		for (bss = &drv->first_bss; bss; bss = bss->next) {
-			if (ifidx == -1 || ifidx == bss->ifindex) {
+			if ((ifidx == -1 && !wdev_id_set) ||
+			    ifidx == bss->ifindex ||
+			    (wdev_id_set && bss->wdev_id_set &&
+			     wdev_id == bss->wdev_id)) {
 				do_process_drv_event(bss, gnlh->cmd, tb);
 				return NL_SKIP;
 			}
@@ -2539,6 +2765,10 @@
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
+	wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s",
+		   gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
+		   bss->ifname);
+
 	switch (gnlh->cmd) {
 	case NL80211_CMD_FRAME:
 	case NL80211_CMD_FRAME_TX_STATUS:
@@ -2699,6 +2929,10 @@
 		case NL80211_IFTYPE_ADHOC:
 			info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
 			break;
+		case NL80211_IFTYPE_P2P_DEVICE:
+			info->capa->flags |=
+				WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+			break;
 		case NL80211_IFTYPE_P2P_GO:
 			info->p2p_go_supported = 1;
 			break;
@@ -2896,6 +3130,10 @@
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
+	if (tb[NL80211_ATTR_WIPHY_NAME])
+		os_strncpy(drv->phyname,
+			   nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
+			   sizeof(drv->phyname));
 	if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
 		capa->max_scan_ssids =
 			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
@@ -2992,7 +3230,8 @@
 		nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
 
 	NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
+	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+		goto nla_put_failure;
 
 	if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
 		return -1;
@@ -3265,39 +3504,6 @@
 }
 
 
-static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
-{
-	/* Find phy (radio) to which this interface belongs */
-	char buf[90], *pos;
-	int f, rv;
-
-	drv->phyname[0] = '\0';
-	snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
-		 drv->first_bss.ifname);
-	f = open(buf, O_RDONLY);
-	if (f < 0) {
-		wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
-			   buf, strerror(errno));
-		return;
-	}
-
-	rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
-	close(f);
-	if (rv < 0) {
-		wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
-			   buf, strerror(errno));
-		return;
-	}
-
-	drv->phyname[rv] = '\0';
-	pos = os_strchr(drv->phyname, '\n');
-	if (pos)
-		*pos = '\0';
-	wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
-		   drv->first_bss.ifname, drv->phyname);
-}
-
-
 static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
 						      void *eloop_ctx,
 						      void *handle)
@@ -3419,8 +3625,6 @@
 	if (nl80211_init_bss(bss))
 		goto failed;
 
-	nl80211_get_phy_name(drv);
-
 	rcfg = os_zalloc(sizeof(*rcfg));
 	if (rcfg == NULL)
 		goto failed;
@@ -3491,7 +3695,9 @@
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
+
 	NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
 	NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
 
@@ -3728,27 +3934,124 @@
 }
 
 
+static void nl80211_del_p2pdev(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
+	NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
+		   bss->ifname, (long long unsigned int) bss->wdev_id,
+		   strerror(ret));
+
+nla_put_failure:
+	nlmsg_free(msg);
+}
+
+
+static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret = -1;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	if (start)
+		nl80211_cmd(drv, msg, 0, NL80211_CMD_START_P2P_DEVICE);
+	else
+		nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_P2P_DEVICE);
+
+	NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+
+	wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
+		   start ? "Start" : "Stop",
+		   bss->ifname, (long long unsigned int) bss->wdev_id,
+		   strerror(ret));
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int i802_set_iface_flags(struct i802_bss *bss, int up)
+{
+	enum nl80211_iftype nlmode;
+
+	nlmode = nl80211_get_ifmode(bss);
+	if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+		return linux_set_iface_flags(bss->drv->global->ioctl_sock,
+					     bss->ifname, up);
+	}
+
+	/* P2P Device has start/stop which is equivalent */
+	return nl80211_set_p2pdev(bss, up);
+}
+
+
 static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
 {
+#ifndef HOSTAPD
+	enum nl80211_iftype nlmode = NL80211_IFTYPE_STATION;
+#endif /* HOSTAPD */
 	struct i802_bss *bss = &drv->first_bss;
 	int send_rfkill_event = 0;
+	int dynamic_if;
 
 	drv->ifindex = if_nametoindex(bss->ifname);
-	drv->first_bss.ifindex = drv->ifindex;
+	bss->ifindex = drv->ifindex;
+	bss->wdev_id = drv->global->if_add_wdevid;
+	bss->wdev_id_set = drv->global->if_add_wdevid_set;
+
+	dynamic_if = drv->ifindex == drv->global->if_add_ifindex;
+	dynamic_if = dynamic_if || drv->global->if_add_wdevid_set;
+	drv->global->if_add_wdevid_set = 0;
+
+	if (wpa_driver_nl80211_capa(drv))
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
+		   bss->ifname, drv->phyname);
 
 #ifndef HOSTAPD
+	if (dynamic_if)
+		nlmode = nl80211_get_ifmode(bss);
+
 	/*
 	 * 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");
+	if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to use managed mode");
 		return -1;
 	}
+	drv->nlmode = nlmode;
+
+	if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+		int ret = nl80211_set_p2pdev(bss, 1);
+		if (ret < 0)
+			wpa_printf(MSG_ERROR, "nl80211: Could not start P2P device");
+		nl80211_get_macaddr(bss);
+		return ret;
+	}
 
 	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
 		if (rfkill_is_blocked(drv->rfkill)) {
@@ -3768,9 +4071,6 @@
 			       1, IF_OPER_DORMANT);
 #endif /* HOSTAPD */
 
-	if (wpa_driver_nl80211_capa(drv))
-		return -1;
-
 	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
 			       bss->addr))
 		return -1;
@@ -3867,10 +4167,13 @@
 
 	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-	(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");
-
+	(void) i802_set_iface_flags(bss, 0);
+	if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+		wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
+	} else {
+		nl80211_mgmt_unsubscribe(bss, "deinit");
+		nl80211_del_p2pdev(bss);
+	}
 	nl_cb_put(drv->nl_cb);
 
 	nl80211_destroy_bss(&drv->first_bss);
@@ -3911,7 +4214,7 @@
 
 static struct nl_msg *
 nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
-		    struct wpa_driver_scan_params *params)
+		    struct wpa_driver_scan_params *params, u64 *wdev_id)
 {
 	struct nl_msg *msg;
 	size_t i;
@@ -3922,8 +4225,10 @@
 
 	nl80211_cmd(drv, msg, 0, cmd);
 
-	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0)
-		goto fail;
+	if (!wdev_id)
+		NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	else
+		NLA_PUT_U64(msg, NL80211_ATTR_WDEV, *wdev_id);
 
 	if (params->num_ssids) {
 		struct nlattr *ssids;
@@ -3972,6 +4277,7 @@
 	return msg;
 
 fail:
+nla_put_failure:
 	nlmsg_free(msg);
 	return NULL;
 }
@@ -3993,7 +4299,8 @@
 	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
 	drv->scan_for_auth = 0;
 
-	msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params);
+	msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,
+				  bss->wdev_id_set ? &bss->wdev_id : NULL);
 	if (!msg)
 		return -1;
 
@@ -4096,7 +4403,8 @@
 		return android_pno_start(bss, params);
 #endif /* ANDROID */
 
-	msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params);
+	msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params,
+				  bss->wdev_id_set ? &bss->wdev_id : NULL);
 	if (!msg)
 		goto nla_put_failure;
 
@@ -4499,7 +4807,8 @@
 		goto nla_put_failure;
 
 	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+		goto nla_put_failure;
 
 	arg.drv = drv;
 	arg.res = res;
@@ -4570,13 +4879,18 @@
 				      const u8 *key, size_t key_len)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ifindex = if_nametoindex(ifname);
+	int ifindex;
 	struct nl_msg *msg;
 	int ret;
 
-	wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
+	/* Ignore for P2P Device */
+	if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+		return 0;
+
+	ifindex = if_nametoindex(ifname);
+	wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
 		   "set_tx=%d seq_len=%lu key_len=%lu",
-		   __func__, ifindex, alg, addr, key_idx, set_tx,
+		   __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
 		   (unsigned long) seq_len, (unsigned long) key_len);
 #ifdef CONFIG_TDLS
 	if (key_idx == -1)
@@ -5785,7 +6099,8 @@
 	mgmt = (struct ieee80211_mgmt *) data;
 	fc = le_to_host16(mgmt->frame_control);
 
-	if (is_sta_interface(drv->nlmode) &&
+	if ((is_sta_interface(drv->nlmode) ||
+	     drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
 	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
 	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
 		/*
@@ -6406,6 +6721,8 @@
 		return "P2P_CLIENT";
 	case NL80211_IFTYPE_P2P_GO:
 		return "P2P_GO";
+	case NL80211_IFTYPE_P2P_DEVICE:
+		return "P2P_DEVICE";
 	default:
 		return "unknown";
 	}
@@ -6415,7 +6732,9 @@
 static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
 				     const char *ifname,
 				     enum nl80211_iftype iftype,
-				     const u8 *addr, int wds)
+				     const u8 *addr, int wds,
+				     int (*handler)(struct nl_msg *, void *),
+				     void *arg)
 {
 	struct nl_msg *msg;
 	int ifidx;
@@ -6429,7 +6748,8 @@
 		return -1;
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+		goto nla_put_failure;
 	NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
 
@@ -6447,7 +6767,7 @@
 		NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = send_and_recv_msgs(drv, msg, handler, arg);
 	msg = NULL;
 	if (ret) {
  nla_put_failure:
@@ -6457,6 +6777,9 @@
 		return ret;
 	}
 
+	if (iftype == NL80211_IFTYPE_P2P_DEVICE)
+		return 0;
+
 	ifidx = if_nametoindex(ifname);
 	wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
 		   ifname, ifidx);
@@ -6479,11 +6802,14 @@
 
 static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
 				const char *ifname, enum nl80211_iftype iftype,
-				const u8 *addr, int wds)
+				const u8 *addr, int wds,
+				int (*handler)(struct nl_msg *, void *),
+				void *arg)
 {
 	int ret;
 
-	ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
+	ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
+					arg);
 
 	/* if error occurred and interface exists already */
 	if (ret == -ENFILE && if_nametoindex(ifname)) {
@@ -6494,10 +6820,10 @@
 
 		/* Try to create the interface again */
 		ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
-						wds);
+						wds, handler, arg);
 	}
 
-	if (ret >= 0 && is_p2p_interface(iftype))
+	if (ret >= 0 && is_p2p_net_interface(iftype))
 		nl80211_disable_11b_rates(drv, ret, 1);
 
 	return ret;
@@ -6844,7 +7170,7 @@
 
 	drv->monitor_ifidx =
 		nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
-				     0);
+				     0, NULL, NULL);
 
 	if (drv->monitor_ifidx == -EOPNOTSUPP) {
 		/*
@@ -7707,7 +8033,8 @@
 		return -ENOMEM;
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+		goto nla_put_failure;
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -7732,6 +8059,9 @@
 	int res;
 
 	res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+	if (res && nlmode == nl80211_get_ifmode(bss))
+		res = 0;
+
 	if (res == 0) {
 		drv->nlmode = nlmode;
 		ret = 0;
@@ -7755,8 +8085,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
 		   "interface down");
 	for (i = 0; i < 10; i++) {
-		res = linux_set_iface_flags(drv->global->ioctl_sock,
-					    bss->ifname, 0);
+		res = i802_set_iface_flags(bss, 0);
 		if (res == -EACCES || res == -ENODEV)
 			break;
 		if (res == 0) {
@@ -7765,8 +8094,7 @@
 			ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
 			if (ret == -EACCES)
 				break;
-			res = linux_set_iface_flags(drv->global->ioctl_sock,
-						    bss->ifname, 1);
+			res = i802_set_iface_flags(bss, 1);
 			if (res && !ret)
 				ret = -1;
 			else if (ret != -EBUSY)
@@ -7791,7 +8119,7 @@
 		return ret;
 	}
 
-	if (is_p2p_interface(nlmode))
+	if (is_p2p_net_interface(nlmode))
 		nl80211_disable_11b_rates(drv, drv->ifindex, 1);
 	else if (drv->disabled_11b_rates)
 		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
@@ -7830,6 +8158,13 @@
 		capa->extended_capa_mask = drv->extended_capa_mask;
 		capa->extended_capa_len = drv->extended_capa_len;
 	}
+
+	if ((capa->flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+	    !drv->allow_p2p_device) {
+		wpa_printf(MSG_DEBUG, "nl80211: Do not indicate P2P_DEVICE support (p2p_device=1 driver param not specified)");
+		capa->flags &= ~WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+	}
+
 	return 0;
 }
 
@@ -8368,7 +8703,7 @@
 		if (!if_nametoindex(name)) {
 			if (nl80211_create_iface(drv, name,
 						 NL80211_IFTYPE_AP_VLAN,
-						 bss->addr, 1) < 0)
+						 bss->addr, 1, NULL, NULL) < 0)
 				return -1;
 			if (bridge_ifname &&
 			    linux_br_add_if(drv->global->ioctl_sock,
@@ -8584,6 +8919,8 @@
 		return NL80211_IFTYPE_AP;
 	case WPA_IF_P2P_GO:
 		return NL80211_IFTYPE_P2P_GO;
+	case WPA_IF_P2P_DEVICE:
+		return NL80211_IFTYPE_P2P_DEVICE;
 	}
 	return -1;
 }
@@ -8630,12 +8967,40 @@
 #endif /* CONFIG_P2P */
 
 
+struct wdev_info {
+	u64 wdev_id;
+	int wdev_id_set;
+	u8 macaddr[ETH_ALEN];
+};
+
+static int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
+{
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct wdev_info *wi = arg;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+	if (tb[NL80211_ATTR_WDEV]) {
+		wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+		wi->wdev_id_set = 1;
+	}
+
+	if (tb[NL80211_ATTR_MAC])
+		os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+			  ETH_ALEN);
+
+	return NL_SKIP;
+}
+
+
 static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
 				     const char *ifname, const u8 *addr,
 				     void *bss_ctx, void **drv_priv,
 				     char *force_ifname, u8 *if_addr,
 				     const char *bridge)
 {
+	enum nl80211_iftype nlmode;
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ifidx;
@@ -8651,21 +9016,46 @@
 
 	if (addr)
 		os_memcpy(if_addr, addr, ETH_ALEN);
-	ifidx = nl80211_create_iface(drv, ifname,
-				     wpa_driver_nl80211_if_type(type), addr,
-				     0);
-	if (ifidx < 0) {
+	nlmode = wpa_driver_nl80211_if_type(type);
+	if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+		struct wdev_info p2pdev_info;
+
+		os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
+		ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
+					     0, nl80211_wdev_handler,
+					     &p2pdev_info);
+		if (!p2pdev_info.wdev_id_set || ifidx != 0) {
+			wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
+				   ifname);
+			return -1;
+		}
+
+		drv->global->if_add_wdevid = p2pdev_info.wdev_id;
+		drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
+		if (!is_zero_ether_addr(p2pdev_info.macaddr))
+			os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
+		wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
+			   ifname,
+			   (long long unsigned int) p2pdev_info.wdev_id);
+	} else {
+		ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
+					     0, NULL, NULL);
+		if (ifidx < 0) {
 #ifdef HOSTAPD
-		os_free(new_bss);
+			os_free(new_bss);
 #endif /* HOSTAPD */
-		return -1;
+			return -1;
+		}
 	}
 
-	if (!addr &&
-	    linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-			       if_addr) < 0) {
-		nl80211_remove_iface(drv, ifidx);
-		return -1;
+	if (!addr) {
+		if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+			os_memcpy(if_addr, bss->addr, ETH_ALEN);
+		else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
+					    bss->ifname, if_addr) < 0) {
+			nl80211_remove_iface(drv, ifidx);
+			return -1;
+		}
 	}
 
 #ifdef CONFIG_P2P
@@ -8673,16 +9063,14 @@
 	    (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
 	     type == WPA_IF_P2P_GO)) {
 		/* Enforce unique P2P Interface Address */
-		u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
+		u8 new_addr[ETH_ALEN];
 
-		if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-				       own_addr) < 0 ||
-		    linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
+		if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
 				       new_addr) < 0) {
 			nl80211_remove_iface(drv, ifidx);
 			return -1;
 		}
-		if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) {
+		if (nl80211_addr_in_use(drv->global, new_addr)) {
 			wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
 				   "for P2P group interface");
 			if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
@@ -8830,7 +9218,9 @@
 		   freq, wait, no_cck, no_ack, offchanok);
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
+
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
 	if (wait)
 		NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
@@ -8923,7 +9313,8 @@
 		   (long long unsigned int) drv->send_action_cookie);
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
 	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -8952,7 +9343,9 @@
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
+
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
 	NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
 
@@ -8999,7 +9392,9 @@
 
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (nl80211_set_iface_id(msg, bss) < 0)
+		goto nla_put_failure;
+
 	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -9154,11 +9549,9 @@
 static void wpa_driver_nl80211_resume(void *priv)
 {
 	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	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");
-	}
+
+	if (i802_set_iface_flags(bss, 1))
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
 }
 
 
@@ -9245,6 +9638,75 @@
 }
 
 
+/* Converts nl80211_chan_width to a common format */
+static enum chan_width convert2width(int width)
+{
+	switch (width) {
+	case NL80211_CHAN_WIDTH_20_NOHT:
+		return CHAN_WIDTH_20_NOHT;
+	case NL80211_CHAN_WIDTH_20:
+		return CHAN_WIDTH_20;
+	case NL80211_CHAN_WIDTH_40:
+		return CHAN_WIDTH_40;
+	case NL80211_CHAN_WIDTH_80:
+		return CHAN_WIDTH_80;
+	case NL80211_CHAN_WIDTH_80P80:
+		return CHAN_WIDTH_80P80;
+	case NL80211_CHAN_WIDTH_160:
+		return CHAN_WIDTH_160;
+	}
+	return CHAN_WIDTH_UNKNOWN;
+}
+
+
+static int get_channel_width(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct wpa_signal_info *sig_change = arg;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	sig_change->center_frq1 = -1;
+	sig_change->center_frq2 = -1;
+	sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+	if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
+		sig_change->chanwidth = convert2width(
+			nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+		if (tb[NL80211_ATTR_CENTER_FREQ1])
+			sig_change->center_frq1 =
+				nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+		if (tb[NL80211_ATTR_CENTER_FREQ2])
+			sig_change->center_frq2 =
+				nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+	}
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
+				     struct wpa_signal_info *sig)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	return send_and_recv_msgs(drv, msg, get_channel_width, sig);
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
 static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
 {
 	struct i802_bss *bss = priv;
@@ -9256,6 +9718,10 @@
 	if (res != 0)
 		return res;
 
+	res = nl80211_get_channel_width(drv, si);
+	if (res != 0)
+		return res;
+
 	return nl80211_get_link_noise(drv, si);
 }
 
@@ -9330,6 +9796,13 @@
 		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
 		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
 	}
+
+	if (os_strstr(param, "p2p_device=1")) {
+		struct i802_bss *bss = priv;
+		struct wpa_driver_nl80211_data *drv = bss->drv;
+		drv->allow_p2p_device = 1;
+	}
+
 #ifdef ANDROID_P2P
 	if(os_strstr(param, "use_multi_chan_concurrent=1")) {
 		struct i802_bss *bss = priv;
@@ -10013,6 +10486,18 @@
 }
 
 
+const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
+		return NULL;
+
+	return bss->addr;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -10092,6 +10577,7 @@
 	.tdls_oper = nl80211_tdls_oper,
 #endif /* CONFIG_TDLS */
 	.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
+	.get_mac_addr = wpa_driver_nl80211_get_macaddr,
 #ifdef ANDROID_P2P
 	.set_noa = wpa_driver_set_p2p_noa,
 	.get_noa = wpa_driver_get_p2p_noa,
diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h
index 0d247c4..f5890be 100644
--- a/src/eap_common/eap_defs.h
+++ b/src/eap_common/eap_defs.h
@@ -63,6 +63,7 @@
 	EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */,
 	EAP_TYPE_GPSK = 51 /* RFC 5433 */,
 	EAP_TYPE_PWD = 52 /* RFC 5931 */,
+	EAP_TYPE_EKE = 53 /* RFC 6124 */,
 	EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
 } EapType;
 
diff --git a/src/eap_common/eap_eke_common.c b/src/eap_common/eap_eke_common.c
new file mode 100644
index 0000000..a62ac8e
--- /dev/null
+++ b/src/eap_common/eap_eke_common.c
@@ -0,0 +1,768 @@
+/*
+ * EAP server/peer: EAP-EKE shared routines
+ * Copyright (c) 2011-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/aes.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "crypto/dh_groups.h"
+#include "crypto/random.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "eap_common/eap_defs.h"
+#include "eap_eke_common.h"
+
+
+static int eap_eke_dh_len(u8 group)
+{
+	switch (group) {
+	case EAP_EKE_DHGROUP_EKE_2:
+		return 128;
+	case EAP_EKE_DHGROUP_EKE_5:
+		return 192;
+	case EAP_EKE_DHGROUP_EKE_14:
+		return 256;
+	case EAP_EKE_DHGROUP_EKE_15:
+		return 384;
+	case EAP_EKE_DHGROUP_EKE_16:
+		return 512;
+	}
+
+	return -1;
+}
+
+
+static int eap_eke_dhcomp_len(u8 dhgroup, u8 encr)
+{
+	int dhlen;
+
+	dhlen = eap_eke_dh_len(dhgroup);
+	if (dhlen < 0)
+		return -1;
+	if (encr != EAP_EKE_ENCR_AES128_CBC)
+		return -1;
+	return AES_BLOCK_SIZE + dhlen;
+}
+
+
+static const struct dh_group * eap_eke_dh_group(u8 group)
+{
+	switch (group) {
+	case EAP_EKE_DHGROUP_EKE_2:
+		return dh_groups_get(2);
+	case EAP_EKE_DHGROUP_EKE_5:
+		return dh_groups_get(5);
+	case EAP_EKE_DHGROUP_EKE_14:
+		return dh_groups_get(14);
+	case EAP_EKE_DHGROUP_EKE_15:
+		return dh_groups_get(15);
+	case EAP_EKE_DHGROUP_EKE_16:
+		return dh_groups_get(16);
+	}
+
+	return NULL;
+}
+
+
+static int eap_eke_dh_generator(u8 group)
+{
+	switch (group) {
+	case EAP_EKE_DHGROUP_EKE_2:
+		return 5;
+	case EAP_EKE_DHGROUP_EKE_5:
+		return 31;
+	case EAP_EKE_DHGROUP_EKE_14:
+		return 11;
+	case EAP_EKE_DHGROUP_EKE_15:
+		return 5;
+	case EAP_EKE_DHGROUP_EKE_16:
+		return 5;
+	}
+
+	return -1;
+}
+
+
+static int eap_eke_pnonce_len(u8 mac)
+{
+	int mac_len;
+
+	if (mac == EAP_EKE_MAC_HMAC_SHA1)
+		mac_len = SHA1_MAC_LEN;
+	else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
+		mac_len = SHA256_MAC_LEN;
+	else
+		return -1;
+
+	return AES_BLOCK_SIZE + 16 + mac_len;
+}
+
+
+static int eap_eke_pnonce_ps_len(u8 mac)
+{
+	int mac_len;
+
+	if (mac == EAP_EKE_MAC_HMAC_SHA1)
+		mac_len = SHA1_MAC_LEN;
+	else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
+		mac_len = SHA256_MAC_LEN;
+	else
+		return -1;
+
+	return AES_BLOCK_SIZE + 2 * 16 + mac_len;
+}
+
+
+static int eap_eke_prf_len(u8 prf)
+{
+	if (prf == EAP_EKE_PRF_HMAC_SHA1)
+		return 20;
+	if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
+		return 32;
+	return -1;
+}
+
+
+static int eap_eke_nonce_len(u8 prf)
+{
+	int prf_len;
+
+	prf_len = eap_eke_prf_len(prf);
+	if (prf_len < 0)
+		return -1;
+
+	if (prf_len > 2 * 16)
+		return (prf_len + 1) / 2;
+
+	return 16;
+}
+
+
+static int eap_eke_auth_len(u8 prf)
+{
+	switch (prf) {
+	case EAP_EKE_PRF_HMAC_SHA1:
+		return SHA1_MAC_LEN;
+	case EAP_EKE_PRF_HMAC_SHA2_256:
+		return SHA256_MAC_LEN;
+	}
+
+	return -1;
+}
+
+
+int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub)
+{
+	int generator;
+	u8 gen;
+	const struct dh_group *dh;
+	size_t pub_len, i;
+
+	generator = eap_eke_dh_generator(group);
+	if (generator < 0 || generator > 255)
+		return -1;
+	gen = generator;
+
+	dh = eap_eke_dh_group(group);
+	if (dh == NULL)
+		return -1;
+
+	/* x = random number 2 .. p-1 */
+	if (random_get_bytes(ret_priv, dh->prime_len))
+		return -1;
+	if (os_memcmp(ret_priv, dh->prime, dh->prime_len) > 0) {
+		/* Make sure private value is smaller than prime */
+		ret_priv[0] = 0;
+	}
+	for (i = 0; i < dh->prime_len - 1; i++) {
+		if (ret_priv[i])
+			break;
+	}
+	if (i == dh->prime_len - 1 && (ret_priv[i] == 0 || ret_priv[i] == 1))
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: DH private value",
+			ret_priv, dh->prime_len);
+
+	/* y = g ^ x (mod p) */
+	pub_len = dh->prime_len;
+	if (crypto_mod_exp(&gen, 1, ret_priv, dh->prime_len,
+			   dh->prime, dh->prime_len, ret_pub, &pub_len) < 0)
+		return -1;
+	if (pub_len < dh->prime_len) {
+		size_t pad = dh->prime_len - pub_len;
+		os_memmove(ret_pub + pad, ret_pub, pub_len);
+		os_memset(ret_pub, 0, pad);
+	}
+
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DH public value",
+		    ret_pub, dh->prime_len);
+
+	return 0;
+}
+
+
+static int eap_eke_prf(u8 prf, const u8 *key, size_t key_len, const u8 *data,
+		       size_t data_len, const u8 *data2, size_t data2_len,
+		       u8 *res)
+{
+	const u8 *addr[2];
+	size_t len[2];
+	size_t num_elem = 1;
+
+	addr[0] = data;
+	len[0] = data_len;
+	if (data2) {
+		num_elem++;
+		addr[1] = data2;
+		len[1] = data2_len;
+	}
+
+	if (prf == EAP_EKE_PRF_HMAC_SHA1)
+		return hmac_sha1_vector(key, key_len, num_elem, addr, len, res);
+	if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
+		return hmac_sha256_vector(key, key_len, num_elem, addr, len,
+					  res);
+	return -1;
+}
+
+
+static int eap_eke_prf_hmac_sha1(const u8 *key, size_t key_len, const u8 *data,
+				 size_t data_len, u8 *res, size_t len)
+{
+	u8 hash[SHA1_MAC_LEN];
+	u8 idx;
+	const u8 *addr[3];
+	size_t vlen[3];
+	int ret;
+
+	idx = 0;
+	addr[0] = hash;
+	vlen[0] = SHA1_MAC_LEN;
+	addr[1] = data;
+	vlen[1] = data_len;
+	addr[2] = &idx;
+	vlen[2] = 1;
+
+	while (len > 0) {
+		idx++;
+		if (idx == 1)
+			ret = hmac_sha1_vector(key, key_len, 2, &addr[1],
+					       &vlen[1], hash);
+		else
+			ret = hmac_sha1_vector(key, key_len, 3, addr, vlen,
+					       hash);
+		if (ret < 0)
+			return -1;
+		if (len > SHA1_MAC_LEN) {
+			os_memcpy(res, hash, SHA1_MAC_LEN);
+			res += SHA1_MAC_LEN;
+			len -= SHA1_MAC_LEN;
+		} else {
+			os_memcpy(res, hash, len);
+			len = 0;
+		}
+	}
+
+	return 0;
+}
+
+
+static int eap_eke_prf_hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+				   size_t data_len, u8 *res, size_t len)
+{
+	u8 hash[SHA256_MAC_LEN];
+	u8 idx;
+	const u8 *addr[3];
+	size_t vlen[3];
+	int ret;
+
+	idx = 0;
+	addr[0] = hash;
+	vlen[0] = SHA256_MAC_LEN;
+	addr[1] = data;
+	vlen[1] = data_len;
+	addr[2] = &idx;
+	vlen[2] = 1;
+
+	while (len > 0) {
+		idx++;
+		if (idx == 1)
+			ret = hmac_sha256_vector(key, key_len, 2, &addr[1],
+						 &vlen[1], hash);
+		else
+			ret = hmac_sha256_vector(key, key_len, 3, addr, vlen,
+						 hash);
+		if (ret < 0)
+			return -1;
+		if (len > SHA256_MAC_LEN) {
+			os_memcpy(res, hash, SHA256_MAC_LEN);
+			res += SHA256_MAC_LEN;
+			len -= SHA256_MAC_LEN;
+		} else {
+			os_memcpy(res, hash, len);
+			len = 0;
+		}
+	}
+
+	return 0;
+}
+
+
+static int eap_eke_prfplus(u8 prf, const u8 *key, size_t key_len,
+			   const u8 *data, size_t data_len, u8 *res, size_t len)
+{
+	if (prf == EAP_EKE_PRF_HMAC_SHA1)
+		return eap_eke_prf_hmac_sha1(key, key_len, data, data_len, res,
+					     len);
+	if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
+		return eap_eke_prf_hmac_sha256(key, key_len, data, data_len,
+					       res, len);
+	return -1;
+}
+
+
+int eap_eke_derive_key(struct eap_eke_session *sess,
+		       const u8 *password, size_t password_len,
+		       const u8 *id_s, size_t id_s_len, const u8 *id_p,
+		       size_t id_p_len, u8 *key)
+{
+	u8 zeros[EAP_EKE_MAX_HASH_LEN];
+	u8 temp[EAP_EKE_MAX_HASH_LEN];
+	size_t key_len = 16; /* Only AES-128-CBC is used here */
+	u8 *id;
+
+	/* temp = prf(0+, password) */
+	os_memset(zeros, 0, sess->prf_len);
+	if (eap_eke_prf(sess->prf, zeros, sess->prf_len,
+			password, password_len, NULL, 0, temp) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: temp = prf(0+, password)",
+			temp, sess->prf_len);
+
+	/* key = prf+(temp, ID_S | ID_P) */
+	id = os_malloc(id_s_len + id_p_len);
+	if (id == NULL)
+		return -1;
+	os_memcpy(id, id_s, id_s_len);
+	os_memcpy(id + id_s_len, id_p, id_p_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: ID_S | ID_P",
+			  id, id_s_len + id_p_len);
+	if (eap_eke_prfplus(sess->prf, temp, sess->prf_len,
+			    id, id_s_len + id_p_len, key, key_len) < 0) {
+		os_free(id);
+		return -1;
+	}
+	os_free(id);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: key = prf+(temp, ID_S | ID_P)",
+			key, key_len);
+
+	return 0;
+}
+
+
+int eap_eke_dhcomp(struct eap_eke_session *sess, const u8 *key, const u8 *dhpub,
+		   u8 *ret_dhcomp)
+{
+	u8 pub[EAP_EKE_MAX_DH_LEN];
+	int dh_len;
+	u8 iv[AES_BLOCK_SIZE];
+
+	dh_len = eap_eke_dh_len(sess->dhgroup);
+	if (dh_len < 0)
+		return -1;
+
+	/*
+	 * DHComponent = Encr(key, y)
+	 *
+	 * All defined DH groups use primes that have length devisible by 16, so
+	 * no need to do extra padding for y (= pub).
+	 */
+	if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
+		return -1;
+	if (random_get_bytes(iv, AES_BLOCK_SIZE))
+		return -1;
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Encr(key, y)",
+		    iv, AES_BLOCK_SIZE);
+	os_memcpy(pub, dhpub, dh_len);
+	if (aes_128_cbc_encrypt(key, iv, pub, dh_len) < 0)
+		return -1;
+	os_memcpy(ret_dhcomp, iv, AES_BLOCK_SIZE);
+	os_memcpy(ret_dhcomp + AES_BLOCK_SIZE, pub, dh_len);
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent = Encr(key, y)",
+		    ret_dhcomp, AES_BLOCK_SIZE + dh_len);
+
+	return 0;
+}
+
+
+int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
+			  const u8 *dhpriv, const u8 *peer_dhcomp)
+{
+	u8 zeros[EAP_EKE_MAX_HASH_LEN];
+	u8 peer_pub[EAP_EKE_MAX_DH_LEN];
+	u8 modexp[EAP_EKE_MAX_DH_LEN];
+	size_t len;
+	const struct dh_group *dh;
+
+	if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
+		return -1;
+
+	dh = eap_eke_dh_group(sess->dhgroup);
+	if (dh == NULL)
+		return -1;
+
+	/* Decrypt peer DHComponent */
+	os_memcpy(peer_pub, peer_dhcomp + AES_BLOCK_SIZE, dh->prime_len);
+	if (aes_128_cbc_decrypt(key, peer_dhcomp, peer_pub, dh->prime_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt DHComponent");
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted peer DH pubkey",
+			peer_pub, dh->prime_len);
+
+	/* SharedSecret = prf(0+, g ^ (x_s * x_p) (mod p)) */
+	len = dh->prime_len;
+	if (crypto_mod_exp(peer_pub, dh->prime_len, dhpriv, dh->prime_len,
+			   dh->prime, dh->prime_len, modexp, &len) < 0)
+		return -1;
+	if (len < dh->prime_len) {
+		size_t pad = dh->prime_len - len;
+		os_memmove(modexp + pad, modexp, len);
+		os_memset(modexp, 0, pad);
+	}
+
+	os_memset(zeros, 0, sess->auth_len);
+	if (eap_eke_prf(sess->prf, zeros, sess->auth_len, modexp, dh->prime_len,
+			NULL, 0, sess->shared_secret) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: SharedSecret",
+			sess->shared_secret, sess->auth_len);
+
+	return 0;
+}
+
+
+int eap_eke_derive_ke_ki(struct eap_eke_session *sess,
+			 const u8 *id_s, size_t id_s_len,
+			 const u8 *id_p, size_t id_p_len)
+{
+	u8 buf[EAP_EKE_MAX_KE_LEN + EAP_EKE_MAX_KI_LEN];
+	size_t ke_len, ki_len;
+	u8 *data;
+	size_t data_len;
+	const char *label = "EAP-EKE Keys";
+	size_t label_len;
+
+	/*
+	 * Ke | Ki = prf+(SharedSecret, "EAP-EKE Keys" | ID_S | ID_P)
+	 * Ke = encryption key
+	 * Ki = integrity protection key
+	 * Length of each key depends on the selected algorithms.
+	 */
+
+	if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
+		ke_len = 16;
+	else
+		return -1;
+
+	if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
+		ki_len = 20;
+	else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
+		ki_len = 32;
+	else
+		return -1;
+
+	label_len = os_strlen(label);
+	data_len = label_len + id_s_len + id_p_len;
+	data = os_malloc(data_len);
+	if (data == NULL)
+		return -1;
+	os_memcpy(data, label, label_len);
+	os_memcpy(data + label_len, id_s, id_s_len);
+	os_memcpy(data + label_len + id_s_len, id_p, id_p_len);
+	if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
+			    data, data_len, buf, ke_len + ki_len) < 0) {
+		os_free(data);
+		return -1;
+	}
+
+	os_memcpy(sess->ke, buf, ke_len);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ke", sess->ke, ke_len);
+	os_memcpy(sess->ki, buf + ke_len, ki_len);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ki", sess->ki, ki_len);
+
+	os_free(data);
+	return 0;
+}
+
+
+int eap_eke_derive_ka(struct eap_eke_session *sess,
+		      const u8 *id_s, size_t id_s_len,
+		      const u8 *id_p, size_t id_p_len,
+		      const u8 *nonce_p, const u8 *nonce_s)
+{
+	u8 *data, *pos;
+	size_t data_len;
+	const char *label = "EAP-EKE Ka";
+	size_t label_len;
+
+	/*
+	 * Ka = prf+(SharedSecret, "EAP-EKE Ka" | ID_S | ID_P | Nonce_P |
+	 *	     Nonce_S)
+	 * Ka = authentication key
+	 * Length of the key depends on the selected algorithms.
+	 */
+
+	label_len = os_strlen(label);
+	data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
+	data = os_malloc(data_len);
+	if (data == NULL)
+		return -1;
+	pos = data;
+	os_memcpy(pos, label, label_len);
+	pos += label_len;
+	os_memcpy(pos, id_s, id_s_len);
+	pos += id_s_len;
+	os_memcpy(pos, id_p, id_p_len);
+	pos += id_p_len;
+	os_memcpy(pos, nonce_p, sess->nonce_len);
+	pos += sess->nonce_len;
+	os_memcpy(pos, nonce_s, sess->nonce_len);
+	if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
+			    data, data_len, sess->ka, sess->prf_len) < 0) {
+		os_free(data);
+		return -1;
+	}
+	os_free(data);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka", sess->ka, sess->prf_len);
+
+	return 0;
+}
+
+
+int eap_eke_derive_msk(struct eap_eke_session *sess,
+		       const u8 *id_s, size_t id_s_len,
+		       const u8 *id_p, size_t id_p_len,
+		       const u8 *nonce_p, const u8 *nonce_s,
+		       u8 *msk, u8 *emsk)
+{
+	u8 *data, *pos;
+	size_t data_len;
+	const char *label = "EAP-EKE Exported Keys";
+	size_t label_len;
+	u8 buf[EAP_MSK_LEN + EAP_EMSK_LEN];
+
+	/*
+	 * MSK | EMSK = prf+(SharedSecret, "EAP-EKE Exported Keys" | ID_S |
+	 *		     ID_P | Nonce_P | Nonce_S)
+	 */
+
+	label_len = os_strlen(label);
+	data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
+	data = os_malloc(data_len);
+	if (data == NULL)
+		return -1;
+	pos = data;
+	os_memcpy(pos, label, label_len);
+	pos += label_len;
+	os_memcpy(pos, id_s, id_s_len);
+	pos += id_s_len;
+	os_memcpy(pos, id_p, id_p_len);
+	pos += id_p_len;
+	os_memcpy(pos, nonce_p, sess->nonce_len);
+	pos += sess->nonce_len;
+	os_memcpy(pos, nonce_s, sess->nonce_len);
+	if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
+			    data, data_len, buf, EAP_MSK_LEN + EAP_EMSK_LEN) <
+	    0) {
+		os_free(data);
+		return -1;
+	}
+	os_free(data);
+
+	os_memcpy(msk, buf, EAP_MSK_LEN);
+	os_memcpy(emsk, buf + EAP_MSK_LEN, EAP_EMSK_LEN);
+	os_memset(buf, 0, sizeof(buf));
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: MSK", msk, EAP_MSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: EMSK", msk, EAP_EMSK_LEN);
+
+	return 0;
+}
+
+
+static int eap_eke_mac(u8 mac, const u8 *key, const u8 *data, size_t data_len,
+		       u8 *res)
+{
+	if (mac == EAP_EKE_MAC_HMAC_SHA1)
+		return hmac_sha1(key, SHA1_MAC_LEN, data, data_len, res);
+	if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
+		return hmac_sha256(key, SHA256_MAC_LEN, data, data_len, res);
+	return -1;
+}
+
+
+int eap_eke_prot(struct eap_eke_session *sess,
+		 const u8 *data, size_t data_len,
+		 u8 *prot, size_t *prot_len)
+{
+	size_t block_size, icv_len, pad;
+	u8 *pos, *iv, *e;
+
+	if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
+		block_size = AES_BLOCK_SIZE;
+	else
+		return -1;
+
+	if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
+		icv_len = SHA1_MAC_LEN;
+	else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
+		icv_len = SHA256_MAC_LEN;
+	else
+		return -1;
+
+	pad = data_len % block_size;
+	if (pad)
+		pad = block_size - pad;
+
+	if (*prot_len < block_size + data_len + pad + icv_len) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for Prot() data");
+	}
+	pos = prot;
+
+	if (random_get_bytes(pos, block_size))
+		return -1;
+	iv = pos;
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Prot()", iv, block_size);
+	pos += block_size;
+
+	e = pos;
+	os_memcpy(pos, data, data_len);
+	pos += data_len;
+	if (pad) {
+		if (random_get_bytes(pos, pad))
+			return -1;
+		pos += pad;
+	}
+
+	if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0)
+		return -1;
+
+	if (eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
+		return -1;
+	pos += icv_len;
+
+	*prot_len = pos - prot;
+	return 0;
+}
+
+
+int eap_eke_decrypt_prot(struct eap_eke_session *sess,
+			 const u8 *prot, size_t prot_len,
+			 u8 *data, size_t *data_len)
+{
+	size_t block_size, icv_len;
+	u8 icv[EAP_EKE_MAX_HASH_LEN];
+
+	if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
+		block_size = AES_BLOCK_SIZE;
+	else
+		return -1;
+
+	if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
+		icv_len = SHA1_MAC_LEN;
+	else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
+		icv_len = SHA256_MAC_LEN;
+	else
+		return -1;
+
+	if (prot_len < 2 * block_size + icv_len)
+		return -1;
+	if ((prot_len - icv_len) % block_size)
+		return -1;
+
+	if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
+			prot_len - block_size - icv_len, icv) < 0)
+		return -1;
+	if (os_memcmp(icv, prot + prot_len - icv_len, icv_len) != 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: ICV mismatch in Prot() data");
+		return -1;
+	}
+
+	if (*data_len < prot_len - block_size - icv_len) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for decrypted Prot() data");
+		return -1;
+	}
+
+	*data_len = prot_len - block_size - icv_len;
+	os_memcpy(data, prot + block_size, *data_len);
+	if (aes_128_cbc_decrypt(sess->ke, prot, data, *data_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt Prot() data");
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted Prot() data",
+			data, *data_len);
+
+	return 0;
+}
+
+
+int eap_eke_auth(struct eap_eke_session *sess, const char *label,
+		 const struct wpabuf *msgs, u8 *auth)
+{
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Auth(%s)", label);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka for Auth",
+			sess->ka, sess->auth_len);
+	wpa_hexdump_buf(MSG_MSGDUMP, "EAP-EKE: Messages for Auth", msgs);
+	return eap_eke_prf(sess->prf, sess->ka, sess->auth_len,
+			   (const u8 *) label, os_strlen(label),
+			   wpabuf_head(msgs), wpabuf_len(msgs), auth);
+}
+
+
+int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
+			 u8 prf, u8 mac)
+{
+	sess->dhgroup = dhgroup;
+	sess->encr = encr;
+	sess->prf = prf;
+	sess->mac = mac;
+
+	sess->prf_len = eap_eke_prf_len(prf);
+	if (sess->prf_len < 0)
+		return -1;
+	sess->nonce_len = eap_eke_nonce_len(prf);
+	if (sess->nonce_len < 0)
+		return -1;
+	sess->auth_len = eap_eke_auth_len(prf);
+	if (sess->auth_len < 0)
+		return -1;
+	sess->dhcomp_len = eap_eke_dhcomp_len(sess->dhgroup, sess->encr);
+	if (sess->dhcomp_len < 0)
+		return -1;
+	sess->pnonce_len = eap_eke_pnonce_len(sess->mac);
+	if (sess->pnonce_len < 0)
+		return -1;
+	sess->pnonce_ps_len = eap_eke_pnonce_ps_len(sess->mac);
+	if (sess->pnonce_ps_len < 0)
+		return -1;
+
+	return 0;
+}
+
+
+void eap_eke_session_clean(struct eap_eke_session *sess)
+{
+	os_memset(sess->shared_secret, 0, EAP_EKE_MAX_HASH_LEN);
+	os_memset(sess->ke, 0, EAP_EKE_MAX_KE_LEN);
+	os_memset(sess->ki, 0, EAP_EKE_MAX_KI_LEN);
+	os_memset(sess->ka, 0, EAP_EKE_MAX_KA_LEN);
+}
diff --git a/src/eap_common/eap_eke_common.h b/src/eap_common/eap_eke_common.h
new file mode 100644
index 0000000..a4c0422
--- /dev/null
+++ b/src/eap_common/eap_eke_common.h
@@ -0,0 +1,114 @@
+/*
+ * EAP server/peer: EAP-EKE shared routines
+ * Copyright (c) 2011-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_EKE_COMMON_H
+#define EAP_EKE_COMMON_H
+
+/* EKE Exchange */
+#define EAP_EKE_ID 1
+#define EAP_EKE_COMMIT 2
+#define EAP_EKE_CONFIRM 3
+#define EAP_EKE_FAILURE 4
+
+/* Diffie-Hellman Group Registry */
+#define EAP_EKE_DHGROUP_EKE_2 1
+#define EAP_EKE_DHGROUP_EKE_5 2
+#define EAP_EKE_DHGROUP_EKE_14 3 /* mandatory to implement */
+#define EAP_EKE_DHGROUP_EKE_15 4
+#define EAP_EKE_DHGROUP_EKE_16 5
+
+/* Encryption Algorithm Registry */
+#define EAP_EKE_ENCR_AES128_CBC 1 /* mandatory to implement */
+
+/* Pseudo Random Function Registry */
+#define EAP_EKE_PRF_HMAC_SHA1 1 /* mandatory to implement */
+#define EAP_EKE_PRF_HMAC_SHA2_256 2
+
+/* Keyed Message Digest (MAC) Registry */
+#define EAP_EKE_MAC_HMAC_SHA1 1 /* mandatory to implement */
+#define EAP_EKE_MAC_HMAC_SHA2_256 2
+
+/* Identity Type Registry */
+#define EAP_EKE_ID_OPAQUE 1
+#define EAP_EKE_ID_NAI 2
+#define EAP_EKE_ID_IPv4 3
+#define EAP_EKE_ID_IPv6 4
+#define EAP_EKE_ID_FQDN 5
+#define EAP_EKE_ID_DN 6
+
+/* Failure-Code */
+#define EAP_EKE_FAIL_NO_ERROR 1
+#define EAP_EKE_FAIL_PROTO_ERROR 2
+#define EAP_EKE_FAIL_PASSWD_NOT_FOUND 3
+#define EAP_EKE_FAIL_AUTHENTICATION_FAIL 4
+#define EAP_EKE_FAIL_AUTHORIZATION_FAIL 5
+#define EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN 6
+#define EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR 0xffffffff
+
+#define EAP_EKE_MAX_DH_LEN 512
+#define EAP_EKE_MAX_HASH_LEN 32
+#define EAP_EKE_MAX_KEY_LEN 16
+#define EAP_EKE_MAX_KE_LEN 16
+#define EAP_EKE_MAX_KI_LEN 32
+#define EAP_EKE_MAX_KA_LEN 32
+#define EAP_EKE_MAX_NONCE_LEN 16
+
+struct eap_eke_session {
+	/* Selected proposal */
+	u8 dhgroup;
+	u8 encr;
+	u8 prf;
+	u8 mac;
+
+	u8 shared_secret[EAP_EKE_MAX_HASH_LEN];
+	u8 ke[EAP_EKE_MAX_KE_LEN];
+	u8 ki[EAP_EKE_MAX_KI_LEN];
+	u8 ka[EAP_EKE_MAX_KA_LEN];
+
+	int prf_len;
+	int nonce_len;
+	int auth_len;
+	int dhcomp_len;
+	int pnonce_len;
+	int pnonce_ps_len;
+};
+
+int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
+			 u8 prf, u8 mac);
+void eap_eke_session_clean(struct eap_eke_session *sess);
+int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub);
+int eap_eke_derive_key(struct eap_eke_session *sess,
+		       const u8 *password, size_t password_len,
+		       const u8 *id_s, size_t id_s_len, const u8 *id_p,
+		       size_t id_p_len, u8 *key);
+int eap_eke_dhcomp(struct eap_eke_session *sess, const u8 *key, const u8 *dhpub,
+		   u8 *ret_dhcomp);
+int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
+			  const u8 *dhpriv, const u8 *peer_dhcomp);
+int eap_eke_derive_ke_ki(struct eap_eke_session *sess,
+			 const u8 *id_s, size_t id_s_len,
+			 const u8 *id_p, size_t id_p_len);
+int eap_eke_derive_ka(struct eap_eke_session *sess,
+		      const u8 *id_s, size_t id_s_len,
+		      const u8 *id_p, size_t id_p_len,
+		      const u8 *nonce_p, const u8 *nonce_s);
+int eap_eke_derive_msk(struct eap_eke_session *sess,
+		       const u8 *id_s, size_t id_s_len,
+		       const u8 *id_p, size_t id_p_len,
+		       const u8 *nonce_p, const u8 *nonce_s,
+		       u8 *msk, u8 *emsk);
+int eap_eke_prot(struct eap_eke_session *sess,
+		 const u8 *data, size_t data_len,
+		 u8 *prot, size_t *prot_len);
+int eap_eke_decrypt_prot(struct eap_eke_session *sess,
+			 const u8 *prot, size_t prot_len,
+			 u8 *data, size_t *data_len);
+int eap_eke_auth(struct eap_eke_session *sess, const char *label,
+		 const struct wpabuf *msgs, u8 *auth);
+
+#endif /* EAP_EKE_COMMON_H */
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index ed90919..42f525b 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -1,6 +1,6 @@
 /*
  * EAP peer configuration data
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -634,6 +634,15 @@
 	 *         password field is the name of that external entry
 	 */
 	u32 flags;
+
+	/**
+	 * ocsp - Whether to use/require OCSP to check server certificate
+	 *
+	 * 0 = do not use OCSP stapling (TLS certificate status extension)
+	 * 1 = try to use OCSP stapling, but not require response
+	 * 2 = require valid OCSP stapling response
+	 */
+	int ocsp;
 };
 
 
diff --git a/src/eap_peer/eap_eke.c b/src/eap_peer/eap_eke.c
new file mode 100644
index 0000000..c71db5f
--- /dev/null
+++ b/src/eap_peer/eap_eke.c
@@ -0,0 +1,723 @@
+/*
+ * EAP peer method: EAP-EKE (RFC 6124)
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/random.h"
+#include "eap_peer/eap_i.h"
+#include "eap_common/eap_eke_common.h"
+
+struct eap_eke_data {
+	enum {
+		IDENTITY, COMMIT, CONFIRM, SUCCESS, FAILURE
+	} state;
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 *peerid;
+	size_t peerid_len;
+	u8 *serverid;
+	size_t serverid_len;
+	u8 dh_priv[EAP_EKE_MAX_DH_LEN];
+	struct eap_eke_session sess;
+	u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
+	u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
+	struct wpabuf *msgs;
+};
+
+
+static const char * eap_eke_state_txt(int state)
+{
+	switch (state) {
+	case IDENTITY:
+		return "IDENTITY";
+	case COMMIT:
+		return "COMMIT";
+	case CONFIRM:
+		return "CONFIRM";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_eke_state(struct eap_eke_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
+		   eap_eke_state_txt(data->state), eap_eke_state_txt(state));
+	data->state = state;
+}
+
+
+static void eap_eke_deinit(struct eap_sm *sm, void *priv);
+
+
+static void * eap_eke_init(struct eap_sm *sm)
+{
+	struct eap_eke_data *data;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
+
+	password = eap_get_config_password(sm, &password_len);
+	if (!password) {
+		wpa_printf(MSG_INFO, "EAP-EKE: No password configured");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	eap_eke_state(data, IDENTITY);
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	if (identity) {
+		data->peerid = os_malloc(identity_len);
+		if (data->peerid == NULL) {
+			eap_eke_deinit(sm, data);
+			return NULL;
+		}
+		os_memcpy(data->peerid, identity, identity_len);
+		data->peerid_len = identity_len;
+	}
+
+	return data;
+}
+
+
+static void eap_eke_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_eke_data *data = priv;
+	eap_eke_session_clean(&data->sess);
+	os_free(data->serverid);
+	os_free(data->peerid);
+	wpabuf_free(data->msgs);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id,
+					 size_t length, u8 eke_exch)
+{
+	struct wpabuf *msg;
+	size_t plen;
+
+	plen = 1 + length;
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
+			    EAP_CODE_RESPONSE, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
+		return NULL;
+	}
+
+	wpabuf_put_u8(msg, eke_exch);
+
+	return msg;
+}
+
+
+static int eap_eke_supp_dhgroup(u8 dhgroup)
+{
+	return dhgroup == EAP_EKE_DHGROUP_EKE_2 ||
+		dhgroup == EAP_EKE_DHGROUP_EKE_5 ||
+		dhgroup == EAP_EKE_DHGROUP_EKE_14 ||
+		dhgroup == EAP_EKE_DHGROUP_EKE_15 ||
+		dhgroup == EAP_EKE_DHGROUP_EKE_16;
+}
+
+
+static int eap_eke_supp_encr(u8 encr)
+{
+	return encr == EAP_EKE_ENCR_AES128_CBC;
+}
+
+
+static int eap_eke_supp_prf(u8 prf)
+{
+	return prf == EAP_EKE_PRF_HMAC_SHA1 ||
+		prf == EAP_EKE_PRF_HMAC_SHA2_256;
+}
+
+
+static int eap_eke_supp_mac(u8 mac)
+{
+	return mac == EAP_EKE_MAC_HMAC_SHA1 ||
+		mac == EAP_EKE_MAC_HMAC_SHA2_256;
+}
+
+
+static struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data,
+					  struct eap_method_ret *ret,
+					  const struct wpabuf *reqData,
+					  u32 failure_code)
+{
+	struct wpabuf *resp;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x",
+		   failure_code);
+
+	resp = eap_eke_build_msg(data, eap_get_id(reqData), 4, EAP_EKE_FAILURE);
+	if (resp)
+		wpabuf_put_be32(resp, failure_code);
+
+	os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
+	eap_eke_session_clean(&data->sess);
+
+	eap_eke_state(data, FAILURE);
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = FALSE;
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data,
+					  struct eap_method_ret *ret,
+					  const struct wpabuf *reqData,
+					  const u8 *payload,
+					  size_t payload_len)
+{
+	struct wpabuf *resp;
+	unsigned num_prop, i;
+	const u8 *pos, *end;
+	const u8 *prop = NULL;
+	u8 idtype;
+
+	if (data->state != IDENTITY) {
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request");
+
+	if (payload_len < 2 + 4) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	pos = payload;
+	end = payload + payload_len;
+
+	num_prop = *pos++;
+	pos++; /* Ignore Reserved field */
+
+	if (pos + num_prop * 4 > end) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)",
+			   num_prop);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	for (i = 0; i < num_prop; i++) {
+		const u8 *tmp = pos;
+
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u",
+			   i, pos[0], pos[1], pos[2], pos[3]);
+		pos += 4;
+
+		if (!eap_eke_supp_dhgroup(*tmp))
+			continue;
+		tmp++;
+		if (!eap_eke_supp_encr(*tmp))
+			continue;
+		tmp++;
+		if (!eap_eke_supp_prf(*tmp))
+			continue;
+		tmp++;
+		if (!eap_eke_supp_mac(*tmp))
+			continue;
+
+		prop = tmp - 3;
+		if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2],
+					 prop[3]) < 0) {
+			prop = NULL;
+			continue;
+		}
+
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal");
+		break;
+	}
+
+	if (prop == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN);
+	}
+
+	pos += (num_prop - i - 1) * 4;
+
+	if (pos == end) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	idtype = *pos++;
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity",
+			  pos, end - pos);
+	os_free(data->serverid);
+	data->serverid = os_malloc(end - pos);
+	if (data->serverid == NULL) {
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	os_memcpy(data->serverid, pos, end - pos);
+	data->serverid_len = end - pos;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response");
+
+	resp = eap_eke_build_msg(data, eap_get_id(reqData),
+				 2 + 4 + 1 + data->peerid_len,
+				 EAP_EKE_ID);
+	if (resp == NULL) {
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	wpabuf_put_u8(resp, 1); /* NumProposals */
+	wpabuf_put_u8(resp, 0); /* Reserved */
+	wpabuf_put_data(resp, prop, 4); /* Selected Proposal */
+	wpabuf_put_u8(resp, EAP_EKE_ID_NAI);
+	if (data->peerid)
+		wpabuf_put_data(resp, data->peerid, data->peerid_len);
+
+	wpabuf_free(data->msgs);
+	data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp));
+	if (data->msgs == NULL) {
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpabuf_put_buf(data->msgs, reqData);
+	wpabuf_put_buf(data->msgs, resp);
+
+	eap_eke_state(data, COMMIT);
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
+					      struct eap_eke_data *data,
+					      struct eap_method_ret *ret,
+					      const struct wpabuf *reqData,
+					      const u8 *payload,
+					      size_t payload_len)
+{
+	struct wpabuf *resp;
+	const u8 *pos, *end, *dhcomp;
+	size_t prot_len;
+	u8 *rpos;
+	u8 key[EAP_EKE_MAX_KEY_LEN];
+	u8 pub[EAP_EKE_MAX_DH_LEN];
+	const u8 *password;
+	size_t password_len;
+
+	if (data->state != COMMIT) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request");
+
+	password = eap_get_config_password(sm, &password_len);
+	if (password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-EKE: No password configured!");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+	}
+
+	pos = payload;
+	end = payload + payload_len;
+
+	if (pos + data->sess.dhcomp_len > end) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S",
+		    pos, data->sess.dhcomp_len);
+	dhcomp = pos;
+	pos += data->sess.dhcomp_len;
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
+
+	/*
+	 * temp = prf(0+, password)
+	 * key = prf+(temp, ID_S | ID_P)
+	 */
+	if (eap_eke_derive_key(&data->sess, password, password_len,
+			       data->serverid, data->serverid_len,
+			       data->peerid, data->peerid_len, key) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	/*
+	 * y_p = g ^ x_p (mod p)
+	 * x_p = random number 2 .. p-1
+	 */
+	if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
+		os_memset(key, 0, sizeof(key));
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0)
+	{
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
+		os_memset(key, 0, sizeof(key));
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	if (eap_eke_derive_ke_ki(&data->sess,
+				 data->serverid, data->serverid_len,
+				 data->peerid, data->peerid_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
+		os_memset(key, 0, sizeof(key));
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response");
+
+	resp = eap_eke_build_msg(data, eap_get_id(reqData),
+				 data->sess.dhcomp_len + data->sess.pnonce_len,
+				 EAP_EKE_COMMIT);
+	if (resp == NULL) {
+		os_memset(key, 0, sizeof(key));
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	/* DHComponent_P = Encr(key, y_p) */
+	rpos = wpabuf_put(resp, data->sess.dhcomp_len);
+	if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S");
+		os_memset(key, 0, sizeof(key));
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	os_memset(key, 0, sizeof(key));
+
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
+		    rpos, data->sess.dhcomp_len);
+
+	if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) {
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
+			data->nonce_p, data->sess.nonce_len);
+	prot_len = wpabuf_tailroom(resp);
+	if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len,
+			 wpabuf_put(resp, 0), &prot_len) < 0) {
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P",
+		    wpabuf_put(resp, 0), prot_len);
+	wpabuf_put(resp, prot_len);
+
+	/* TODO: CBValue */
+
+	if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp))
+	    < 0) {
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpabuf_put_buf(data->msgs, reqData);
+	wpabuf_put_buf(data->msgs, resp);
+
+	eap_eke_state(data, CONFIRM);
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data,
+					       struct eap_method_ret *ret,
+					       const struct wpabuf *reqData,
+					       const u8 *payload,
+					       size_t payload_len)
+{
+	struct wpabuf *resp;
+	const u8 *pos, *end;
+	size_t prot_len;
+	u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
+	u8 auth_s[EAP_EKE_MAX_HASH_LEN];
+	size_t decrypt_len;
+	u8 *auth;
+
+	if (data->state != CONFIRM) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)",
+			   data->state);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request");
+
+	pos = payload;
+	end = payload + payload_len;
+
+	if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PROTO_ERROR);
+	}
+
+	decrypt_len = sizeof(nonces);
+	if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len,
+				 nonces, &decrypt_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+	}
+	if (decrypt_len != (size_t) 2 * data->sess.nonce_len) {
+		wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S",
+			nonces, 2 * data->sess.nonce_len);
+	if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match trnsmitted Nonce_P");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+	}
+
+	os_memcpy(data->nonce_s, nonces + data->sess.nonce_len,
+		  data->sess.nonce_len);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
+			data->nonce_s, data->sess.nonce_len);
+
+	if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len,
+			      data->peerid, data->peerid_len,
+			      data->nonce_p, data->nonce_s) < 0) {
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0)
+	{
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len);
+	if (os_memcmp(auth_s, pos + data->sess.pnonce_ps_len,
+		      data->sess.prf_len) != 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match");
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response");
+
+	resp = eap_eke_build_msg(data, eap_get_id(reqData),
+				 data->sess.pnonce_len + data->sess.prf_len,
+				 EAP_EKE_CONFIRM);
+	if (resp == NULL) {
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	prot_len = wpabuf_tailroom(resp);
+	if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len,
+			 wpabuf_put(resp, 0), &prot_len) < 0) {
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpabuf_put(resp, prot_len);
+
+	auth = wpabuf_put(resp, data->sess.prf_len);
+	if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) {
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len);
+
+	if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len,
+			       data->peerid, data->peerid_len,
+			       data->nonce_s, data->nonce_p,
+			       data->msk, data->emsk) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
+		wpabuf_free(resp);
+		return eap_eke_build_fail(data, ret, reqData,
+					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+	}
+
+	os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
+	eap_eke_session_clean(&data->sess);
+
+	eap_eke_state(data, SUCCESS);
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_COND_SUCC;
+	ret->allowNotifications = FALSE;
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data,
+					       struct eap_method_ret *ret,
+					       const struct wpabuf *reqData,
+					       const u8 *payload,
+					       size_t payload_len)
+{
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request");
+
+	if (payload_len < 4) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
+	} else {
+		u32 code;
+		code = WPA_GET_BE32(payload);
+		wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code);
+	}
+
+	return eap_eke_build_fail(data, ret, reqData, EAP_EKE_FAIL_NO_ERROR);
+}
+
+
+static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct eap_eke_data *data = priv;
+	struct wpabuf *resp;
+	const u8 *pos, *end;
+	size_t len;
+	u8 eke_exch;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len);
+	if (pos == NULL || len < 1) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	end = pos + len;
+	eke_exch = *pos++;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch);
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos);
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = TRUE;
+
+	switch (eke_exch) {
+	case EAP_EKE_ID:
+		resp = eap_eke_process_id(data, ret, reqData, pos, end - pos);
+		break;
+	case EAP_EKE_COMMIT:
+		resp = eap_eke_process_commit(sm, data, ret, reqData,
+					      pos, end - pos);
+		break;
+	case EAP_EKE_CONFIRM:
+		resp = eap_eke_process_confirm(data, ret, reqData,
+					       pos, end - pos);
+		break;
+	case EAP_EKE_FAILURE:
+		resp = eap_eke_process_failure(data, ret, reqData,
+					       pos, end - pos);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (ret->methodState == METHOD_DONE)
+		ret->allowNotifications = FALSE;
+
+	return resp;
+}
+
+
+static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_eke_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_eke_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_eke_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+
+	return key;
+}
+
+
+int eap_peer_eke_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+				    EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_eke_init;
+	eap->deinit = eap_eke_deinit;
+	eap->process = eap_eke_process;
+	eap->isKeyAvailable = eap_eke_isKeyAvailable;
+	eap->getKey = eap_eke_getKey;
+	eap->get_emsk = eap_eke_get_emsk;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}
diff --git a/src/eap_peer/eap_methods.h b/src/eap_peer/eap_methods.h
index 4994ff1..a465fd2 100644
--- a/src/eap_peer/eap_methods.h
+++ b/src/eap_peer/eap_methods.h
@@ -105,5 +105,6 @@
 int eap_peer_vendor_test_register(void);
 int eap_peer_tnc_register(void);
 int eap_peer_pwd_register(void);
+int eap_peer_eke_register(void);
 
 #endif /* EAP_METHODS_H */
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index a777bb0..be8c301 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -1,6 +1,6 @@
 /*
  * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -164,6 +164,10 @@
 {
 	int res;
 
+	if (config->ocsp)
+		params->flags |= TLS_CONN_REQUEST_OCSP;
+	if (config->ocsp == 2)
+		params->flags |= TLS_CONN_REQUIRE_OCSP;
 	data->conn = tls_connection_init(data->ssl_ctx);
 	if (data->conn == NULL) {
 		wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index f2a7cd7..36b230b 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -104,6 +104,9 @@
 	int fragment_size;
 
 	int pbc_in_m1;
+
+	const u8 *server_id;
+	size_t server_id_len;
 };
 
 
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index f92704a..003e202 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -188,6 +188,9 @@
 	int fragment_size;
 
 	int pbc_in_m1;
+
+	const u8 *server_id;
+	size_t server_id_len;
 };
 
 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
diff --git a/src/eap_server/eap_methods.h b/src/eap_server/eap_methods.h
index bc810a9..429cb72 100644
--- a/src/eap_server/eap_methods.h
+++ b/src/eap_server/eap_methods.h
@@ -45,5 +45,6 @@
 int eap_server_ikev2_register(void);
 int eap_server_tnc_register(void);
 int eap_server_pwd_register(void);
+int eap_server_eke_register(void);
 
 #endif /* EAP_SERVER_METHODS_H */
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 15f7e22..54b7533 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -1278,6 +1278,8 @@
 	sm->fragment_size = conf->fragment_size;
 	sm->pwd_group = conf->pwd_group;
 	sm->pbc_in_m1 = conf->pbc_in_m1;
+	sm->server_id = conf->server_id;
+	sm->server_id_len = conf->server_id_len;
 
 	wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
 
diff --git a/src/eap_server/eap_server_eke.c b/src/eap_server/eap_server_eke.c
new file mode 100644
index 0000000..b19a321
--- /dev/null
+++ b/src/eap_server/eap_server_eke.c
@@ -0,0 +1,793 @@
+/*
+ * hostapd / EAP-EKE (RFC 6124) server
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/random.h"
+#include "eap_server/eap_i.h"
+#include "eap_common/eap_eke_common.h"
+
+
+struct eap_eke_data {
+	enum {
+		IDENTITY, COMMIT, CONFIRM, FAILURE_REPORT, SUCCESS, FAILURE
+	} state;
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 *peerid;
+	size_t peerid_len;
+	u8 peerid_type;
+	u8 serverid_type;
+	u8 dh_priv[EAP_EKE_MAX_DH_LEN];
+	u8 key[EAP_EKE_MAX_KEY_LEN];
+	struct eap_eke_session sess;
+	u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
+	u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
+	struct wpabuf *msgs;
+	int phase2;
+	u32 failure_code;
+};
+
+
+static const char * eap_eke_state_txt(int state)
+{
+	switch (state) {
+	case IDENTITY:
+		return "IDENTITY";
+	case COMMIT:
+		return "COMMIT";
+	case CONFIRM:
+		return "CONFIRM";
+	case FAILURE_REPORT:
+		return "FAILURE_REPORT";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_eke_state(struct eap_eke_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
+		   eap_eke_state_txt(data->state),
+		   eap_eke_state_txt(state));
+	data->state = state;
+}
+
+
+static void eap_eke_fail(struct eap_eke_data *data, u32 code)
+{
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Failure - code 0x%x", code);
+	data->failure_code = code;
+	eap_eke_state(data, FAILURE_REPORT);
+}
+
+
+static void * eap_eke_init(struct eap_sm *sm)
+{
+	struct eap_eke_data *data;
+	size_t i;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	eap_eke_state(data, IDENTITY);
+
+	data->serverid_type = EAP_EKE_ID_OPAQUE;
+	for (i = 0; i < sm->server_id_len; i++) {
+		if (sm->server_id[i] == '.' &&
+		    data->serverid_type == EAP_EKE_ID_OPAQUE)
+			data->serverid_type = EAP_EKE_ID_FQDN;
+		if (sm->server_id[i] == '@')
+			data->serverid_type = EAP_EKE_ID_NAI;
+	}
+
+	data->phase2 = sm->init_phase2;
+
+	return data;
+}
+
+
+static void eap_eke_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_eke_data *data = priv;
+	eap_eke_session_clean(&data->sess);
+	os_free(data->peerid);
+	wpabuf_free(data->msgs);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data,
+					 u8 id, size_t length, u8 eke_exch)
+{
+	struct wpabuf *msg;
+	size_t plen;
+
+	plen = 1 + length;
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
+			    EAP_CODE_REQUEST, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
+		return NULL;
+	}
+
+	wpabuf_put_u8(msg, eke_exch);
+
+	return msg;
+}
+
+
+static int supported_proposal(const u8 *pos)
+{
+	if (pos[0] == EAP_EKE_DHGROUP_EKE_16 &&
+	    pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+	    pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
+	    pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
+		return 1;
+
+	if (pos[0] == EAP_EKE_DHGROUP_EKE_15 &&
+	    pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+	    pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
+	    pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
+		return 1;
+
+	if (pos[0] == EAP_EKE_DHGROUP_EKE_14 &&
+	    pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+	    pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
+	    pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
+		return 1;
+
+	if (pos[0] == EAP_EKE_DHGROUP_EKE_14 &&
+	    pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+	    pos[2] == EAP_EKE_PRF_HMAC_SHA1 &&
+	    pos[3] == EAP_EKE_MAC_HMAC_SHA1)
+		return 1;
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_eke_build_failure(struct eap_eke_data *data, u8 id)
+{
+	struct wpabuf *msg;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Failure: Failure-Code=0x%x",
+		   data->failure_code);
+
+	msg = eap_eke_build_msg(data, id, 4, EAP_EKE_FAILURE);
+	if (msg == NULL) {
+		eap_eke_state(data, FAILURE);
+		return NULL;
+	}
+	wpabuf_put_be32(msg, data->failure_code);
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_eke_build_identity(struct eap_sm *sm,
+					      struct eap_eke_data *data,
+					      u8 id)
+{
+	struct wpabuf *msg;
+	size_t plen;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Identity");
+
+	plen = 2 + 4 * 4 + 1 + sm->server_id_len;
+	msg = eap_eke_build_msg(data, id, plen, EAP_EKE_ID);
+	if (msg == NULL)
+		return NULL;
+
+	wpabuf_put_u8(msg, 4); /* NumProposals */
+	wpabuf_put_u8(msg, 0); /* Reserved */
+
+	/* Proposal - DH Group 16 with AES128-CBC and SHA256 */
+	wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_16); /* Group Description */
+	wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+	wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
+	wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
+
+	/* Proposal - DH Group 15 with AES128-CBC and SHA256 */
+	wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_15); /* Group Description */
+	wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+	wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
+	wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
+
+	/* Proposal - DH Group 14 with AES128-CBC and SHA256 */
+	wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
+	wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+	wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
+	wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
+
+	/*
+	 * Proposal - DH Group 14 with AES128-CBC and SHA1
+	 * (mandatory to implement algorithms)
+	 */
+	wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
+	wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+	wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA1); /* PRF */
+	wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA1); /* MAC */
+
+	/* Server IDType + Identity */
+	wpabuf_put_u8(msg, data->serverid_type);
+	wpabuf_put_data(msg, sm->server_id, sm->server_id_len);
+
+	wpabuf_free(data->msgs);
+	data->msgs = wpabuf_dup(msg);
+	if (data->msgs == NULL) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_eke_build_commit(struct eap_sm *sm,
+					    struct eap_eke_data *data, u8 id)
+{
+	struct wpabuf *msg;
+	u8 pub[EAP_EKE_MAX_DH_LEN];
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Commit");
+
+	if (sm->user == NULL || sm->user->password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Password with not configured");
+		eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+		return eap_eke_build_failure(data, id);
+	}
+
+	if (eap_eke_derive_key(&data->sess, sm->user->password,
+			       sm->user->password_len,
+			       sm->server_id, sm->server_id_len,
+			       data->peerid, data->peerid_len, data->key) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+
+	msg = eap_eke_build_msg(data, id, data->sess.dhcomp_len,
+				EAP_EKE_COMMIT);
+	if (msg == NULL) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+
+	/*
+	 * y_s = g ^ x_s (mod p)
+	 * x_s = random number 2 .. p-1
+	 * temp = prf(0+, password)
+	 * key = prf+(temp, ID_S | ID_P)
+	 * DHComponent_S = Encr(key, y_s)
+	 */
+
+	if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+
+	if (eap_eke_dhcomp(&data->sess, data->key, pub,
+			   wpabuf_put(msg, data->sess.dhcomp_len))
+	    < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S");
+		wpabuf_free(msg);
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+
+	if (wpabuf_resize(&data->msgs, wpabuf_len(msg)) < 0) {
+		wpabuf_free(msg);
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+	wpabuf_put_buf(data->msgs, msg);
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_eke_build_confirm(struct eap_sm *sm,
+					     struct eap_eke_data *data, u8 id)
+{
+	struct wpabuf *msg;
+	size_t plen, prot_len;
+	u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
+	u8 *auth;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Confirm");
+
+	plen = data->sess.pnonce_ps_len + data->sess.prf_len;
+	msg = eap_eke_build_msg(data, id, plen, EAP_EKE_CONFIRM);
+	if (msg == NULL) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+
+	if (random_get_bytes(data->nonce_s, data->sess.nonce_len)) {
+		wpabuf_free(msg);
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
+			data->nonce_s, data->sess.nonce_len);
+
+	os_memcpy(nonces, data->nonce_p, data->sess.nonce_len);
+	os_memcpy(nonces + data->sess.nonce_len, data->nonce_s,
+		  data->sess.nonce_len);
+	prot_len = wpabuf_tailroom(msg);
+	if (eap_eke_prot(&data->sess, nonces, 2 * data->sess.nonce_len,
+			 wpabuf_put(msg, 0), &prot_len) < 0) {
+		wpabuf_free(msg);
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+	wpabuf_put(msg, prot_len);
+
+	if (eap_eke_derive_ka(&data->sess,
+			      sm->server_id, sm->server_id_len,
+			      data->peerid, data->peerid_len,
+			      data->nonce_p, data->nonce_s) < 0) {
+		wpabuf_free(msg);
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+
+	auth = wpabuf_put(msg, data->sess.prf_len);
+	if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth) < 0) {
+		wpabuf_free(msg);
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return eap_eke_build_failure(data, id);
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth, data->sess.prf_len);
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_eke_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_eke_data *data = priv;
+
+	switch (data->state) {
+	case IDENTITY:
+		return eap_eke_build_identity(sm, data, id);
+	case COMMIT:
+		return eap_eke_build_commit(sm, data, id);
+	case CONFIRM:
+		return eap_eke_build_confirm(sm, data, id);
+	case FAILURE_REPORT:
+		return eap_eke_build_failure(data, id);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Unknown state %d in buildReq",
+			   data->state);
+		break;
+	}
+	return NULL;
+}
+
+
+static Boolean eap_eke_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_eke_data *data = priv;
+	size_t len;
+	const u8 *pos;
+	u8 eke_exch;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Invalid frame");
+		return TRUE;
+	}
+
+	eke_exch = *pos;
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: EKE-Exch=%d", eke_exch);
+
+	if (data->state == IDENTITY && eke_exch == EAP_EKE_ID)
+		return FALSE;
+
+	if (data->state == COMMIT && eke_exch == EAP_EKE_COMMIT)
+		return FALSE;
+
+	if (data->state == CONFIRM && eke_exch == EAP_EKE_CONFIRM)
+		return FALSE;
+
+	if (eke_exch == EAP_EKE_FAILURE)
+		return FALSE;
+
+	wpa_printf(MSG_INFO, "EAP-EKE: Unexpected EKE-Exch=%d in state=%d",
+		   eke_exch, data->state);
+
+	return TRUE;
+}
+
+
+static void eap_eke_process_identity(struct eap_sm *sm,
+				     struct eap_eke_data *data,
+				     const struct wpabuf *respData,
+				     const u8 *payload, size_t payloadlen)
+{
+	const u8 *pos, *end;
+	int i;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Identity");
+
+	if (data->state != IDENTITY) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	pos = payload;
+	end = payload + payloadlen;
+
+	if (pos + 2 + 4 + 1 > end) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Too short EAP-EKE-ID payload");
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	if (*pos != 1) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Unexpected NumProposals %d (expected 1)",
+			   *pos);
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	pos += 2;
+
+	if (!supported_proposal(pos)) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Unexpected Proposal (%u:%u:%u:%u)",
+			   pos[0], pos[1], pos[2], pos[3]);
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Selected Proposal (%u:%u:%u:%u)",
+		   pos[0], pos[1], pos[2], pos[3]);
+	if (eap_eke_session_init(&data->sess, pos[0], pos[1], pos[2], pos[3]) <
+	    0) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+	pos += 4;
+
+	data->peerid_type = *pos++;
+	os_free(data->peerid);
+	data->peerid = os_malloc(end - pos);
+	if (data->peerid == NULL) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to allocate memory for peerid");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+	os_memcpy(data->peerid, pos, end - pos);
+	data->peerid_len = end - pos;
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Peer IDType %u", data->peerid_type);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Peer Identity",
+			  data->peerid, data->peerid_len);
+
+	if (eap_user_get(sm, data->peerid, data->peerid_len, data->phase2)) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Peer Identity not found from user database");
+		eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+		return;
+	}
+
+	for (i = 0; i < EAP_MAX_METHODS; i++) {
+		if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
+		    sm->user->methods[i].method == EAP_TYPE_EKE)
+			break;
+	}
+	if (i == EAP_MAX_METHODS) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Matching user entry does not allow EAP-EKE");
+		eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+		return;
+	}
+
+	if (sm->user->password == NULL || sm->user->password_len == 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: No password configured for peer");
+		eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+		return;
+	}
+
+	if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+	wpabuf_put_buf(data->msgs, respData);
+
+	eap_eke_state(data, COMMIT);
+}
+
+
+static void eap_eke_process_commit(struct eap_sm *sm,
+				   struct eap_eke_data *data,
+				   const struct wpabuf *respData,
+				   const u8 *payload, size_t payloadlen)
+{
+	const u8 *pos, *end, *dhcomp, *pnonce;
+	size_t decrypt_len;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Commit");
+
+	if (data->state != COMMIT) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	pos = payload;
+	end = payload + payloadlen;
+
+	if (pos + data->sess.dhcomp_len + data->sess.pnonce_len > end) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
+		    pos, data->sess.dhcomp_len);
+	dhcomp = pos;
+	pos += data->sess.dhcomp_len;
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", pos, data->sess.pnonce_len);
+	pnonce = pos;
+	pos += data->sess.pnonce_len;
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
+
+	if (eap_eke_shared_secret(&data->sess, data->key, data->dh_priv, dhcomp)
+	    < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+
+	if (eap_eke_derive_ke_ki(&data->sess,
+				 sm->server_id, sm->server_id_len,
+				 data->peerid, data->peerid_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+
+	decrypt_len = sizeof(data->nonce_p);
+	if (eap_eke_decrypt_prot(&data->sess, pnonce, data->sess.pnonce_len,
+				 data->nonce_p, &decrypt_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_P");
+		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+		return;
+	}
+	if (decrypt_len < (size_t) data->sess.nonce_len) {
+		wpa_printf(MSG_INFO, "EAP-EKE: PNonce_P protected data too short to include Nonce_P");
+		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+		return;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
+			data->nonce_p, data->sess.nonce_len);
+
+	if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+	wpabuf_put_buf(data->msgs, respData);
+
+	eap_eke_state(data, CONFIRM);
+}
+
+
+static void eap_eke_process_confirm(struct eap_sm *sm,
+				    struct eap_eke_data *data,
+				    const struct wpabuf *respData,
+				    const u8 *payload, size_t payloadlen)
+{
+	size_t decrypt_len;
+	u8 nonce[EAP_EKE_MAX_NONCE_LEN];
+	u8 auth_p[EAP_EKE_MAX_HASH_LEN];
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
+
+	if (data->state != CONFIRM) {
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
+
+	if (payloadlen < (size_t) data->sess.pnonce_len + data->sess.prf_len) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
+		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+		return;
+	}
+
+	decrypt_len = sizeof(nonce);
+	if (eap_eke_decrypt_prot(&data->sess, payload, data->sess.pnonce_len,
+				 nonce, &decrypt_len) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_S");
+		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+		return;
+	}
+	if (decrypt_len < (size_t) data->sess.nonce_len) {
+		wpa_printf(MSG_INFO, "EAP-EKE: PNonce_S protected data too short to include Nonce_S");
+		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+		return;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_S",
+			nonce, data->sess.nonce_len);
+	if (os_memcmp(nonce, data->nonce_s, data->sess.nonce_len) != 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_S does not match previously sent Nonce_S");
+		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+		return;
+	}
+
+	if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth_p) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Could not derive Auth_P");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth_p, data->sess.prf_len);
+	if (os_memcmp(auth_p, payload + data->sess.pnonce_len,
+		      data->sess.prf_len) != 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Auth_P does not match");
+		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+		return;
+	}
+
+	if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len,
+			       data->peerid, data->peerid_len,
+			       data->nonce_s, data->nonce_p,
+			       data->msk, data->emsk) < 0) {
+		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
+		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+		return;
+	}
+
+	os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
+	os_memset(data->key, 0, sizeof(data->key));
+	eap_eke_session_clean(&data->sess);
+
+	eap_eke_state(data, SUCCESS);
+}
+
+
+static void eap_eke_process_failure(struct eap_sm *sm,
+				    struct eap_eke_data *data,
+				    const struct wpabuf *respData,
+				    const u8 *payload, size_t payloadlen)
+{
+	u32 code;
+
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Failure");
+
+	if (payloadlen < 4) {
+		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
+		eap_eke_state(data, FAILURE);
+		return;
+	}
+
+	code = WPA_GET_BE32(payload);
+	wpa_printf(MSG_DEBUG, "EAP-EKE: Peer reported failure code 0x%x", code);
+
+	eap_eke_state(data, FAILURE);
+}
+
+
+static void eap_eke_process(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_eke_data *data = priv;
+	u8 eke_exch;
+	size_t len;
+	const u8 *pos, *end;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
+	if (pos == NULL || len < 1)
+		return;
+
+	eke_exch = *pos;
+	end = pos + len;
+	pos++;
+
+	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received payload", pos, end - pos);
+
+	switch (eke_exch) {
+	case EAP_EKE_ID:
+		eap_eke_process_identity(sm, data, respData, pos, end - pos);
+		break;
+	case EAP_EKE_COMMIT:
+		eap_eke_process_commit(sm, data, respData, pos, end - pos);
+		break;
+	case EAP_EKE_CONFIRM:
+		eap_eke_process_confirm(sm, data, respData, pos, end - pos);
+		break;
+	case EAP_EKE_FAILURE:
+		eap_eke_process_failure(sm, data, respData, pos, end - pos);
+		break;
+	}
+}
+
+
+static Boolean eap_eke_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_eke_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_eke_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_eke_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+
+	return key;
+}
+
+
+static Boolean eap_eke_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_eke_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+int eap_server_eke_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_eke_init;
+	eap->reset = eap_eke_reset;
+	eap->buildReq = eap_eke_buildReq;
+	eap->check = eap_eke_check;
+	eap->process = eap_eke_process;
+	eap->isDone = eap_eke_isDone;
+	eap->getKey = eap_eke_getKey;
+	eap->isSuccess = eap_eke_isSuccess;
+	eap->get_emsk = eap_eke_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
diff --git a/src/eap_server/eap_server_gpsk.c b/src/eap_server/eap_server_gpsk.c
index 2853c48..66f4271 100644
--- a/src/eap_server/eap_server_gpsk.c
+++ b/src/eap_server/eap_server_gpsk.c
@@ -26,8 +26,6 @@
 	size_t pk_len;
 	u8 *id_peer;
 	size_t id_peer_len;
-	u8 *id_server;
-	size_t id_server_len;
 #define MAX_NUM_CSUITES 2
 	struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES];
 	size_t csuite_count;
@@ -71,11 +69,6 @@
 		return NULL;
 	data->state = GPSK_1;
 
-	/* TODO: add support for configuring ID_Server */
-	data->id_server = (u8 *) os_strdup("hostapd");
-	if (data->id_server)
-		data->id_server_len = os_strlen((char *) data->id_server);
-
 	data->csuite_count = 0;
 	if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
 					   EAP_GPSK_CIPHER_AES)) {
@@ -101,7 +94,6 @@
 static void eap_gpsk_reset(struct eap_sm *sm, void *priv)
 {
 	struct eap_gpsk_data *data = priv;
-	os_free(data->id_server);
 	os_free(data->id_peer);
 	os_free(data);
 }
@@ -123,7 +115,7 @@
 	wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
 		    data->rand_server, EAP_GPSK_RAND_LEN);
 
-	len = 1 + 2 + data->id_server_len + EAP_GPSK_RAND_LEN + 2 +
+	len = 1 + 2 + sm->server_id_len + EAP_GPSK_RAND_LEN + 2 +
 		data->csuite_count * sizeof(struct eap_gpsk_csuite);
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
 			    EAP_CODE_REQUEST, id);
@@ -135,8 +127,8 @@
 	}
 
 	wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1);
-	wpabuf_put_be16(req, data->id_server_len);
-	wpabuf_put_data(req, data->id_server, data->id_server_len);
+	wpabuf_put_be16(req, sm->server_id_len);
+	wpabuf_put_data(req, sm->server_id, sm->server_id_len);
 	wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
 	wpabuf_put_be16(req,
 			data->csuite_count * sizeof(struct eap_gpsk_csuite));
@@ -158,7 +150,7 @@
 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
 
 	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
-	len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + data->id_server_len +
+	len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->server_id_len +
 		sizeof(struct eap_gpsk_csuite) + 2 + miclen;
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
 			    EAP_CODE_REQUEST, id);
@@ -174,8 +166,8 @@
 
 	wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN);
 	wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
-	wpabuf_put_be16(req, data->id_server_len);
-	wpabuf_put_data(req, data->id_server, data->id_server_len);
+	wpabuf_put_be16(req, sm->server_id_len);
+	wpabuf_put_data(req, sm->server_id, sm->server_id_len);
 	csuite = wpabuf_put(req, sizeof(*csuite));
 	WPA_PUT_BE32(csuite->vendor, data->vendor);
 	WPA_PUT_BE16(csuite->specifier, data->specifier);
@@ -301,8 +293,8 @@
 		eap_gpsk_state(data, FAILURE);
 		return;
 	}
-	if (alen != data->id_server_len ||
-	    os_memcmp(pos, data->id_server, alen) != 0) {
+	if (alen != sm->server_id_len ||
+	    os_memcmp(pos, sm->server_id, alen) != 0) {
 		wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
 			   "GPSK-2 did not match");
 		eap_gpsk_state(data, FAILURE);
@@ -416,7 +408,7 @@
 				 data->vendor, data->specifier,
 				 data->rand_peer, data->rand_server,
 				 data->id_peer, data->id_peer_len,
-				 data->id_server, data->id_server_len,
+				 sm->server_id, sm->server_id_len,
 				 data->msk, data->emsk,
 				 data->sk, &data->sk_len,
 				 data->pk, &data->pk_len) < 0) {
diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c
index 42aaca2..1ada0c8 100644
--- a/src/eap_server/eap_server_ikev2.c
+++ b/src/eap_server/eap_server_ikev2.c
@@ -103,8 +103,11 @@
 	data->ikev2.proposal.encr = ENCR_AES_CBC;
 	data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP;
 
-	data->ikev2.IDi = (u8 *) os_strdup("hostapd");
-	data->ikev2.IDi_len = 7;
+	data->ikev2.IDi = os_malloc(sm->server_id_len);
+	if (data->ikev2.IDi == NULL)
+		goto failed;
+	os_memcpy(data->ikev2.IDi, sm->server_id, sm->server_id_len);
+	data->ikev2.IDi_len = sm->server_id_len;
 
 	data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret;
 	data->ikev2.cb_ctx = sm;
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index 8d3dd52..3153d2e 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -100,7 +100,6 @@
 {
 	struct wpabuf *req;
 	struct eap_mschapv2_hdr *ms;
-	char *name = "hostapd"; /* TODO: make this configurable */
 	size_t ms_len;
 
 	if (!data->auth_challenge_from_tls &&
@@ -111,7 +110,7 @@
 		return NULL;
 	}
 
-	ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + os_strlen(name);
+	ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->server_id_len;
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
 			    EAP_CODE_REQUEST, id);
 	if (req == NULL) {
@@ -133,7 +132,7 @@
 		wpabuf_put(req, CHALLENGE_LEN);
 	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge",
 		    data->auth_challenge, CHALLENGE_LEN);
-	wpabuf_put_data(req, name, os_strlen(name));
+	wpabuf_put_data(req, sm->server_id, sm->server_id_len);
 
 	return req;
 }
diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c
index 0cd9799..46bedd9 100644
--- a/src/eap_server/eap_server_psk.c
+++ b/src/eap_server/eap_server_psk.c
@@ -22,8 +22,8 @@
 	enum { PSK_1, PSK_3, SUCCESS, FAILURE } state;
 	u8 rand_s[EAP_PSK_RAND_LEN];
 	u8 rand_p[EAP_PSK_RAND_LEN];
-	u8 *id_p, *id_s;
-	size_t id_p_len, id_s_len;
+	u8 *id_p;
+	size_t id_p_len;
 	u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
 	u8 msk[EAP_MSK_LEN];
 	u8 emsk[EAP_EMSK_LEN];
@@ -38,8 +38,6 @@
 	if (data == NULL)
 		return NULL;
 	data->state = PSK_1;
-	data->id_s = (u8 *) "hostapd";
-	data->id_s_len = 7;
 
 	return data;
 }
@@ -70,7 +68,7 @@
 		    data->rand_s, EAP_PSK_RAND_LEN);
 
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
-			    sizeof(*psk) + data->id_s_len,
+			    sizeof(*psk) + sm->server_id_len,
 			    EAP_CODE_REQUEST, id);
 	if (req == NULL) {
 		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
@@ -82,7 +80,7 @@
 	psk = wpabuf_put(req, sizeof(*psk));
 	psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
 	os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
-	wpabuf_put_data(req, data->id_s, data->id_s_len);
+	wpabuf_put_data(req, sm->server_id, sm->server_id_len);
 
 	return req;
 }
@@ -112,13 +110,13 @@
 	os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
 
 	/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
-	buflen = data->id_s_len + EAP_PSK_RAND_LEN;
+	buflen = sm->server_id_len + EAP_PSK_RAND_LEN;
 	buf = os_malloc(buflen);
 	if (buf == NULL)
 		goto fail;
 
-	os_memcpy(buf, data->id_s, data->id_s_len);
-	os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
+	os_memcpy(buf, sm->server_id, sm->server_id_len);
+	os_memcpy(buf + sm->server_id_len, data->rand_p, EAP_PSK_RAND_LEN);
 	if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
 		os_free(buf);
 		goto fail;
@@ -296,7 +294,7 @@
 	os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN);
 
 	/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
-	buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
+	buflen = data->id_p_len + sm->server_id_len + 2 * EAP_PSK_RAND_LEN;
 	buf = os_malloc(buflen);
 	if (buf == NULL) {
 		data->state = FAILURE;
@@ -304,8 +302,8 @@
 	}
 	os_memcpy(buf, data->id_p, data->id_p_len);
 	pos = buf + data->id_p_len;
-	os_memcpy(pos, data->id_s, data->id_s_len);
-	pos += data->id_s_len;
+	os_memcpy(pos, sm->server_id, sm->server_id_len);
+	pos += sm->server_id_len;
 	os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
 	pos += EAP_PSK_RAND_LEN;
 	os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
diff --git a/src/eap_server/eap_server_sake.c b/src/eap_server/eap_server_sake.c
index f72e1bf..68dd76b 100644
--- a/src/eap_server/eap_server_sake.c
+++ b/src/eap_server/eap_server_sake.c
@@ -27,8 +27,6 @@
 	u8 session_id;
 	u8 *peerid;
 	size_t peerid_len;
-	u8 *serverid;
-	size_t serverid_len;
 };
 
 
@@ -77,11 +75,6 @@
 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
 		   data->session_id);
 
-	/* TODO: add support for configuring SERVERID */
-	data->serverid = (u8 *) os_strdup("hostapd");
-	if (data->serverid)
-		data->serverid_len = os_strlen((char *) data->serverid);
-
 	return data;
 }
 
@@ -89,7 +82,6 @@
 static void eap_sake_reset(struct eap_sm *sm, void *priv)
 {
 	struct eap_sake_data *data = priv;
-	os_free(data->serverid);
 	os_free(data->peerid);
 	os_free(data);
 }
@@ -131,8 +123,7 @@
 	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
 
 	plen = 4;
-	if (data->serverid)
-		plen += 2 + data->serverid_len;
+	plen += 2 + sm->server_id_len;
 	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
 	if (msg == NULL) {
 		data->state = FAILURE;
@@ -142,11 +133,9 @@
 	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
 	eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
 
-	if (data->serverid) {
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
-		eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
-				  data->serverid, data->serverid_len);
-	}
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+	eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
+			  sm->server_id, sm->server_id_len);
 
 	return msg;
 }
@@ -169,9 +158,7 @@
 	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
 		    data->rand_s, EAP_SAKE_RAND_LEN);
 
-	plen = 2 + EAP_SAKE_RAND_LEN;
-	if (data->serverid)
-		plen += 2 + data->serverid_len;
+	plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->server_id_len;
 	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
 	if (msg == NULL) {
 		data->state = FAILURE;
@@ -182,11 +169,9 @@
 	eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
 			  data->rand_s, EAP_SAKE_RAND_LEN);
 
-	if (data->serverid) {
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
-		eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
-				  data->serverid, data->serverid_len);
-	}
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+	eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
+			  sm->server_id, sm->server_id_len);
 
 	return msg;
 }
@@ -213,7 +198,7 @@
 	wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
 	mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
 	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-				 data->serverid, data->serverid_len,
+				 sm->server_id, sm->server_id_len,
 				 data->peerid, data->peerid_len, 0,
 				 wpabuf_head(msg), wpabuf_len(msg), mic, mic))
 	{
@@ -362,7 +347,7 @@
 			     (u8 *) &data->tek, data->msk, data->emsk);
 
 	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-			     data->serverid, data->serverid_len,
+			     sm->server_id, sm->server_id_len,
 			     data->peerid, data->peerid_len, 1,
 			     wpabuf_head(respData), wpabuf_len(respData),
 			     attr.mic_p, mic_p);
@@ -399,7 +384,7 @@
 	}
 
 	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-			     data->serverid, data->serverid_len,
+			     sm->server_id, sm->server_id_len,
 			     data->peerid, data->peerid_len, 1,
 			     wpabuf_head(respData), wpabuf_len(respData),
 			     attr.mic_p, mic_p);
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index c3ccb46..013d781 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -830,6 +830,8 @@
 	eap_conf.fragment_size = eapol->conf.fragment_size;
 	eap_conf.pwd_group = eapol->conf.pwd_group;
 	eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
+	eap_conf.server_id = eapol->conf.server_id;
+	eap_conf.server_id_len = eapol->conf.server_id_len;
 	sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
 	if (sm->eap == NULL) {
 		eapol_auth_free(sm);
@@ -1045,6 +1047,8 @@
 	os_free(dst->eap_req_id_text);
 	dst->pwd_group = src->pwd_group;
 	dst->pbc_in_m1 = src->pbc_in_m1;
+	dst->server_id = src->server_id;
+	dst->server_id_len = src->server_id_len;
 	if (src->eap_req_id_text) {
 		dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len);
 		if (dst->eap_req_id_text == NULL)
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index b50bbdd..3a0f450 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -37,6 +37,8 @@
 	int fragment_size;
 	u16 pwd_group;
 	int pbc_in_m1;
+	const u8 *server_id;
+	size_t server_id_len;
 
 	/* Opaque context pointer to owner data for callback functions */
 	void *ctx;
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 0534b8c..0a414ee 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1967,39 +1967,6 @@
 }
 
 
-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 enum p2p_probe_req_status
 p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
 		const u8 *bssid, const u8 *ie, size_t ie_len)
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 5b2d711..0144c9f 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -223,6 +223,11 @@
 	u16 pwd_group;
 
 	/**
+	 * server_id - Server identity
+	 */
+	const char *server_id;
+
+	/**
 	 * wps - Wi-Fi Protected Setup context
 	 *
 	 * If WPS is used with an external RADIUS server (which is quite
@@ -511,6 +516,8 @@
 	eap_conf.tnc = data->tnc;
 	eap_conf.wps = data->wps;
 	eap_conf.pwd_group = data->pwd_group;
+	eap_conf.server_id = (const u8 *) data->server_id;
+	eap_conf.server_id_len = os_strlen(data->server_id);
 	sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
 				       &eap_conf);
 	if (sess->eap == NULL) {
@@ -1280,6 +1287,7 @@
 	data->tnc = conf->tnc;
 	data->wps = conf->wps;
 	data->pwd_group = conf->pwd_group;
+	data->server_id = conf->server_id;
 	if (conf->eap_req_id_text) {
 		data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
 		if (data->eap_req_id_text) {
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 82466c3..284bd59 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -144,6 +144,11 @@
 	u16 pwd_group;
 
 	/**
+	 * server_id - Server identity
+	 */
+	const char *server_id;
+
+	/**
 	 * wps - Wi-Fi Protected Setup context
 	 *
 	 * If WPS is used with an external RADIUS server (which is quite
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 93056ea..33fa1a2 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -15,7 +15,7 @@
 #include "wpa_i.h"
 #include "pmksa_cache.h"
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 static const int pmksa_cache_max_entries = 32;
 
@@ -522,4 +522,4 @@
 	return pmksa;
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index d5aa229..6cbf89a 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -44,7 +44,7 @@
 	PMKSA_EXPIRE,
 };
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
@@ -69,7 +69,7 @@
 void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
 		       const u8 *pmk, size_t pmk_len);
 
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#else /* IEEE8021X_EAPOL */
 
 static inline struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
@@ -122,10 +122,11 @@
 }
 
 static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
-				     void *network_ctx)
+				     void *network_ctx,
+				     const u8 *pmk, size_t pmk_len)
 {
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
 
 #endif /* PMKSA_CACHE_H */
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index ab61867..c51620e 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -18,7 +18,7 @@
 #include "wpa_i.h"
 
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 #define PMKID_CANDIDATE_PRIO_SCAN 1000
 
@@ -508,4 +508,4 @@
 	return sm->preauth_eapol != NULL;
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
diff --git a/src/rsn_supp/preauth.h b/src/rsn_supp/preauth.h
index 27d3112..277f066 100644
--- a/src/rsn_supp/preauth.h
+++ b/src/rsn_supp/preauth.h
@@ -11,7 +11,7 @@
 
 struct wpa_scan_results;
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 void pmksa_candidate_free(struct wpa_sm *sm);
 int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
@@ -27,7 +27,7 @@
 			   int verbose);
 int rsn_preauth_in_progress(struct wpa_sm *sm);
 
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#else /* IEEE8021X_EAPOL */
 
 static inline void pmksa_candidate_free(struct wpa_sm *sm)
 {
@@ -74,6 +74,6 @@
 	return 0;
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
 
 #endif /* PREAUTH_H */
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 221d5fd..539aa25 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -1347,7 +1347,8 @@
 	peer->supp_rates_len = merge_byte_arrays(
 		peer->supp_rates, sizeof(peer->supp_rates),
 		kde->supp_rates + 2, kde->supp_rates_len - 2,
-		kde->ext_supp_rates + 2, kde->ext_supp_rates_len - 2);
+		kde->ext_supp_rates ? kde->ext_supp_rates + 2 : NULL,
+		kde->ext_supp_rates_len - 2);
 	return 0;
 }
 
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index d83700a..292255c 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -392,7 +392,6 @@
 
 	os_memset(&ie, 0, sizeof(ie));
 
-#ifndef CONFIG_NO_WPA2
 	if (sm->proto == WPA_PROTO_RSN) {
 		/* RSN: msg 1/4 should contain PMKID for the selected PMK */
 		const u8 *_buf = (const u8 *) (key + 1);
@@ -405,7 +404,6 @@
 				    "Authenticator", ie.pmkid, PMKID_LEN);
 		}
 	}
-#endif /* CONFIG_NO_WPA2 */
 
 	res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
 	if (res == -2) {
@@ -664,7 +662,6 @@
 				       const u8 *gtk, size_t gtk_len,
 				       int key_info)
 {
-#ifndef CONFIG_NO_WPA2
 	struct wpa_gtk_data gd;
 
 	/*
@@ -703,9 +700,6 @@
 	wpa_supplicant_key_neg_complete(sm, sm->bssid,
 					key_info & WPA_KEY_INFO_SECURE);
 	return 0;
-#else /* CONFIG_NO_WPA2 */
-	return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
@@ -2601,11 +2595,7 @@
 
 int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
 {
-#ifndef CONFIG_NO_WPA2
 	return pmksa_cache_list(sm->pmksa, buf, len);
-#else /* CONFIG_NO_WPA2 */
-	return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
@@ -2636,9 +2626,7 @@
 
 void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
 {
-#ifndef CONFIG_NO_WPA2
 	pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0);
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index c757dcf..26e9c6c 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -245,6 +245,11 @@
 	return 0;
 }
 
+static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm)
+{
+	return 0;
+}
+
 static inline void wpa_sm_key_request(struct wpa_sm *sm, int error,
 				      int pairwise)
 {
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index ba203e6..50b9272 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -107,7 +107,6 @@
 			      int key_mgmt, int mgmt_group_cipher,
 			      struct wpa_sm *sm)
 {
-#ifndef CONFIG_NO_WPA2
 	u8 *pos;
 	struct rsn_ie_hdr *hdr;
 	u16 capab;
@@ -220,9 +219,6 @@
 	WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
 
 	return pos - rsn_ie;
-#else /* CONFIG_NO_WPA2 */
-	return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
diff --git a/src/utils/build_config.h b/src/utils/build_config.h
index f947388..c6f4e43 100644
--- a/src/utils/build_config.h
+++ b/src/utils/build_config.h
@@ -47,31 +47,4 @@
 #endif /* USE_INTERNAL_CRYPTO */
 #endif /* CONFIG_WIN32_DEFAULTS */
 
-#ifdef CONFIG_XCODE_DEFAULTS
-#define CONFIG_DRIVER_OSX
-#define CONFIG_BACKEND_FILE
-#define IEEE8021X_EAPOL
-#define PKCS12_FUNCS
-#define CONFIG_CTRL_IFACE
-#define CONFIG_CTRL_IFACE_UNIX
-#define CONFIG_DEBUG_FILE
-#define EAP_MD5
-#define EAP_TLS
-#define EAP_MSCHAPv2
-#define EAP_PEAP
-#define EAP_TTLS
-#define EAP_GTC
-#define EAP_OTP
-#define EAP_LEAP
-#define EAP_TNC
-#define CONFIG_WPS
-#define EAP_WSC
-
-#ifdef USE_INTERNAL_CRYPTO
-#define CONFIG_TLS_INTERNAL_CLIENT
-#define CONFIG_INTERNAL_LIBTOMMATH
-#define CONFIG_CRYPTO_INTERNAL
-#endif /* USE_INTERNAL_CRYPTO */
-#endif /* CONFIG_XCODE_DEFAULTS */
-
 #endif /* BUILD_CONFIG_H */
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index af63e4d..bea2b33 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -982,6 +982,7 @@
 
 	wpa_printf(MSG_DEBUG, "WPS UPnP: Stop device");
 	web_listener_stop(sm);
+	ssdp_listener_stop(sm);
 	upnp_wps_free_msearchreply(&sm->msearch_replies);
 	upnp_wps_free_subscriptions(&sm->subscriptions, NULL);
 
@@ -995,7 +996,6 @@
 	if (sm->multicast_sd >= 0)
 		close(sm->multicast_sd);
 	sm->multicast_sd = -1;
-	ssdp_listener_stop(sm);
 
 	sm->started = 0;
 }