Accumulative patch from commit 20a0b03debef66cc57b0c34a05f8be5229be907c

atheros: Fix auth_alg configuration for static WEP
nl80211: Implement set_rate_sets for non-hostapd AP case
nl80211: Enable more AP callbacks for non-hostapd AP mode
nl80211: Re-order functions to group AP/hostapd specific code
Remove compiler warning for non-P2P builds
random: Add support for maintaining internal entropy store over restarts
Fix a compiler warning on WPS-AP-without-UPnP builds
P2P: Retry provision discovery requests in IDLE state
P2P: Add callback for provision discovery failure
P2P: Add wpas_notify_p2p_provision_discovery()
P2P: Add group started notification
DBus: Move wpas_dbus_new_decompose_object_path()
DBus: Refactor array adding, add binary arrays
DBus: Add support for P2P primitives
DBus: Fix some typos on comments
Fix CONFIG_AP=y build without CONFIG_P2P=y
Fix non-P2P D-Bus build
nl80211: Add support for driver-based PMKSA cache
P2P: Start GO without extra scan step
Remove a compiler warning on uninitialized variable
Add EVENT_RX_ACTION handler for hostapd
Fix hostapd build without NEED_AP_MLME=y
Fix AP selection to check privacy mismatch and IBSS with WPA/RSN IE
bsd: Fix set_key() sequence number endian issue
Add a copyright and license statement for a radiotap header file
Use nl80211 as an example instead of WEXT
Add notes for CONFIG_WPS_ER build configuration option
Fix CONFIG_NO_WPA_PASSPHRASE=y build
hostapd: Don't mask out non-symmetric STA HT caps
P2P: Enable P2P capability advertisement on D-Bus
P2P: Update D-Bus network object semantics during group formation
P2P: Show P2P peer signal level in D-Bus P2P device properties
P2P: Fix P2P device signal level type in D-Bus
P2P: Add dissasoc_low_ack in P2P device properties
P2P: More complete persistent group management over D-Bus
P2P: Add WpsFailed signal in P2P D-Bus
P2P: Update listen and operating channel from P2P D-Bus
P2P: Fix WpsFailed signal in P2P D-Bus
atheros: Fix glibc 'invalid pointer' error when WPA_TRACE is enabled
Clear WPA and EAPOL state machine config pointer on network removal
	20a0b03debef66cc57b0c34a05f8be5229be907c

Change-Id: I2b83bf86ba9c7a9a218638be7b4de31d209cdde1
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 36bb826..f6076af 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -194,4 +194,12 @@
 	return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
 }
 
+static inline int hostapd_drv_set_authmode(struct hostapd_data *hapd,
+					   int auth_algs)
+{
+	if (hapd->driver == NULL || hapd->driver->set_authmode == NULL)
+		return 0;
+	return hapd->driver->set_authmode(hapd->drv_priv, auth_algs);
+}
+
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 02b7ecf..fc4bc31 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -396,6 +396,46 @@
 }
 
 
+static void hostapd_rx_action(struct hostapd_data *hapd,
+			      struct rx_action *rx_action)
+{
+	struct rx_mgmt rx_mgmt;
+	u8 *buf;
+	struct ieee80211_hdr *hdr;
+
+	wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR
+		   " BSSID=" MACSTR " category=%u",
+		   MAC2STR(rx_action->da), MAC2STR(rx_action->sa),
+		   MAC2STR(rx_action->bssid), rx_action->category);
+	wpa_hexdump(MSG_MSGDUMP, "Received action frame contents",
+		    rx_action->data, rx_action->len);
+
+	buf = os_zalloc(24 + 1 + rx_action->len);
+	if (buf == NULL)
+		return;
+	hdr = (struct ieee80211_hdr *) buf;
+	hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_ACTION);
+	if (rx_action->category == WLAN_ACTION_SA_QUERY) {
+		/*
+		 * Assume frame was protected; it would have been dropped if
+		 * not.
+		 */
+		hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+	}
+	os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN);
+	os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN);
+	os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN);
+	buf[24] = rx_action->category;
+	os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len);
+	os_memset(&rx_mgmt, 0, sizeof(rx_mgmt));
+	rx_mgmt.frame = buf;
+	rx_mgmt.frame_len = 24 + 1 + rx_action->len;
+	hostapd_mgmt_rx(hapd, &rx_mgmt);
+	os_free(buf);
+}
+
+
 static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
 			       size_t len, u16 stype, int ok)
 {
@@ -530,6 +570,14 @@
 			break;
 		hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
 		break;
+#ifdef NEED_AP_MLME
+	case EVENT_RX_ACTION:
+		if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
+		    data->rx_action.bssid == NULL)
+			break;
+		hostapd_rx_action(hapd, &data->rx_action);
+		break;
+#endif /* NEED_AP_MLME */
 	default:
 		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
 		break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 32db668..d8af571 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -306,6 +306,12 @@
 		return 0;
 	}
 
