Accumulative patch from commit b57b560034f1bb1ad3a3892228940dde97323c0e

b57b560 wpa_supplicant: Default to nl80211 instead of wext
ee28f08 hostapd: Add more messages for error paths
61d2ce2 hostapd: Reject configuration file without interface parameter
a8a7890 Clear extra_blacklist_count on FLUSH command
c646862 WPS ER: Allow UPnP interface to be forced
728d971 Use status code 17 (unable to handle new STA) on max-STA limitation
5e24dc8 Add dup_binstr() to help common binary string tasks
8b44ad7 Use os_zalloc() instead of os_malloc() + os_memset()
2c48211 FT RRB: Validate os_malloc() return value before using it
7ca902b Make vlan_file optional if dynamic_vlan is used
bdb112d Add bitfield routines
04382f7 NFC: Add no waiting and no multiple operations options for scripts
fe90496 WPS: Fix AP auto configuration on config token generation
28fcfb6 NFC: Increase wpa_cli command buffer size
8f7a6dd WPS NFC: Allow Device Password ID override for selected registrar
aaecb69 WPS: Use generic MAC Address attribute builder
9ccd916 P2P: Clean up channel--frequency conversion functions
e864c0a Use a common frequency to channel conversion function
02db75b FT: Reset FT flag upon STA deauthentication
7800d45 P2P: Set P2P_DEV_PEER_WAITING_RESPONSE from TX status callback
d78d3c6 EAP peer: Add check before calling getSessionId method
dd57970 Disable network temporarily on repeated connection failures

Change-Id: If8078d5c1ff40ea806e844543cf6f2bf9d24b7ac
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 5e3caf1..07fd11d 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -469,7 +469,7 @@
 	if (!sta) {
 		sta = ap_sta_add(hapd, rx_auth->peer);
 		if (sta == NULL) {
-			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
 			goto fail;
 		}
 	}
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 7bef55f..2e570c0 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -645,7 +645,7 @@
 
 	sta = ap_sta_add(hapd, mgmt->sa);
 	if (!sta) {
-		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
 		goto fail;
 	}
 
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index a832a73..a28c0f8 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -399,15 +399,13 @@
 
 	/* Save station identity for future RADIUS packets */
 	os_free(sm->identity);
-	sm->identity = os_malloc(identity_len + 1);
+	sm->identity = (u8 *) dup_binstr(identity, identity_len);
 	if (sm->identity == NULL) {
 		sm->identity_len = 0;
 		return;
 	}
 
-	os_memcpy(sm->identity, identity, identity_len);
 	sm->identity_len = identity_len;
-	sm->identity[identity_len] = '\0';
 	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
 		       HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity);
 	sm->dot1xAuthEapolRespIdFramesRx++;
@@ -1272,13 +1270,10 @@
 				    NULL) < 0)
 		return;
 
-	identity = os_malloc(len + 1);
+	identity = (u8 *) dup_binstr(buf, len);
 	if (identity == NULL)
 		return;
 
-	os_memcpy(identity, buf, len);
-	identity[len] = '\0';
-
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
 		       HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
 		       "User-Name from Access-Accept '%s'",
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 7b1a9e6..6390e8b 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -837,6 +837,27 @@
 	hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
 
+	if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
+	    !hapd->conf->vlan) {
+		/* dynamic vlans enabled but no (or empty) vlan_file given */
+		struct hostapd_vlan *vlan;
+		vlan = os_zalloc(sizeof(*vlan));
+		if (vlan == NULL) {
+			wpa_printf(MSG_ERROR, "Out of memory while assigning "
+				   "VLAN interfaces");
+			return -1;
+		}
+
+		vlan->vlan_id = VLAN_ID_WILDCARD;
+		os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
+			    hapd->conf->iface);
+		if (hapd->conf->vlan_tail)
+			hapd->conf->vlan_tail->next = vlan;
+		else
+			hapd->conf->vlan = vlan;
+		hapd->conf->vlan_tail = vlan;
+	}
+
 	if (vlan_dynamic_add(hapd, hapd->conf->vlan))
 		return -1;
 
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index ccb3f82..791b48d 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -1166,6 +1166,8 @@
 
 	/* RRB - Forward action frame to the target AP */
 	frame = os_malloc(sizeof(*frame) + len);
+	if (frame == NULL)
+		return -1;
 	frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
 	frame->packet_type = FT_PACKET_REQUEST;
 	frame->action_length = host_to_le16(len);
@@ -1216,6 +1218,8 @@
 	rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
 
 	frame = os_malloc(sizeof(*frame) + rlen);
+	if (frame == NULL)
+		return -1;
 	frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
 	frame->packet_type = FT_PACKET_RESPONSE;
 	frame->action_length = host_to_le16(rlen);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 98fadda..407b066 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.11 Common routines
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -9,6 +9,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "defs.h"
 #include "ieee802_11_defs.h"
 #include "ieee802_11_common.h"
 
@@ -486,3 +487,28 @@
 
 	return 0;
 }
+
+
+enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
+{
+	enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
+
+	if (freq >= 2412 && freq <= 2472) {
+		mode = HOSTAPD_MODE_IEEE80211G;
+		*channel = (freq - 2407) / 5;
+	} else if (freq == 2484) {
+		mode = HOSTAPD_MODE_IEEE80211B;
+		*channel = 14;
+	} else if (freq >= 4900 && freq < 5000) {
+		mode = HOSTAPD_MODE_IEEE80211A;
+		*channel = (freq - 4000) / 5;
+	} else if (freq >= 5000 && freq < 5900) {
+		mode = HOSTAPD_MODE_IEEE80211A;
+		*channel = (freq - 5000) / 5;
+	} else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
+		mode = HOSTAPD_MODE_IEEE80211AD;
+		*channel = (freq - 56160) / 2160;
+	}
+
+	return mode;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 55fa49d..7f59cf2 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -99,5 +99,6 @@
 
 int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
 			  const char *name, const char *val);
+enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
 
 #endif /* IEEE802_11_COMMON_H */
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 7af3317..4656c1b 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -2110,14 +2110,8 @@
 		dlen = dpos - desc;
 	else
 		dlen = os_strlen(desc);
-	drv->adapter_desc = os_malloc(dlen + 1);
-	if (drv->adapter_desc) {
-		os_memcpy(drv->adapter_desc, desc, dlen);
-		drv->adapter_desc[dlen] = '\0';
-	}
-
+	drv->adapter_desc = dup_binstr(desc, dlen);
 	os_free(b);
-
 	if (drv->adapter_desc == NULL)
 		return -1;
 
@@ -2284,14 +2278,8 @@
 	} else {
 		dlen = os_strlen(desc[i]);
 	}
-	drv->adapter_desc = os_malloc(dlen + 1);
-	if (drv->adapter_desc) {
-		os_memcpy(drv->adapter_desc, desc[i], dlen);
-		drv->adapter_desc[dlen] = '\0';
-	}
-
+	drv->adapter_desc = dup_binstr(desc[i], dlen);
 	os_free(names);