+	/*
+	 * When IEEE 802.1X is not enabled, the driver may need to know how to
+	 * set authentication algorithms for static WEP.
+	 */
+	hostapd_drv_set_authmode(hapd, hapd->conf->auth_algs);
+
 	for (i = 0; i < 4; i++) {
 		if (hapd->conf->ssid.wep.key[i] &&
 		    hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 3dce5cb..6c3696f 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -250,8 +250,14 @@
 		return;
 	os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap));
 	cap = le_to_host16(neg_ht_cap->ht_capabilities_info);
-	cap &= hapd->iconf->ht_capab;
-	cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED);
+
+	/*
+	 * Mask out HT features we don't support, but don't overwrite
+	 * non-symmetric features like STBC and SMPS. Just because
+	 * we're not in dynamic SMPS mode the STA might still be.
+	 */
+	cap &= (hapd->iconf->ht_capab | HT_CAP_INFO_RX_STBC_MASK |
+		HT_CAP_INFO_TX_STBC | HT_CAP_INFO_SMPS_MASK);
 
 	/*
 	 * STBC needs to be handled specially
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 217f9f9..6b6fd4b 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1852,6 +1852,7 @@
 
 const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
 {
+	*len = 0;
 	if (sm == NULL)
 		return NULL;
 
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index fc927f9..640e8cd 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -890,7 +890,7 @@
 {
 	struct wps_context *wps = hapd->wps;
 
-	if (hapd->wps == NULL)
+	if (wps == NULL)
 		return 0;
 
 #ifdef CONFIG_WPS_UPNP
diff --git a/src/crypto/random.c b/src/crypto/random.c
index a30afde..f545917 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -57,12 +57,18 @@
 static int random_fd = -1;
 #endif /* __linux__ */
 static unsigned int own_pool_ready = 0;
+#define RANDOM_ENTROPY_SIZE 20
+static char *random_entropy_file = NULL;
+static int random_entropy_file_read = 0;
 
 #define MIN_COLLECT_ENTROPY 1000
 static unsigned int entropy = 0;
 static unsigned int total_collected = 0;
 
 
+static void random_write_entropy(void);
+
+
 static u32 __ROL32(u32 x, u32 y)
 {
 	return (x << (y & 31)) | (x >> (32 - (y & 31)));
@@ -232,8 +238,12 @@
 	dummy_key_avail += res;
 	close(fd);
 
-	if (dummy_key_avail == sizeof(dummy_key))
+	if (dummy_key_avail == sizeof(dummy_key)) {
+		if (own_pool_ready < MIN_READY_MARK)
+			own_pool_ready = MIN_READY_MARK;
+		random_write_entropy();
 		return 1;
+	}
 
 	wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
 		   "random data available from /dev/random",
@@ -261,6 +271,7 @@
 	own_pool_ready++;
 	wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be "
 		   "ready (count=%u/%u)", own_pool_ready, MIN_READY_MARK);
+	random_write_entropy();
 }
 
 
@@ -298,15 +309,84 @@
 		   (unsigned) (sizeof(dummy_key) - dummy_key_avail));
 	dummy_key_avail += res;
 
-	if (dummy_key_avail == sizeof(dummy_key))
+	if (dummy_key_avail == sizeof(dummy_key)) {
 		random_close_fd();
+		if (own_pool_ready < MIN_READY_MARK)
+			own_pool_ready = MIN_READY_MARK;
+		random_write_entropy();
+	}
 }
 
 #endif /* __linux__ */
 
 
-void random_init(void)
+static void random_read_entropy(void)
 {
+	char *buf;
+	size_t len;
+
+	if (!random_entropy_file)
+		return;
+
+	buf = os_readfile(random_entropy_file, &len);
+	if (buf == NULL)
+		return; /* entropy file not yet available */
+
+	if (len != 1 + RANDOM_ENTROPY_SIZE) {
+		wpa_printf(MSG_DEBUG, "random: Invalid entropy file %s",
+			   random_entropy_file);
+		os_free(buf);
+		return;
+	}
+
+	own_pool_ready = (u8) buf[0];
+	random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE);
+	random_entropy_file_read = 1;
+	os_free(buf);
+	wpa_printf(MSG_DEBUG, "random: Added entropy from %s "
+		   "(own_pool_ready=%u)",
+		   random_entropy_file, own_pool_ready);
+}
+
+
+static void random_write_entropy(void)
+{
+	char buf[RANDOM_ENTROPY_SIZE];
+	FILE *f;
+	u8 opr;
+
+	if (!random_entropy_file)
+		return;
+
+	random_get_bytes(buf, RANDOM_ENTROPY_SIZE);
+
+	f = fopen(random_entropy_file, "wb");
+	if (f == NULL) {
+		wpa_printf(MSG_ERROR, "random: Could not write %s",
+			   random_entropy_file);
+		return;
+	}
+
+	opr = own_pool_ready > 0xff ? 0xff : own_pool_ready;
+	fwrite(&opr, 1, 1, f);
+	fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f);
+	fclose(f);
+
+	wpa_printf(MSG_DEBUG, "random: Updated entropy file %s "
+		   "(own_pool_ready=%u)",
+		   random_entropy_file, own_pool_ready);
+}
+
+
+void random_init(const char *entropy_file)
+{
+	os_free(random_entropy_file);
+	if (entropy_file)
+		random_entropy_file = os_strdup(entropy_file);
+	else
+		random_entropy_file = NULL;
+	random_read_entropy();
+
 #ifdef __linux__
 	if (random_fd >= 0)
 		return;
@@ -326,6 +406,8 @@
 
 	eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL);
 #endif /* __linux__ */
+
+	random_write_entropy();
 }
 
 
@@ -334,4 +416,7 @@
 #ifdef __linux__
 	random_close_fd();
 #endif /* __linux__ */
+	random_write_entropy();
+	os_free(random_entropy_file);
+	random_entropy_file = NULL;
 }
diff --git a/src/crypto/random.h b/src/crypto/random.h
index 5dabd2b..1048bb4 100644
--- a/src/crypto/random.h
+++ b/src/crypto/random.h
@@ -16,14 +16,14 @@
 #define RANDOM_H
 
 #ifdef CONFIG_NO_RANDOM_POOL
-#define random_init() do { } while (0)
+#define random_init(e) do { } while (0)
 #define random_deinit() do { } while (0)
 #define random_add_randomness(b, l) do { } while (0)
 #define random_get_bytes(b, l) os_get_random((b), (l))
 #define random_pool_ready() 1
 #define random_mark_pool_ready() do { } while (0)
 #else /* CONFIG_NO_RANDOM_POOL */
-void random_init(void);
+void random_init(const char *entropy_file);
 void random_deinit(void);
 void random_add_randomness(const void *buf, size_t len);
 int random_get_bytes(void *buf, size_t len);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 2a3efa4..c7dbdc1 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2243,6 +2243,18 @@
 	int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
 
 	/**
+	 * set_authmode - Set authentication algorithm(s) for static WEP
+	 * @priv: Private driver interface data
+	 * @authmode: 1=Open System, 2=Shared Key, 3=both
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function can be used to set authentication algorithms for AP
+	 * mode when static WEP is used. If the driver uses user space MLME/SME
+	 * implementation, there is no need to implement this function.
+	 */
+	int (*set_authmode)(void *priv, int authmode);
+
+	/**
 	 * driver_cmd - execute driver-specific command
 	 * @priv: private driver interface data
 	 * @cmd: command to execute
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 6ac1cea..1e78f6e 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -1116,7 +1116,7 @@
 		drv->we_version = range->we_version_compiled;
 	}
 
-	free(range);
+	os_free(range);
 	return 0;
 }
 
@@ -1357,6 +1357,23 @@
 	return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
 }
 
+static int atheros_set_authmode(void *priv, int auth_algs)
+{
+	int authmode;
+
+	if ((auth_algs & WPA_AUTH_ALG_OPEN) &&
+	    (auth_algs & WPA_AUTH_ALG_SHARED))
+		authmode = IEEE80211_AUTH_AUTO;
+	else if (auth_algs & WPA_AUTH_ALG_OPEN)
+		authmode = IEEE80211_AUTH_OPEN;
+	else if (auth_algs & WPA_AUTH_ALG_SHARED)
+		authmode = IEEE80211_AUTH_SHARED;
+	else
+		return -1;
+
+	return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode);
+}
+
 const struct wpa_driver_ops wpa_driver_atheros_ops = {
 	.name			= "atheros",
 	.hapd_init		= atheros_init,
@@ -1378,4 +1395,5 @@
 	.sta_clear_stats	= atheros_sta_clear_stats,
 	.commit			= atheros_commit,
 	.set_ap_wps_ie		= atheros_set_ap_wps_ie,
+	.set_authmode		= atheros_set_authmode,
 };
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 1b52865..4596a51 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -345,8 +345,20 @@
 	if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
 		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
 	wk.ik_keylen = key_len;
-	if (seq)
+	if (seq) {
+#ifdef WORDS_BIGENDIAN
+		/*
+		 * wk.ik_keyrsc is in host byte order (big endian), need to
+		 * swap it to match with the byte order used in WPA.
+		 */
+		int i;
+		u8 *keyrsc = (u8 *) &wk.ik_keyrsc;
+		for (i = 0; i < seq_len; i++)
+			keyrsc[WPA_KEY_RSC_LEN - i - 1] = seq[i];
+#else /* WORDS_BIGENDIAN */
 		os_memcpy(&wk.ik_keyrsc, seq, seq_len);