-
 	if (drv->adapter_desc == NULL)
 		return -1;
 
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 0b5a7dc..6125015 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5121,35 +5121,11 @@
 			  struct hostapd_channel_data *chan,
 			  struct nlattr *tb_freq[])
 {
-	enum hostapd_hw_mode m;
-
+	u8 channel;
 	chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
 	chan->flag = 0;
-
-	if (chan->freq < 4000)
-		m = HOSTAPD_MODE_IEEE80211B;
-	else if (chan->freq > 50000)
-		m = HOSTAPD_MODE_IEEE80211AD;
-	else
-		m = HOSTAPD_MODE_IEEE80211A;
-
-	switch (m) {
-	case HOSTAPD_MODE_IEEE80211AD:
-		chan->chan = (chan->freq - 56160) / 2160;
-		break;
-	case HOSTAPD_MODE_IEEE80211A:
-		chan->chan = chan->freq / 5 - 1000;
-		break;
-	case HOSTAPD_MODE_IEEE80211B:
-	case HOSTAPD_MODE_IEEE80211G:
-		if (chan->freq == 2484)
-			chan->chan = 14;
-		else
-			chan->chan = (chan->freq - 2407) / 5;
-		break;
-	default:
-		break;
-	}
+	if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
+		chan->chan = channel;
 
 	if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
 		chan->flag |= HOSTAPD_CHAN_DISABLED;
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 9733e01..1401050 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -502,11 +502,9 @@
 					   "IWEVCUSTOM length");
 				return;
 			}
-			buf = os_malloc(iwe->u.data.length + 1);
+			buf = dup_binstr(custom, iwe->u.data.length);
 			if (buf == NULL)
 				return;
-			os_memcpy(buf, custom, iwe->u.data.length);
-			buf[iwe->u.data.length] = '\0';
 			wpa_driver_wext_event_wireless_custom(drv->ctx, buf);
 			os_free(buf);
 			break;
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index 1d0ff6e..04eb4fd 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -50,12 +50,12 @@
 
 struct wpa_driver_ops *wpa_drivers[] =
 {
-#ifdef CONFIG_DRIVER_WEXT
-	&wpa_driver_wext_ops,
-#endif /* CONFIG_DRIVER_WEXT */
 #ifdef CONFIG_DRIVER_NL80211
 	&wpa_driver_nl80211_ops,
 #endif /* CONFIG_DRIVER_NL80211 */
+#ifdef CONFIG_DRIVER_WEXT
+	&wpa_driver_wext_ops,
+#endif /* CONFIG_DRIVER_WEXT */
 #ifdef CONFIG_DRIVER_HOSTAP
 	&wpa_driver_hostap_ops,
 #endif /* CONFIG_DRIVER_HOSTAP */
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 4df8853..c0d7078 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -406,9 +406,11 @@
 		sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
 					       &sm->eapKeyDataLen);
 		os_free(sm->eapSessionId);
-		sm->eapSessionId = sm->m->getSessionId(sm, sm->eap_method_priv,
-						       &sm->eapSessionIdLen);
-		if (sm->eapSessionId) {
+		sm->eapSessionId = NULL;
+		if (sm->m->getSessionId) {
+			sm->eapSessionId = sm->m->getSessionId(
+				sm, sm->eap_method_priv,
+				&sm->eapSessionIdLen);
 			wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
 				    sm->eapSessionId, sm->eapSessionIdLen);
 		}
diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c
index fb6c282..f9aa742 100644
--- a/src/eap_peer/eap_mschapv2.c
+++ b/src/eap_peer/eap_mschapv2.c
@@ -644,10 +644,8 @@
 	 * must allocate a large enough temporary buffer to create that since
 	 * the received message does not include nul termination.
 	 */
-	buf = os_malloc(len + 1);
+	buf = dup_binstr(msdata, len);
 	if (buf) {
-		os_memcpy(buf, msdata, len);
-		buf[len] = '\0';
 		retry = eap_mschapv2_failure_txt(sm, data, buf);
 		os_free(buf);
 	}
diff --git a/src/eap_peer/tncc.c b/src/eap_peer/tncc.c
index f5edfd5..a3ec395 100644
--- a/src/eap_peer/tncc.c
+++ b/src/eap_peer/tncc.c
@@ -741,12 +741,10 @@
 	enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
 	int recommendation_msg = 0;
 
-	buf = os_malloc(len + 1);
+	buf = dup_binstr(msg, len);
 	if (buf == NULL)
 		return TNCCS_PROCESS_ERROR;
 
-	os_memcpy(buf, msg, len);
-	buf[len] = '\0';
 	start = os_strstr(buf, "<TNCCS-Batch ");
 	end = os_strstr(buf, "</TNCCS-Batch>");
 	if (start == NULL || end == NULL || start > end) {
diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c
index 257013e..1b9d701 100644
--- a/src/eap_server/eap_sim_db.c
+++ b/src/eap_server/eap_sim_db.c
@@ -1480,7 +1480,6 @@
  */
 char * sim_get_username(const u8 *identity, size_t identity_len)
 {
-	char *username;
 	size_t pos;
 
 	if (identity == NULL)
@@ -1491,11 +1490,5 @@
 			break;
 	}
 
-	username = os_malloc(pos + 1);
-	if (username == NULL)
-		return NULL;
-	os_memcpy(username, identity, pos);
-	username[pos] = '\0';
-
-	return username;
+	return dup_binstr(identity, pos);
 }
diff --git a/src/eap_server/tncs.c b/src/eap_server/tncs.c
index 5e332ae..e429f1e 100644
--- a/src/eap_server/tncs.c
+++ b/src/eap_server/tncs.c
@@ -851,12 +851,10 @@
 	unsigned char *decoded;
 	size_t decoded_len;
 
-	buf = os_malloc(len + 1);
+	buf = dup_binstr(msg, len);
 	if (buf == NULL)
 		return TNCCS_PROCESS_ERROR;
 
-	os_memcpy(buf, msg, len);
-	buf[len] = '\0';
 	start = os_strstr(buf, "<TNCCS-Batch ");
 	end = os_strstr(buf, "</TNCCS-Batch>");
 	if (start == NULL || end == NULL || start > end) {
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 00fbb90..cbd039a 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -268,8 +268,7 @@
 		"P2P: Starting short listen state (state=%s)",
 		p2p_state_txt(p2p->state));
 
-	freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
-				   p2p->cfg->channel);
+	freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
 	if (freq < 0) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Unknown regulatory class/channel");
@@ -319,8 +318,7 @@
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 		"P2P: Going to listen(only) state");
 
-	freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
-				   p2p->cfg->channel);
+	freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
 	if (freq < 0) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Unknown regulatory class/channel");
@@ -914,7 +912,7 @@
 		channel = c->reg_class[cl].channel[ch];
 	}
 
-	freq = p2p_channel_to_freq(p2p->cfg->country, reg_class, channel);
+	freq = p2p_channel_to_freq(reg_class, channel);
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Next progressive search "
 		"channel: reg_class %u channel %u -> %d MHz",
 		reg_class, channel, freq);