+#endif /* WORDS_BIGENDIAN */
+	}
 	os_memcpy(wk.ik_keydata, key, key_len);
 
 	return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index b4f01fa..cfc9372 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5043,70 +5043,17 @@
 }
 
 
-#ifdef HOSTAPD
-
-static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+/* Set kernel driver on given frequency (MHz) */
+static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
 {
-	int i;
-	int *old;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
-		   ifidx);
-	for (i = 0; i < drv->num_if_indices; i++) {
-		if (drv->if_indices[i] == 0) {
-			drv->if_indices[i] = ifidx;
-			return;
-		}
-	}
-
-	if (drv->if_indices != drv->default_if_indices)
-		old = drv->if_indices;
-	else
-		old = NULL;
-
-	drv->if_indices = os_realloc(old,
-				     sizeof(int) * (drv->num_if_indices + 1));
-	if (!drv->if_indices) {
-		if (!old)
-			drv->if_indices = drv->default_if_indices;
-		else
-			drv->if_indices = old;
-		wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
-			   "interfaces");
-		wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
-		return;
-	} else if (!old)
-		os_memcpy(drv->if_indices, drv->default_if_indices,
-			  sizeof(drv->default_if_indices));
-	drv->if_indices[drv->num_if_indices] = ifidx;
-	drv->num_if_indices++;
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
+					   freq->sec_channel_offset);
 }
 
 
-static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-	int i;
-
-	for (i = 0; i < drv->num_if_indices; i++) {
-		if (drv->if_indices[i] == ifidx) {
-			drv->if_indices[i] = 0;
-			break;
-		}
-	}
-}
-
-
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-	int i;
-
-	for (i = 0; i < drv->num_if_indices; i++)
-		if (drv->if_indices[i] == ifidx)
-			return 1;
-
-	return 0;
-}
-
+#if defined(HOSTAPD) || defined(CONFIG_AP)
 
 static inline int min_int(int a, int b)
 {
@@ -5193,20 +5140,6 @@
 	return -ENOBUFS;
 }
 
-#endif /* HOSTAPD */
-
-
-/* Set kernel driver on given frequency (MHz) */
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
-					   freq->sec_channel_offset);
-}
-
-
-#ifdef HOSTAPD
 
 static int i802_set_rts(void *priv, int rts)
 {
@@ -5511,37 +5444,6 @@
 }
 
 
-static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
-                            const char *bridge_ifname)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	char name[IFNAMSIZ + 1];
-
-	os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
-	wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
-		   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
-	if (val) {
-		if (!if_nametoindex(name)) {
-			if (nl80211_create_iface(drv, name,
-						 NL80211_IFTYPE_AP_VLAN,
-						 NULL, 1) < 0)
-				return -1;
-			if (bridge_ifname &&
-			    linux_br_add_if(drv->ioctl_sock, bridge_ifname,
-					    name) < 0)
-				return -1;
-		}
-		linux_set_iface_flags(drv->ioctl_sock, name, 1);
-		return i802_set_sta_vlan(priv, addr, name, 0);
-	} else {
-		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
-		return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
-						    name);
-	}
-}
-
-
 static int i802_set_ht_params(void *priv, const u8 *ht_capab,
 			      size_t ht_capab_len, const u8 *ht_oper,
 			      size_t ht_oper_len)
@@ -5555,26 +5457,6 @@
 }
 
 