@@ -1243,8 +1241,7 @@
 	u8 op_class, op_channel;
 	unsigned int freq = force_freq ? force_freq : pref_freq;
 
-	if (p2p_freq_to_channel(p2p->cfg->country, freq,
-				&op_class, &op_channel) < 0) {
+	if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Unsupported frequency %u MHz", freq);
 		return -1;
@@ -1280,24 +1277,24 @@
 
 	if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
 	    p2p_supported_freq(p2p, p2p->best_freq_overall) &&
-	    p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_overall,
-				&op_class, &op_channel) == 0) {
+	    p2p_freq_to_channel(p2p->best_freq_overall, &op_class, &op_channel)
+	    == 0) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best "
 			"overall channel as operating channel preference");
 		p2p->op_reg_class = op_class;
 		p2p->op_channel = op_channel;
 	} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
 		   p2p_supported_freq(p2p, p2p->best_freq_5) &&
-		   p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
-				       &op_class, &op_channel) == 0) {
+		   p2p_freq_to_channel(p2p->best_freq_5, &op_class, &op_channel)
+		   == 0) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 5 GHz "
 			"channel as operating channel preference");
 		p2p->op_reg_class = op_class;
 		p2p->op_channel = op_channel;
 	} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_24 > 0 &&
 		   p2p_supported_freq(p2p, p2p->best_freq_24) &&
-		   p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
-				       &op_class, &op_channel) == 0) {
+		   p2p_freq_to_channel(p2p->best_freq_24, &op_class,
+				       &op_channel) == 0) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 2.4 "
 			"GHz channel as operating channel preference");
 		p2p->op_reg_class = op_class;
@@ -1546,8 +1543,7 @@
 
 	if (msg->listen_channel) {
 		int freq;
-		freq = p2p_channel_to_freq((char *) msg->listen_channel,
-					   msg->listen_channel[3],
+		freq = p2p_channel_to_freq(msg->listen_channel[3],
 					   msg->listen_channel[4]);
 		if (freq < 0) {
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1646,8 +1642,7 @@
 
 	if (go) {
 		/* Setup AP mode for WPS provisioning */
-		res.freq = p2p_channel_to_freq(p2p->cfg->country,
-					       p2p->op_reg_class,
+		res.freq = p2p_channel_to_freq(p2p->op_reg_class,
 					       p2p->op_channel);
 		os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
 		res.ssid_len = p2p->ssid_len;
@@ -1671,8 +1666,7 @@
 			int freq;
 			if (freqs + 1 == P2P_MAX_CHANNELS)
 				break;
-			freq = p2p_channel_to_freq(peer->country, c->reg_class,
-						   c->channel[j]);
+			freq = p2p_channel_to_freq(c->reg_class, c->channel[j]);
 			if (freq < 0)
 				continue;
 			res.freq_list[freqs++] = freq;
@@ -1902,8 +1896,7 @@
 
 	if (msg.listen_channel) {
 		os_memcpy(dev->country, msg.listen_channel, 3);
-		dev->listen_freq = p2p_channel_to_freq(dev->country,
-						       msg.listen_channel[3],
+		dev->listen_freq = p2p_channel_to_freq(msg.listen_channel[3],
 						       msg.listen_channel[4]);
 	}
 
@@ -3099,7 +3092,8 @@
 }
 
 
-static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success)
+static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success,
+				       const u8 *addr)
 {
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 		"P2P: GO Negotiation Response (failure) TX callback: "
@@ -3107,6 +3101,12 @@
 	if (p2p->go_neg_peer && p2p->go_neg_peer->status != P2P_SC_SUCCESS) {
 		p2p_go_neg_failed(p2p, p2p->go_neg_peer,
 				  p2p->go_neg_peer->status);
+	} else if (success) {
+		struct p2p_device *dev;
+		dev = p2p_get_device(p2p, addr);
+		if (dev &&
+		    dev->status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
+			dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE;
 	}
 }
 
@@ -3186,7 +3186,7 @@
 		p2p_go_neg_resp_cb(p2p, success);
 		break;
 	case P2P_PENDING_GO_NEG_RESPONSE_FAILURE:
-		p2p_go_neg_resp_failure_cb(p2p, success);
+		p2p_go_neg_resp_failure_cb(p2p, success, dst);
 		break;
 	case P2P_PENDING_GO_NEG_CONFIRM:
 		p2p_go_neg_conf_cb(p2p, result);
@@ -4155,7 +4155,7 @@
 
 int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel)
 {
-	if (p2p_channel_to_freq(p2p->cfg->country, reg_class, channel) < 0)
+	if (p2p_channel_to_freq(reg_class, channel) < 0)
 		return -1;
 
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set Listen channel: "
@@ -4185,8 +4185,7 @@
 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)
+	if (p2p_channel_to_freq(op_reg_class, op_channel) < 0)
 		return -1;
 
 	wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, "P2P: Set Operating channel: "
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index c143ef4..c7cf205 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -351,7 +351,7 @@
 	unsigned int i;
 
 	if (p2p->own_freq_preference > 0 &&
-	    p2p_freq_to_channel(p2p->cfg->country, p2p->own_freq_preference,
+	    p2p_freq_to_channel(p2p->own_freq_preference,
 				&op_reg_class, &op_channel) == 0 &&
 	    p2p_channels_includes(intersection, op_reg_class, op_channel)) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick own channel "
@@ -363,7 +363,7 @@
 	}
 
 	if (p2p->best_freq_overall > 0 &&
-	    p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_overall,
+	    p2p_freq_to_channel(p2p->best_freq_overall,
 				&op_reg_class, &op_channel) == 0 &&
 	    p2p_channels_includes(intersection, op_reg_class, op_channel)) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best overall "
@@ -375,12 +375,11 @@
 	}
 
 	/* First, try to pick the best channel from another band */
-	freq = p2p_channel_to_freq(p2p->cfg->country, p2p->op_reg_class,
-				   p2p->op_channel);
+	freq = p2p_channel_to_freq(p2p->op_reg_class, p2p->op_channel);
 	if (freq >= 2400 && freq < 2500 && p2p->best_freq_5 > 0 &&
 	    !p2p_channels_includes(intersection, p2p->op_reg_class,
 				   p2p->op_channel) &&
-	    p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
+	    p2p_freq_to_channel(p2p->best_freq_5,
 				&op_reg_class, &op_channel) == 0 &&
 	    p2p_channels_includes(intersection, op_reg_class, op_channel)) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 5 GHz "
@@ -394,7 +393,7 @@
 	if (freq >= 4900 && freq < 6000 && p2p->best_freq_24 > 0 &&
 	    !p2p_channels_includes(intersection, p2p->op_reg_class,
 				   p2p->op_channel) &&
-	    p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
+	    p2p_freq_to_channel(p2p->best_freq_24,
 				&op_reg_class, &op_channel) == 0 &&
 	    p2p_channels_includes(intersection, op_reg_class, op_channel)) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 2.4 GHz "
@@ -619,8 +618,6 @@
 			"P2P: Not ready for GO negotiation with " MACSTR,
 			MAC2STR(sa));
 		status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
-		if (dev)
-			dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE;
 		p2p->cfg->go_neg_req_rx(p2p->cfg->cb_ctx, sa,
 					msg.dev_password_id);
 	} else if (p2p->go_neg_peer && p2p->go_neg_peer != dev) {
@@ -736,9 +733,7 @@
 			goto fail;
 
 		dev->go_state = go ? LOCAL_GO : REMOTE_GO;
-		dev->oper_freq = p2p_channel_to_freq((const char *)
-						     msg.operating_channel,
-						     msg.operating_channel[3],
+		dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
 						     msg.operating_channel[4]);
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
 			"channel preference: %d MHz", dev->oper_freq);
@@ -773,8 +768,7 @@
 	if (rx_freq > 0)
 		freq = rx_freq;
 	else
-		freq = p2p_channel_to_freq(p2p->cfg->country,
-					   p2p->cfg->reg_class,
+		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
 					   p2p->cfg->channel);
 	if (freq < 0) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1050,9 +1044,7 @@
 	}
 
 	if (msg.operating_channel) {
-		dev->oper_freq = p2p_channel_to_freq((const char *)
-						     msg.operating_channel,
-						     msg.operating_channel[3],
+		dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
 						     msg.operating_channel[4]);
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
 			"channel preference: %d MHz", dev->oper_freq);
@@ -1231,9 +1223,7 @@
 
 #ifdef ANDROID_P2P
 	if (msg.operating_channel) {
-		dev->oper_freq = p2p_channel_to_freq((const char *)
-						     msg.operating_channel,
-						     msg.operating_channel[3],
+		dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
 						     msg.operating_channel[4]);
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
 			"channel preference: %d MHz", dev->oper_freq);
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 008f3f0..81a0b27 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -570,9 +570,8 @@
 
 /* p2p_utils.c */
 int p2p_random(char *buf, size_t len);
-int p2p_channel_to_freq(const char *country, int reg_class, int channel);
-int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class,
-			u8 *channel);
+int p2p_channel_to_freq(int op_class, int channel);
+int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel);
 void p2p_channels_intersect(const struct p2p_channels *a,
 			    const struct p2p_channels *b,
 			    struct p2p_channels *res);
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 3beefd2..05822c6 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -238,8 +238,7 @@
 	if (op_freq) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Invitation "
 			"processing forced frequency %d MHz", op_freq);
-		if (p2p_freq_to_channel(p2p->cfg->country, op_freq,
-					&reg_class, &channel) < 0) {
+		if (p2p_freq_to_channel(op_freq, &reg_class, &channel) < 0) {
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 				"P2P: Unknown forced freq %d MHz from "
 				"invitation_process()", op_freq);
@@ -278,7 +277,6 @@
 		if (msg.operating_channel) {
 			int req_freq;
 			req_freq = p2p_channel_to_freq(
-				(const char *) msg.operating_channel,
 				msg.operating_channel[3],
 				msg.operating_channel[4]);
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer "
@@ -326,8 +324,7 @@
 			}
 		}
 
-		op_freq = p2p_channel_to_freq(p2p->cfg->country,
-					      p2p->op_reg_class,
+		op_freq = p2p_channel_to_freq(p2p->op_reg_class,
 					      p2p->op_channel);
 		if (op_freq < 0) {
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -362,8 +359,7 @@
 	if (rx_freq > 0)
 		freq = rx_freq;
 	else
-		freq = p2p_channel_to_freq(p2p->cfg->country,
-					   p2p->cfg->reg_class,
+		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
 					   p2p->cfg->channel);
 	if (freq < 0) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index a1268e4..3bbce16 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -217,8 +217,7 @@
 	if (rx_freq > 0)
 		freq = rx_freq;
 	else
-		freq = p2p_channel_to_freq(p2p->cfg->country,
-					   p2p->cfg->reg_class,
+		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
 					   p2p->cfg->channel);
 	if (freq < 0) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index bf75605..d8daa59 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -290,8 +290,7 @@
 	if (rx_freq > 0)
 		freq = rx_freq;
 	else
-		freq = p2p_channel_to_freq(p2p->cfg->country,
-					   p2p->cfg->reg_class,
+		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
 					   p2p->cfg->channel);
 	if (freq < 0)
 		return;
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 37b9361..69bd14b 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -46,11 +46,17 @@
 }
 
 
-static int p2p_channel_to_freq_j4(int reg_class, int channel)
+/**
+ * p2p_channel_to_freq - Convert channel info to frequency
+ * @op_class: Operating class
+ * @channel: Channel number
+ * Returns: Frequency in MHz or -1 if the specified channel is unknown
+ */
+int p2p_channel_to_freq(int op_class, int channel)
 {
-	/* Table J-4 in P802.11REVmb/D4.0 - Global operating classes */
-	/* TODO: more regulatory classes */
-	switch (reg_class) {
+	/* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
+	/* TODO: more operating classes */
+	switch (op_class) {
 	case 81:
 		/* channels 1..13 */
 		if (channel < 1 || channel > 13)
@@ -94,75 +100,34 @@
 
 
 /**
- * p2p_channel_to_freq - Convert channel info to frequency
- * @country: Country code
- * @reg_class: Regulatory class
- * @channel: Channel number
- * Returns: Frequency in MHz or -1 if the specified channel is unknown
- */
-int p2p_channel_to_freq(const char *country, int reg_class, int channel)
-{
-	if (country[2] == 0x04)
-		return p2p_channel_to_freq_j4(reg_class, channel);
-
-	/* These are mainly for backwards compatibility; to be removed */
-	switch (reg_class) {
-	case 1: /* US/1, EU/1, JP/1 = 5 GHz, channels 36,40,44,48 */
-		if (channel < 36 || channel > 48)
-			return -1;
-		return 5000 + 5 * channel;
-	case 3: /* US/3 = 5 GHz, channels 149,153,157,161 */
-	case 5: /* US/5 = 5 GHz, channels 149,153,157,161 */
-		if (channel < 149 || channel > 161)
-			return -1;
-		return 5000 + 5 * channel;
-	case 4: /* EU/4 = 2.407 GHz, channels 1..13 */
-	case 12: /* US/12 = 2.407 GHz, channels 1..11 */
-	case 30: /* JP/30 = 2.407 GHz, channels 1..13 */
-		if (channel < 1 || channel > 13)
-			return -1;
-		return 2407 + 5 * channel;
-	case 31: /* JP/31 = 2.414 GHz, channel 14 */
-		if (channel != 14)
-			return -1;
-		return 2414 + 5 * channel;
-	}
-
-	return -1;
-}
-
-
-/**
  * p2p_freq_to_channel - Convert frequency into channel info
- * @country: Country code
- * @reg_class: Buffer for returning regulatory class
+ * @op_class: Buffer for returning operating class
  * @channel: Buffer for returning channel number
  * Returns: 0 on success, -1 if the specified frequency is unknown
  */
-int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class,
-			u8 *channel)
+int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel)
 {
 	/* TODO: more operating classes */
 	if (freq >= 2412 && freq <= 2472) {
-		*reg_class = 81; /* 2.407 GHz, channels 1..13 */
+		*op_class = 81; /* 2.407 GHz, channels 1..13 */
 		*channel = (freq - 2407) / 5;
 		return 0;
 	}
 
 	if (freq == 2484) {
-		*reg_class = 82; /* channel 14 */
+		*op_class = 82; /* channel 14 */
 		*channel = 14;
 		return 0;
 	}
 
 	if (freq >= 5180 && freq <= 5240) {
-		*reg_class = 115; /* 5 GHz, channels 36..48 */
+		*op_class = 115; /* 5 GHz, channels 36..48 */
 		*channel = (freq - 5000) / 5;
 		return 0;
 	}
 
 	if (freq >= 5745 && freq <= 5805) {
-		*reg_class = 124; /* 5 GHz, channels 149..161 */
+		*op_class = 124; /* 5 GHz, channels 149..161 */
 		*channel = (freq - 5000) / 5;
 		return 0;
 	}
@@ -261,9 +226,8 @@
 	for (i = 0; i < channels->reg_classes; i++) {
 		const struct p2p_reg_class *reg = &channels->reg_class[i];
 		for (j = 0; j < reg->channels; j++) {
-			if (p2p_channel_to_freq_j4(reg->reg_class,
-						   reg->channel[j]) ==
-			    (int) freq)
+			if (p2p_channel_to_freq(reg->reg_class,
+						reg->channel[j]) == (int) freq)
 				return 1;
 		}
 	}
@@ -274,8 +238,7 @@
 int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
 {
 	u8 op_reg_class, op_channel;
-	if (p2p_freq_to_channel(p2p->cfg->country, freq,
-				&op_reg_class, &op_channel) < 0)
+	if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
 		return 0;
 	return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
 				     op_channel);
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index dbb493e..d4533a8 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -315,6 +315,7 @@
 			    int ft_action, const u8 *target_ap,
 			    const u8 *ric_ies, size_t ric_ies_len);
 int wpa_ft_is_completed(struct wpa_sm *sm);
+void wpa_reset_ft_completed(struct wpa_sm *sm);
 int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
 				 size_t ies_len, const u8 *src_addr);
 int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
@@ -346,6 +347,10 @@
 	return 0;
 }
 