-static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct wpa_driver_nl80211_data *drv = eloop_ctx;
-	struct sockaddr_ll lladdr;
-	unsigned char buf[3000];
-	int len;
-	socklen_t fromlen = sizeof(lladdr);
-
-	len = recvfrom(sock, buf, sizeof(buf), 0,
-		       (struct sockaddr *)&lladdr, &fromlen);
-	if (len < 0) {
-		perror("recv");
-		return;
-	}
-
-	if (have_ifidx(drv, lladdr.sll_ifindex))
-		drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
-}
-
-
 static int i802_get_inact_sec(void *priv, const u8 *addr)
 {
 	struct hostap_sta_driver_data data;
@@ -5596,9 +5478,6 @@
 	return 0;
 }
 
-#endif /* HOSTAPD */
-
-#if defined(HOSTAPD) || defined(CONFIG_AP)
 
 static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
 			   int reason)
@@ -5641,6 +5520,120 @@
 
 #ifdef HOSTAPD
 
+static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+	int i;
+	int *old;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
+		   ifidx);
+	for (i = 0; i < drv->num_if_indices; i++) {
+		if (drv->if_indices[i] == 0) {
+			drv->if_indices[i] = ifidx;
+			return;
+		}
+	}
+
+	if (drv->if_indices != drv->default_if_indices)
+		old = drv->if_indices;
+	else
+		old = NULL;
+
+	drv->if_indices = os_realloc(old,
+				     sizeof(int) * (drv->num_if_indices + 1));
+	if (!drv->if_indices) {
+		if (!old)
+			drv->if_indices = drv->default_if_indices;
+		else
+			drv->if_indices = old;
+		wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
+			   "interfaces");
+		wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
+		return;
+	} else if (!old)
+		os_memcpy(drv->if_indices, drv->default_if_indices,
+			  sizeof(drv->default_if_indices));
+	drv->if_indices[drv->num_if_indices] = ifidx;
+	drv->num_if_indices++;
+}
+
+
+static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+	int i;
+
+	for (i = 0; i < drv->num_if_indices; i++) {
+		if (drv->if_indices[i] == ifidx) {
+			drv->if_indices[i] = 0;
+			break;
+		}
+	}
+}
+
+
+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+	int i;
+
+	for (i = 0; i < drv->num_if_indices; i++)
+		if (drv->if_indices[i] == ifidx)
+			return 1;
+
+	return 0;
+}
+
+
+static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
+                            const char *bridge_ifname)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	char name[IFNAMSIZ + 1];
+
+	os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+	wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
+		   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
+	if (val) {
+		if (!if_nametoindex(name)) {
+			if (nl80211_create_iface(drv, name,
+						 NL80211_IFTYPE_AP_VLAN,
+						 NULL, 1) < 0)
+				return -1;
+			if (bridge_ifname &&
+			    linux_br_add_if(drv->ioctl_sock, bridge_ifname,
+					    name) < 0)
+				return -1;
+		}
+		linux_set_iface_flags(drv->ioctl_sock, name, 1);
+		return i802_set_sta_vlan(priv, addr, name, 0);
+	} else {
+		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
+		return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
+						    name);
+	}
+}
+
+
+static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_driver_nl80211_data *drv = eloop_ctx;
+	struct sockaddr_ll lladdr;
+	unsigned char buf[3000];
+	int len;
+	socklen_t fromlen = sizeof(lladdr);
+
+	len = recvfrom(sock, buf, sizeof(buf), 0,
+		       (struct sockaddr *)&lladdr, &fromlen);
+	if (len < 0) {
+		perror("recv");
+		return;
+	}
+
+	if (have_ifidx(drv, lladdr.sll_ifindex))
+		drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
+}
+
+
 static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
 			     struct i802_bss *bss,
 			     const char *brname, const char *ifname)
@@ -6562,6 +6555,55 @@
 }
 
 