+static inline void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+}
+
 static inline int
 wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
 			     const u8 *src_addr)
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 4b08a62..6b7fa91 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -534,6 +534,13 @@
 }
 
 
+void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+	if (sm != NULL)
+		sm->ft_completed = 0;
+}
+
+
 static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
 				      size_t gtk_elem_len)
 {
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index 87c5178..06540bf 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -443,17 +443,16 @@
 			return -1;
 		}
 
-		val = os_malloc(hdr.length + 1);
+		val = dup_binstr(hdr.payload, hdr.length);
 		if (val == NULL) {
 			x509_free_name(name);
 			return -1;
 		}
-		os_memcpy(val, hdr.payload, hdr.length);
-		val[hdr.length] = '\0';
 		if (os_strlen(val) != hdr.length) {
 			wpa_printf(MSG_INFO, "X509: Reject certificate with "
 				   "embedded NUL byte in a string (%s[NUL])",
 				   val);
+			os_free(val);
 			x509_free_name(name);
 			return -1;
 		}
diff --git a/src/utils/Makefile b/src/utils/Makefile
index 0f1f191..940b4d8 100644
--- a/src/utils/Makefile
+++ b/src/utils/Makefile
@@ -14,6 +14,7 @@
 
 LIB_OBJS= \
 	base64.o \
+	bitfield.o \
 	common.o \
 	ip_addr.o \
 	radiotap.o \
diff --git a/src/utils/bitfield.c b/src/utils/bitfield.c
new file mode 100644
index 0000000..f90e4be
--- /dev/null
+++ b/src/utils/bitfield.c
@@ -0,0 +1,89 @@
+/*
+ * Bitfield
+ * 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 "bitfield.h"
+
+
+struct bitfield {
+	u8 *bits;
+	size_t max_bits;
+};
+
+
+struct bitfield * bitfield_alloc(size_t max_bits)
+{
+	struct bitfield *bf;
+
+	bf = os_zalloc(sizeof(*bf) + (max_bits + 7) / 8);
+	if (bf == NULL)
+		return NULL;
+	bf->bits = (u8 *) (bf + 1);
+	bf->max_bits = max_bits;
+	return bf;
+}
+
+
+void bitfield_free(struct bitfield *bf)
+{
+	os_free(bf);
+}
+
+
+void bitfield_set(struct bitfield *bf, size_t bit)
+{
+	if (bit >= bf->max_bits)
+		return;
+	bf->bits[bit / 8] |= BIT(bit % 8);
+}
+
+
+void bitfield_clear(struct bitfield *bf, size_t bit)
+{
+	if (bit >= bf->max_bits)
+		return;
+	bf->bits[bit / 8] &= ~BIT(bit % 8);
+}
+
+
+int bitfield_is_set(struct bitfield *bf, size_t bit)
+{
+	if (bit >= bf->max_bits)
+		return 0;
+	return !!(bf->bits[bit / 8] & BIT(bit % 8));
+}
+
+
+static int first_zero(u8 val)
+{
+	int i;
+	for (i = 0; i < 8; i++) {
+		if (!(val & 0x01))
+			return i;
+		val >>= 1;
+	}
+	return -1;
+}
+
+
+int bitfield_get_first_zero(struct bitfield *bf)
+{
+	size_t i;
+	for (i = 0; i <= (bf->max_bits + 7) / 8; i++) {
+		if (bf->bits[i] != 0xff)
+			break;
+	}
+	if (i > (bf->max_bits + 7) / 8)
+		return -1;
+	i = i * 8 + first_zero(bf->bits[i]);
+	if (i >= bf->max_bits)
+		return -1;
+	return i;
+}
diff --git a/src/utils/bitfield.h b/src/utils/bitfield.h
new file mode 100644
index 0000000..7050a20
--- /dev/null
+++ b/src/utils/bitfield.h
@@ -0,0 +1,21 @@
+/*
+ * Bitfield
+ * 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.
+ */
+
+#ifndef BITFIELD_H
+#define BITFIELD_H
+
+struct bitfield;
+
+struct bitfield * bitfield_alloc(size_t max_bits);
+void bitfield_free(struct bitfield *bf);
+void bitfield_set(struct bitfield *bf, size_t bit);
+void bitfield_clear(struct bitfield *bf, size_t bit);
+int bitfield_is_set(struct bitfield *bf, size_t bit);
+int bitfield_get_first_zero(struct bitfield *bf);
+
+#endif /* BITFIELD_H */
diff --git a/src/utils/common.c b/src/utils/common.c
index e636984..bf326cd 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -517,11 +517,9 @@
 		if (pos == NULL || pos[1] != '\0')
 			return NULL;
 		*len = pos - value;
-		str = os_malloc(*len + 1);
+		str = dup_binstr(value, *len);
 		if (str == NULL)
 			return NULL;