+static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
+			 const u8 *pmkid)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	genlmsg_put(msg, 0, 0, genl_family_get_id(bss->drv->nl80211), 0, 0,
+		    cmd, 0);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+	if (pmkid)
+		NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid);
+	if (bssid)
+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+
+	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ nla_put_failure:
+	return -ENOBUFS;
+}
+
+
+static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+{
+	struct i802_bss *bss = priv;
+	wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
+	return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
+}
+
+
+static int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+{
+	struct i802_bss *bss = priv;
+	wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
+		   MAC2STR(bssid));
+	return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
+}
+
+
+static int nl80211_flush_pmkid(void *priv)
+{
+	struct i802_bss *bss = priv;
+	wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
+	return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -6594,6 +6636,9 @@
 #ifdef HOSTAPD
 	.hapd_init = i802_init,
 	.hapd_deinit = i802_deinit,
+	.set_wds_sta = i802_set_wds_sta,
+#endif /* HOSTAPD */
+#if defined(HOSTAPD) || defined(CONFIG_AP)
 	.get_seqnum = i802_get_seqnum,
 	.flush = i802_flush,
 	.read_sta_data = i802_read_sta_data,
@@ -6601,16 +6646,13 @@
 	.sta_clear_stats = i802_sta_clear_stats,
 	.set_rts = i802_set_rts,
 	.set_frag = i802_set_frag,
-	.set_rate_sets = i802_set_rate_sets,
 	.set_cts_protect = i802_set_cts_protect,
 	.set_preamble = i802_set_preamble,
 	.set_short_slot_time = i802_set_short_slot_time,
 	.set_tx_queue_params = i802_set_tx_queue_params,
 	.set_sta_vlan = i802_set_sta_vlan,
-	.set_wds_sta = i802_set_wds_sta,
 	.set_ht_params = i802_set_ht_params,
-#endif /* HOSTAPD */
-#if defined(HOSTAPD) || defined(CONFIG_AP)
+	.set_rate_sets = i802_set_rate_sets,
 	.sta_deauth = i802_sta_deauth,
 	.sta_disassoc = i802_sta_disassoc,
 #endif /* HOSTAPD || CONFIG_AP */
@@ -6631,4 +6673,7 @@
 	.set_intra_bss = nl80211_set_intra_bss,
 	.set_param = nl80211_set_param,
 	.get_radio_name = nl80211_get_radio_name,
+	.add_pmkid = nl80211_add_pmkid,
+	.remove_pmkid = nl80211_remove_pmkid,
+	.flush_pmkid = nl80211_flush_pmkid,
 };
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 653609e..191099a 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -576,7 +576,7 @@
 	dev->listen_freq = freq;
 	if (msg.group_info)
 		dev->oper_freq = freq;
-	dev->level = level;
+	dev->info.level = level;
 
 	p2p_copy_wps_info(dev, 0, &msg);
 
@@ -2250,19 +2250,81 @@
 	p2p_set_timeout(p2p, 0, 200000);
 }
 
+
+/**
+ * p2p_retry_pd - Retry any pending provision disc requests in IDLE state
+ * @p2p: P2P module context from p2p_init()
+ */
+void p2p_retry_pd(struct p2p_data *p2p)
+{
+	struct p2p_device *dev;
+
+	if (p2p->state != P2P_IDLE)
+		return;
+
+	/*
+	 * Retry the prov disc req attempt only for the peer that the user had
+	 * requested for and provided a join has not been initiated on it
+	 * in the meantime.
+	 */
+
+	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+		if (os_memcmp(p2p->pending_pd_devaddr,
+			      dev->info.p2p_device_addr, ETH_ALEN) != 0)
+			continue;
+		if (!dev->req_config_methods)
+			continue;
+		if (dev->flags & P2P_DEV_PD_FOR_JOIN)
+			continue;
+
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
+			"pending Provisioning Discovery Request to "
+			MACSTR " (config methods 0x%x)",
+			MAC2STR(dev->info.p2p_device_addr),
+			dev->req_config_methods);
+		p2p_send_prov_disc_req(p2p, dev, 0);
+		return;
+	}
+}
+
+
 static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
 {
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 		"P2P: Provision Discovery Request TX callback: success=%d",
 		success);
-	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+	/*
+	 * Postpone resetting the pending action state till after we actually
+	 * time out. This allows us to take some action like notifying any
+	 * interested parties about no response to the request.
+	 *
+	 * When the timer (below) goes off we check in IDLE, SEARCH, or
+	 * LISTEN_ONLY state, which are the only allowed states to issue a PD
+	 * requests in, if this was still pending and then raise notification.
+	 */
 
 	if (!success) {
+		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
 		if (p2p->state != P2P_IDLE)
 			p2p_continue_find(p2p);
+		else if (p2p->user_initiated_pd) {
+			p2p->pending_action_state = P2P_PENDING_PD;
+			p2p_set_timeout(p2p, 0, 300000);
+		}
 		return;
 	}
 