-		os_memcpy(str, value, *len);
-		str[*len] = '\0';
 		return str;
 	} else if (*value == 'P' && value[1] == '"') {
 		const char *pos;
@@ -532,11 +530,9 @@
 		if (pos == NULL || pos[1] != '\0')
 			return NULL;
 		tlen = pos - value;
-		tstr = os_malloc(tlen + 1);
+		tstr = dup_binstr(value, tlen);
 		if (tstr == NULL)
 			return NULL;
-		os_memcpy(tstr, value, tlen);
-		tstr[tlen] = '\0';
 
 		str = os_malloc(tlen + 1);
 		if (str == NULL) {
@@ -610,3 +606,19 @@
 
 	return len;
 }
+
+
+char * dup_binstr(const void *src, size_t len)
+{
+	char *res;
+
+	if (src == NULL)
+		return NULL;
+	res = os_malloc(len + 1);
+	if (res == NULL)
+		return NULL;
+	os_memcpy(res, src, len);
+	res[len] = '\0';
+
+	return res;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index a859042..e4f7031 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -487,6 +487,7 @@
 size_t merge_byte_arrays(u8 *res, size_t res_len,
 			 const u8 *src1, size_t src1_len,
 			 const u8 *src2, size_t src2_len);
+char * dup_binstr(const void *src, size_t len);
 
 static inline int is_zero_ether_addr(const u8 *a)
 {
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index edcc18c..ac9bb1e 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -417,3 +417,14 @@
 
 	return ie;
 }
+
+
+int wps_build_mac_addr(struct wpabuf *msg, const u8 *addr)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (" MACSTR ")",
+		   MAC2STR(addr));
+	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
+	wpabuf_put_be16(msg, ETH_ALEN);
+	wpabuf_put_data(msg, addr, ETH_ALEN);
+	return 0;
+}
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 0897b7b..4e4da5e 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -343,10 +343,36 @@
 	if (wps_build_version(plain) ||
 	    wps_build_cred(&data, plain) ||
 	    wps_build_wfa_ext(plain, 0, NULL, 0)) {
+		os_free(data.new_psk);
 		wpabuf_free(plain);
 		return NULL;
 	}
 
+	if (wps->wps_state == WPS_STATE_NOT_CONFIGURED && data.new_psk &&
+	    wps->ap) {
+		struct wps_credential cred;
+
+		wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based "
+			   "on credential token generation");
+
+		os_memset(&cred, 0, sizeof(cred));
+		os_memcpy(cred.ssid, wps->ssid, wps->ssid_len);
+		cred.ssid_len = wps->ssid_len;
+		cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK;
+		cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES;
+		os_memcpy(cred.key, data.new_psk, data.new_psk_len);
+		cred.key_len = data.new_psk_len;
+
+		wps->wps_state = WPS_STATE_CONFIGURED;
+		wpa_hexdump_ascii_key(MSG_DEBUG,
+				      "WPS: Generated random passphrase",
+				      data.new_psk, data.new_psk_len);
+		if (wps->cred_cb)
+			wps->cred_cb(wps->cb_ctx, &cred);
+	}
+
+	os_free(data.new_psk);
+
 	return plain;
 }
 
diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c
index 3c94a43..7a7c099 100644
--- a/src/wps/wps_dev_attr.c
+++ b/src/wps/wps_dev_attr.c
@@ -257,11 +257,9 @@
 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", str, str_len);
 
 	os_free(dev->manufacturer);
-	dev->manufacturer = os_malloc(str_len + 1);
+	dev->manufacturer = dup_binstr(str, str_len);
 	if (dev->manufacturer == NULL)
 		return -1;
-	os_memcpy(dev->manufacturer, str, str_len);
-	dev->manufacturer[str_len] = '\0';
 
 	return 0;
 }
@@ -278,11 +276,9 @@
 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", str, str_len);
 
 	os_free(dev->model_name);
-	dev->model_name = os_malloc(str_len + 1);
+	dev->model_name = dup_binstr(str, str_len);
 	if (dev->model_name == NULL)
 		return -1;
-	os_memcpy(dev->model_name, str, str_len);
-	dev->model_name[str_len] = '\0';
 
 	return 0;
 }
@@ -299,11 +295,9 @@
 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", str, str_len);
 
 	os_free(dev->model_number);
-	dev->model_number = os_malloc(str_len + 1);
+	dev->model_number = dup_binstr(str, str_len);
 	if (dev->model_number == NULL)
 		return -1;
-	os_memcpy(dev->model_number, str, str_len);
-	dev->model_number[str_len] = '\0';
 
 	return 0;
 }
@@ -320,11 +314,9 @@
 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", str, str_len);
 
 	os_free(dev->serial_number);
-	dev->serial_number = os_malloc(str_len + 1);
+	dev->serial_number = dup_binstr(str, str_len);
 	if (dev->serial_number == NULL)
 		return -1;
-	os_memcpy(dev->serial_number, str, str_len);
-	dev->serial_number[str_len] = '\0';
 
 	return 0;
 }
@@ -341,11 +333,9 @@
 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", str, str_len);
 
 	os_free(dev->device_name);
-	dev->device_name = os_malloc(str_len + 1);
+	dev->device_name = dup_binstr(str, str_len);
 	if (dev->device_name == NULL)
 		return -1;
-	os_memcpy(dev->device_name, str, str_len);
-	dev->device_name[str_len] = '\0';
 
 	return 0;
 }
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 9c0cebb..1af43c2 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -16,16 +16,6 @@
 #include "wps_dev_attr.h"
 
 