+	/*
+	 * This postponing, of resetting pending_action_state, needs to be
+	 * done only for user initiated PD requests and not internal ones.
+	 */
+	if (p2p->user_initiated_pd)
+		p2p->pending_action_state = P2P_PENDING_PD;
+	else
+		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
 	/* Wait for response from the peer */
 	if (p2p->state == P2P_SEARCH)
 		p2p_set_state(p2p, P2P_PD_DURING_FIND);
@@ -2653,6 +2715,34 @@
 }
 
 
+static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
+{
+	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+	/*
+	 * For user initiated PD requests that we have not gotten any responses
+	 * for while in IDLE state, we retry them a couple of times before
+	 * giving up.
+	 */
+	if (!p2p->user_initiated_pd)
+		return;
+
+	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+		"P2P: User initiated Provision Discovery Request timeout");
+
+	if (p2p->pd_retries) {
+		p2p->pd_retries--;
+		p2p_retry_pd(p2p);
+	} else {
+		if (p2p->cfg->prov_disc_fail)
+			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx,
+						 p2p->pending_pd_devaddr,
+						 P2P_PROV_DISC_TIMEOUT);
+		p2p_reset_pending_pd(p2p);
+	}
+}
+
+
 static void p2p_timeout_invite(struct p2p_data *p2p)
 {
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
@@ -2701,8 +2791,14 @@
 
 	switch (p2p->state) {
 	case P2P_IDLE:
+		/* Check if we timed out waiting for PD req */
+		if (p2p->pending_action_state == P2P_PENDING_PD)
+			p2p_timeout_prov_disc_req(p2p);
 		break;
 	case P2P_SEARCH:
+		/* Check if we timed out waiting for PD req */
+		if (p2p->pending_action_state == P2P_PENDING_PD)
+			p2p_timeout_prov_disc_req(p2p);
 		p2p_search(p2p);
 		break;
 	case P2P_CONNECT:
@@ -2714,6 +2810,10 @@
 	case P2P_GO_NEG:
 		break;
 	case P2P_LISTEN_ONLY:
+		/* Check if we timed out waiting for PD req */
+		if (p2p->pending_action_state == P2P_PENDING_PD)
+			p2p_timeout_prov_disc_req(p2p);
+
 		if (p2p->ext_listen_only) {
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 				"P2P: Extended Listen Timing - Listen State "
@@ -2861,7 +2961,7 @@
 			  "invitation_reqs=%u\n",
 			  (int) (now.sec - dev->last_seen.sec),
 			  dev->listen_freq,
-			  dev->level,
+			  dev->info.level,
 			  p2p_wps_method_text(dev->wps_method),
 			  MAC2STR(dev->interface_addr),
 			  MAC2STR(dev->member_in_go_dev),
@@ -3328,6 +3428,22 @@
 }
 
 
+int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
+			 int cfg_op_channel)
+{
+	if (p2p_channel_to_freq(p2p->cfg->country, op_reg_class, op_channel)
+	    < 0)
+		return -1;
+
+	wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, "P2P: Set Operating channel: "
+		"reg_class %u channel %u", op_reg_class, op_channel);
+	p2p->cfg->op_reg_class = op_reg_class;
+	p2p->cfg->op_channel = op_channel;
+	p2p->cfg->cfg_op_channel = cfg_op_channel;
+	return 0;
+}
+
+
 int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
 			   u8 *iface_addr)
 {
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 954f562..db816a6 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -180,6 +180,11 @@
 	char serial_number[33];
 
 	/**
+	 * level - Signal level
+	 */
+	int level;
+
+	/**
 	 * config_methods - WPS Configuration Methods
 	 */
 	u16 config_methods;
@@ -210,6 +215,12 @@
 	struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
 };
 