-static int wps_build_mac_addr(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address");
-	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
-	wpabuf_put_be16(msg, ETH_ALEN);
-	wpabuf_put_data(msg, wps->mac_addr_e, ETH_ALEN);
-	return 0;
-}
-
-
 static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)
 {
 	u8 state;
@@ -149,7 +139,7 @@
 	if (wps_build_version(msg) ||
 	    wps_build_msg_type(msg, WPS_M1) ||
 	    wps_build_uuid_e(msg, wps->uuid_e) ||
-	    wps_build_mac_addr(wps, msg) ||
+	    wps_build_mac_addr(msg, wps->mac_addr_e) ||
 	    wps_build_enrollee_nonce(wps, msg) ||
 	    wps_build_public_key(wps, msg) ||
 	    wps_build_auth_type_flags(wps, msg) ||
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index 14c1b77..5694997 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -796,52 +796,31 @@
 
 	if (attr->manufacturer) {
 		os_free(sta->manufacturer);
-		sta->manufacturer = os_malloc(attr->manufacturer_len + 1);
-		if (sta->manufacturer) {
-			os_memcpy(sta->manufacturer, attr->manufacturer,
-				  attr->manufacturer_len);
-			sta->manufacturer[attr->manufacturer_len] = '\0';
-		}
+		sta->manufacturer = dup_binstr(attr->manufacturer,
+					       attr->manufacturer_len);
 	}
 
 	if (attr->model_name) {
 		os_free(sta->model_name);
-		sta->model_name = os_malloc(attr->model_name_len + 1);
-		if (sta->model_name) {
-			os_memcpy(sta->model_name, attr->model_name,
-				  attr->model_name_len);
-			sta->model_name[attr->model_name_len] = '\0';
-		}
+		sta->model_name = dup_binstr(attr->model_name,
+					     attr->model_name_len);
 	}
 
 	if (attr->model_number) {
 		os_free(sta->model_number);
-		sta->model_number = os_malloc(attr->model_number_len + 1);
-		if (sta->model_number) {
-			os_memcpy(sta->model_number, attr->model_number,
-				  attr->model_number_len);
-			sta->model_number[attr->model_number_len] = '\0';
-		}
+		sta->model_number = dup_binstr(attr->model_number,
+					       attr->model_number_len);
 	}
 
 	if (attr->serial_number) {
 		os_free(sta->serial_number);
-		sta->serial_number = os_malloc(attr->serial_number_len + 1);
-		if (sta->serial_number) {
-			os_memcpy(sta->serial_number, attr->serial_number,
-				  attr->serial_number_len);
-			sta->serial_number[attr->serial_number_len] = '\0';
-		}
+		sta->serial_number = dup_binstr(attr->serial_number,
+						attr->serial_number_len);
 	}
 
 	if (attr->dev_name) {
 		os_free(sta->dev_name);
-		sta->dev_name = os_malloc(attr->dev_name_len + 1);
-		if (sta->dev_name) {
-			os_memcpy(sta->dev_name, attr->dev_name,
-				  attr->dev_name_len);
-			sta->dev_name[attr->dev_name_len] = '\0';
-		}
+		sta->dev_name = dup_binstr(attr->dev_name, attr->dev_name_len);
 	}
 
 	eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
@@ -1292,6 +1271,22 @@
 	/* Limit event_id to < 32 bits to avoid issues with atoi() */
 	er->event_id &= 0x0fffffff;
 
+	if (filter && os_strncmp(filter, "ifname=", 7) == 0) {
+		const char *pos, *end;
+		pos = filter + 7;
+		end = os_strchr(pos, ' ');
+		if (end) {
+			size_t len = end - pos;
+			os_strlcpy(er->ifname, pos, len < sizeof(er->ifname) ?
+				   len + 1 : sizeof(er->ifname));
+			filter = end + 1;
+		} else {
+			os_strlcpy(er->ifname, pos, sizeof(er->ifname));
+			filter = NULL;
+		}
+		er->forced_ifname = 1;
+	}
+
 	if (filter) {
 		if (inet_aton(filter, &er->filter_addr) == 0) {
 			wpa_printf(MSG_INFO, "WPS UPnP: Invalid filter "
@@ -1302,10 +1297,10 @@
 		wpa_printf(MSG_DEBUG, "WPS UPnP: Only accepting connections "
 			   "with %s", filter);
 	}
-	if (get_netif_info(ifname, &er->ip_addr, &er->ip_addr_text,
+	if (get_netif_info(er->ifname, &er->ip_addr, &er->ip_addr_text,
 			   er->mac_addr)) {
 		wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
-			   "for %s. Does it have IP address?", ifname);
+			   "for %s. Does it have IP address?", er->ifname);
 		wps_er_deinit(er, NULL, NULL);
 		return NULL;
 	}
diff --git a/src/wps/wps_er.h b/src/wps/wps_er.h
index 6119647..4b48ff6 100644
--- a/src/wps/wps_er.h
+++ b/src/wps/wps_er.h
@@ -76,6 +76,7 @@
 struct wps_er {
 	struct wps_context *wps;
 	char ifname[17];
+	int forced_ifname;
 	u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */
 	char *ip_addr_text; /* IP address of network i.f. we use */
 	unsigned ip_addr; /* IP address of network i.f. we use (host order) */
diff --git a/src/wps/wps_er_ssdp.c b/src/wps/wps_er_ssdp.c
index f9f6e6c..e381fec 100644
--- a/src/wps/wps_er_ssdp.c
+++ b/src/wps/wps_er_ssdp.c
@@ -166,7 +166,9 @@
 		return -1;
 	}
 
-	er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr);
+	er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr,
+						    er->forced_ifname ?
+						    er->ifname : NULL);
 	if (er->multicast_sd < 0) {
 		wpa_printf(MSG_INFO, "WPS ER: Failed to open multicast socket "
 			   "for SSDP");
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index 6efc3bf..413379b 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -169,6 +169,7 @@
 			 const struct wpabuf *pubkey, const u8 *dev_pw,
 			 size_t dev_pw_len);
 struct wpabuf * wps_ie_encapsulate(struct wpabuf *data);
+int wps_build_mac_addr(struct wpabuf *msg, const u8 *addr);
 
 /* wps_attr_process.c */
 int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
@@ -196,7 +197,8 @@
 int wps_build_cred(struct wps_data *wps, struct wpabuf *msg);
 int wps_device_store(struct wps_registrar *reg,
 		     struct wps_device_data *dev, const u8 *uuid);
-void wps_registrar_selected_registrar_changed(struct wps_registrar *reg);
+void wps_registrar_selected_registrar_changed(struct wps_registrar *reg,
+					      u16 dev_pw_id);
 const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count);
 int wps_registrar_pbc_overlap(struct wps_registrar *reg,
 			      const u8 *addr, const u8 *uuid_e);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 86ef022..d182f14 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -771,7 +771,7 @@
 	else
 		wps_registrar_add_authorized_mac(
 			reg, (u8 *) "\xff\xff\xff\xff\xff\xff");
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
 	eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
 			       wps_registrar_set_selected_timeout,
@@ -793,7 +793,7 @@
 		addr = pin->enrollee_addr;
 	wps_registrar_remove_authorized_mac(reg, addr);
 	wps_remove_pin(pin);
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -956,7 +956,7 @@
 	os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
 	wps_registrar_remove_authorized_mac(reg,
 					    (u8 *) "\xff\xff\xff\xff\xff\xff");
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -1004,7 +1004,7 @@
 		os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
 	wps_registrar_add_authorized_mac(reg,
 					 (u8 *) "\xff\xff\xff\xff\xff\xff");
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 
 	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
 	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
@@ -1027,7 +1027,7 @@
 	wpa_printf(MSG_DEBUG, "WPS: PIN completed using internal Registrar");
 	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
 	reg->selected_registrar = 0;
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -1531,18 +1531,6 @@
 }
 
 
-static int wps_build_cred_mac_addr(struct wpabuf *msg,
-				   const struct wps_credential *cred)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (" MACSTR ")",
-		   MAC2STR(cred->mac_addr));
-	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
-	wpabuf_put_be16(msg, ETH_ALEN);
-	wpabuf_put_data(msg, cred->mac_addr, ETH_ALEN);
-	return 0;
-}
-
-
 static int wps_build_credential(struct wpabuf *msg,
 				const struct wps_credential *cred)
 {
@@ -1551,7 +1539,7 @@
 	    wps_build_cred_auth_type(msg, cred) ||
 	    wps_build_cred_encr_type(msg, cred) ||
 	    wps_build_cred_network_key(msg, cred) ||
-	    wps_build_cred_mac_addr(msg, cred))
+	    wps_build_mac_addr(msg, cred->mac_addr))
 		return -1;
 	return 0;
 }
@@ -3296,7 +3284,7 @@
 		   "unselect internal Registrar");
 	reg->selected_registrar = 0;
 	reg->pbc = 0;
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -3368,7 +3356,8 @@
  * This function is called when selected registrar state changes, e.g., when an
  * AP receives a SetSelectedRegistrar UPnP message.
  */
-void wps_registrar_selected_registrar_changed(struct wps_registrar *reg)
+void wps_registrar_selected_registrar_changed(struct wps_registrar *reg,
+					      u16 dev_pw_id)
 {
 	wpa_printf(MSG_DEBUG, "WPS: Selected registrar information changed");
 
@@ -3392,7 +3381,8 @@
 			reg->sel_reg_dev_password_id_override =
 				DEV_PW_PUSHBUTTON;
 			wps_set_pushbutton(&methods, reg->wps->config_methods);
-		}
+		} else if (dev_pw_id)
+			reg->sel_reg_dev_password_id_override = dev_pw_id;
 		wpa_printf(MSG_DEBUG, "WPS: Internal Registrar selected "
 			   "(pbc=%d)", reg->pbc);
 		reg->sel_reg_config_methods_override = methods;
@@ -3514,12 +3504,15 @@
 	reg->pbc = 0;
 	wps_registrar_add_authorized_mac(reg,
 					 (u8 *) "\xff\xff\xff\xff\xff\xff");
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, pw_id);
 	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
 	eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
 			       wps_registrar_set_selected_timeout,
 			       reg, NULL);
 
+	wpa_printf(MSG_DEBUG, "WPS: Added NFC Device Password %u to Registrar",
+		   pw_id);
+
 	return 0;
 }
 
@@ -3561,7 +3554,7 @@
 {
 	wps_registrar_remove_authorized_mac(reg,
 					    (u8 *) "\xff\xff\xff\xff\xff\xff");
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 #endif /* CONFIG_WPS_NFC */
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index 09a46a2..af63e4d 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -322,11 +322,9 @@
 	url_len -= 7;
 
 	/* Make a copy of the string to allow modification during parsing */
-	scratch_mem = os_malloc(url_len + 1);
+	scratch_mem = dup_binstr(url, url_len);
 	if (scratch_mem == NULL)
 		goto fail;
-	os_memcpy(scratch_mem, url, url_len);
-	scratch_mem[url_len] = '\0';
 	wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", scratch_mem);
 	host = scratch_mem;
 	path = os_strchr(host, '/');
diff --git a/src/wps/wps_upnp_ap.c b/src/wps/wps_upnp_ap.c
index 54ed98f..4f1dd8f 100644
--- a/src/wps/wps_upnp_ap.c
+++ b/src/wps/wps_upnp_ap.c
@@ -22,7 +22,7 @@
 	struct wps_registrar *reg = timeout_ctx;
 	wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar from ER timed out");
 	s->selected_registrar = 0;
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 }
 
 
@@ -71,7 +71,7 @@
 				       upnp_er_set_selected_timeout, s, reg);
 	}
 
-	wps_registrar_selected_registrar_changed(reg);
+	wps_registrar_selected_registrar_changed(reg, 0);
 
 	return 0;
 }
@@ -83,5 +83,5 @@
 	s->selected_registrar = 0;
 	eloop_cancel_timeout(upnp_er_set_selected_timeout, s, reg);
 	if (reg)
-		wps_registrar_selected_registrar_changed(reg);
+		wps_registrar_selected_registrar_changed(reg, 0);
 }
diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h
index 7f3c561..5c39f7e 100644
--- a/src/wps/wps_upnp_i.h
+++ b/src/wps/wps_upnp_i.h
@@ -171,7 +171,7 @@
 int ssdp_listener_start(struct upnp_wps_device_sm *sm);
 int ssdp_listener_open(void);
 int add_ssdp_network(const char *net_if);
-int ssdp_open_multicast_sock(u32 ip_addr);
+int ssdp_open_multicast_sock(u32 ip_addr, const char *forced_ifname);
 int ssdp_open_multicast(struct upnp_wps_device_sm *sm);
 
 /* wps_upnp_web.c */
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index 17a8207..416961c 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -3,7 +3,7 @@
  * Copyright (c) 2000-2003 Intel Corporation
  * Copyright (c) 2006-2007 Sony Corporation
  * Copyright (c) 2008-2009 Atheros Communications
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
  *
  * See wps_upnp.c for more details on licensing and code history.
  */
@@ -13,6 +13,9 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <net/route.h>
+#ifdef __linux__
+#include <net/if.h>
+#endif /* __linux__ */
 
 #include "common.h"
 #include "uuid.h"
@@ -854,7 +857,7 @@
 }
 
 
-int ssdp_open_multicast_sock(u32 ip_addr)
+int ssdp_open_multicast_sock(u32 ip_addr, const char *forced_ifname)
 {
 	int sd;
 	 /* per UPnP-arch-DeviceArchitecture, 1. Discovery, keep IP packet
@@ -865,6 +868,22 @@
 	if (sd < 0)
 		return -1;
 
+	if (forced_ifname) {
+#ifdef __linux__
+		struct ifreq req;
+		os_memset(&req, 0, sizeof(req));
+		os_strlcpy(req.ifr_name, forced_ifname, sizeof(req.ifr_name));
+		if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, &req,
+			       sizeof(req)) < 0) {
+			wpa_printf(MSG_INFO, "WPS UPnP: Failed to bind "
+				   "multicast socket to ifname %s: %s",
+				   forced_ifname, strerror(errno));
+			close(sd);
+			return -1;
+		}
+#endif /* __linux__ */
+	}
+
 #if 0   /* maybe ok if we sometimes block on writes */
 	if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) {
 		close(sd);
@@ -924,7 +943,7 @@
  */
 int ssdp_open_multicast(struct upnp_wps_device_sm *sm)
 {
-	sm->multicast_sd = ssdp_open_multicast_sock(sm->ip_addr);
+	sm->multicast_sd = ssdp_open_multicast_sock(sm->ip_addr, NULL);
 	if (sm->multicast_sd < 0)
 		return -1;
 	return 0;
diff --git a/src/wps/wps_upnp_web.c b/src/wps/wps_upnp_web.c
index ce0bede..11386d8 100644
--- a/src/wps/wps_upnp_web.c
+++ b/src/wps/wps_upnp_web.c
@@ -996,13 +996,11 @@
 				h++;
 			len = end - h;
 			os_free(callback_urls);
-			callback_urls = os_malloc(len + 1);
+			callback_urls = dup_binstr(h, len);
 			if (callback_urls == NULL) {
 				ret = HTTP_INTERNAL_SERVER_ERROR;
 				goto error;
 			}
-			os_memcpy(callback_urls, h, len);
-			callback_urls[len] = 0;
 			continue;
 		}
 		/* SID is only for renewal */