+enum p2p_prov_disc_status {
+	P2P_PROV_DISC_SUCCESS,
+	P2P_PROV_DISC_TIMEOUT,
+	P2P_PROV_DISC_REJECTED,
+};
+
 /**
  * struct p2p_config - P2P configuration
  *
@@ -603,6 +614,21 @@
 	void (*prov_disc_resp)(void *ctx, const u8 *peer, u16 config_methods);
 
 	/**
+	 * prov_disc_fail - Callback on Provision Discovery failure
+	 * @ctx: Callback context from cb_ctx
+	 * @peer: Source address of the response
+	 * @status: Cause of failure, will not be %P2P_PROV_DISC_SUCCESS
+	 *
+	 * This callback is used to indicate either a failure or no response
+	 * to an earlier provision discovery request.
+	 *
+	 * This callback handler can be set to %NULL if provision discovery
+	 * is not used or failures do not need to be indicated.
+	 */
+	void (*prov_disc_fail)(void *ctx, const u8 *peer,
+			       enum p2p_prov_disc_status status);
+
+	/**
 	 * invitation_process - Optional callback for processing Invitations
 	 * @ctx: Callback context from cb_ctx
 	 * @sa: Source address of the Invitation Request
@@ -1470,4 +1496,15 @@
 int p2p_add_wps_vendor_extension(struct p2p_data *p2p,
 				 const struct wpabuf *vendor_ext);
 
+/**
+ * p2p_set_oper_channel - Set the P2P operating channel
+ * @p2p: P2P module context from p2p_init()
+ * @op_reg_class: Operating regulatory class to set
+ * @op_channel: operating channel to set
+ * @cfg_op_channel : Whether op_channel is hardcoded in configuration
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
+			 int cfg_op_channel);
+
 #endif /* P2P_H */
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 68b1194..52d9311 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -33,7 +33,6 @@
 	struct dl_list list;
 	struct os_time last_seen;
 	int listen_freq;
-	int level;
 	enum p2p_wps_method wps_method;
 
 	struct p2p_peer_info info;
@@ -393,6 +392,23 @@
 	 * wps_vendor_ext - WPS Vendor Extensions to add
 	 */
 	struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+
+	/*
+	 * user_initiated_pd - Whether a PD request is user initiated or not.
+	 */
+	u8 user_initiated_pd;
+
+	/*
+	 * Keep track of which peer a given PD request was sent to.
+	 * Used to raise a timeout alert in case there is no response.
+	 */
+	u8 pending_pd_devaddr[ETH_ALEN];
+
+	/*
+	 * Retry counter for provision discovery requests when issued
+	 * in IDLE state.
+	 */
+	int pd_retries;
 };
 
 /**
@@ -586,6 +602,7 @@
 				const u8 *data, size_t len);
 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
 			   int join);
+void p2p_reset_pending_pd(struct p2p_data *p2p);
 
 /* p2p_invitation.c */
 void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index e064216..f7ff06c 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -21,6 +21,13 @@
 #include "p2p.h"
 
 
+/*
+ * Number of retries to attempt for provision discovery requests during IDLE
+ * state in case the peer is not listening.
+ */
+#define MAX_PROV_DISC_REQ_RETRIES 10
+
+
 static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
 					    u16 config_methods)
 {
@@ -215,6 +222,11 @@
 		return;
 	}
 
+	if (p2p->pending_action_state == P2P_PENDING_PD) {
+		os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
+		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+	}
+
 	if (dev->dialog_token != msg.dialog_token) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Ignore Provisioning Discovery Response with "
@@ -224,9 +236,20 @@
 		return;
 	}
 
+	/*
+	 * If the response is from the peer to whom a user initiated request
+	 * was sent earlier, we reset that state info here.
+	 */
+	if (p2p->user_initiated_pd &&
+	    os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
+		p2p_reset_pending_pd(p2p);
+
 	if (msg.wps_config_methods != dev->req_config_methods) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
 			"our Provisioning Discovery Request");
+		if (p2p->cfg->prov_disc_fail)
+			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
+						 P2P_PROV_DISC_REJECTED);
 		p2p_parse_free(&msg);
 		goto out;
 	}
@@ -301,6 +324,8 @@
 		return -1;
 	}
 
+	os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
+
 	wpabuf_free(req);
 	return 0;
 }
@@ -343,5 +368,23 @@
 		return 0;
 	}
 
+	/*
+	 * We use the join param as a cue to differentiate between user
+	 * initiated PD request and one issued during finds (internal).
+	 */
+	p2p->user_initiated_pd = !join;
+
+	/* Also set some retries to attempt in case of IDLE state */
+	if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
+		p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
+
 	return p2p_send_prov_disc_req(p2p, dev, join);
 }
+
+
+void p2p_reset_pending_pd(struct p2p_data *p2p)
+{
+	p2p->user_initiated_pd = 0;
+	os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
+	p2p->pd_retries = 0;
+}
diff --git a/src/utils/radiotap_iter.h b/src/utils/radiotap_iter.h
index 92a798a..2e0e872 100644
--- a/src/utils/radiotap_iter.h
+++ b/src/utils/radiotap_iter.h
@@ -1,3 +1,18 @@
+/*
+ * Radiotap parser
+ *
+ * Copyright 2007		Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
 #ifndef __RADIOTAP_ITER_H
 #define __RADIOTAP_ITER_H