Accumulative patch from commit 88c8bf311efa4eb64468bed9b41b3110ab9effff

88c8bf3 WPS NFC: Allow configuration token to be built from network block
e205401 WPS ER: Allow Enrollee to be specified with MAC address
c44a19c WPS ER: Document additional NFC command for ER operations
59307b3 WPS ER: Allow AP to be specified with BSSID
49e160a WPS: Fix use of pre-configured DH keys with multiple operations
5c9d63d WPS: Be more careful with pre-configured DH parameters
cd61936 hostapd: Show more helpful message for -g and -G errors

Change-Id: I7bfd1fa30214c54f2536679411ccd11bb4dd896d
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/main.c b/hostapd/main.c
index 881a053..d2ec1a5 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -525,6 +525,8 @@
 		return -1;
 	pos = os_strrchr(interfaces->global_iface_path, '/');
 	if (pos == NULL) {
+		wpa_printf(MSG_ERROR, "No '/' in the global control interface "
+			   "file");
 		os_free(interfaces->global_iface_path);
 		interfaces->global_iface_path = NULL;
 		return -1;
@@ -614,10 +616,12 @@
 			exit(1);
 			break;
 		case 'g':
-			hostapd_get_global_ctrl_iface(&interfaces, optarg);
+			if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
+				return -1;
 			break;
 		case 'G':
-			hostapd_get_ctrl_iface_group(&interfaces, optarg);
+			if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
+				return -1;
 			break;
 		default:
 			usage();
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 39fce56..cb03dbd 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup
- * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -793,14 +793,19 @@
 void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx);
 void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
 			u16 sel_reg_config_methods);
-int wps_er_pbc(struct wps_er *er, const u8 *uuid);
-int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
-		 size_t pin_len);
-int wps_er_set_config(struct wps_er *er, const u8 *uuid,
+int wps_er_pbc(struct wps_er *er, const u8 *uuid, const u8 *addr);
+const u8 * wps_er_get_sta_uuid(struct wps_er *er, const u8 *addr);
+int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *addr,
+		 const u8 *pin, size_t pin_len);
+int wps_er_set_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
 		      const struct wps_credential *cred);
-int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
-		  size_t pin_len, const struct wps_credential *cred);
-struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid);
+int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
+		  const u8 *pin, size_t pin_len,
+		  const struct wps_credential *cred);
+struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
+					      struct wps_credential *cred);
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
+					const u8 *addr);
 
 int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]);
 char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index 29aee8e..edcc18c 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -24,8 +24,15 @@
 
 	wpa_printf(MSG_DEBUG, "WPS:  * Public Key");
 	wpabuf_free(wps->dh_privkey);
-	if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey) {
+	wps->dh_privkey = NULL;
+	if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey &&
+	    wps->wps->dh_ctx) {
 		wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys");
+		if (wps->wps->dh_pubkey == NULL) {
+			wpa_printf(MSG_DEBUG,
+				   "WPS: wps->wps->dh_pubkey == NULL");
+			return -1;
+		}
 		wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey);
 		wps->dh_ctx = wps->wps->dh_ctx;
 		wps->wps->dh_ctx = NULL;
@@ -34,13 +41,22 @@
 	} else if (wps->dev_pw_id >= 0x10 && wps->wps->ap &&
 		   wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) {
 		wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
+		if (wps->wps->ap_nfc_dh_privkey == NULL) {
+			wpa_printf(MSG_DEBUG,
+				   "WPS: wps->wps->ap_nfc_dh_privkey == NULL");
+			return -1;
+		}
+		if (wps->wps->ap_nfc_dh_pubkey == NULL) {
+			wpa_printf(MSG_DEBUG,
+				   "WPS: wps->wps->ap_nfc_dh_pubkey == NULL");
+			return -1;
+		}
 		wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey);
 		pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey);
 		wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
 #endif /* CONFIG_WPS_NFC */
 	} else {
 		wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
-		wps->dh_privkey = NULL;
 		dh5_free(wps->dh_ctx);
 		wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey);
 		pubkey = wpabuf_zeropad(pubkey, 192);
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index 95a0dec..14c1b77 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup - External Registrar
- * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -97,13 +97,16 @@
 
 
 static struct wps_er_ap * wps_er_ap_get(struct wps_er *er,
-					struct in_addr *addr, const u8 *uuid)
+					struct in_addr *addr, const u8 *uuid,
+					const u8 *mac_addr)
 {
 	struct wps_er_ap *ap;
 	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
 		if ((addr == NULL || ap->addr.s_addr == addr->s_addr) &&
 		    (uuid == NULL ||
-		     os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0))
+		     os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0) &&
+		    (mac_addr == NULL ||
+		     os_memcmp(mac_addr, ap->mac_addr, ETH_ALEN) == 0))
 			return ap;
 	}
 	return NULL;
@@ -290,7 +293,7 @@
 	struct wps_er_ap *ap;
 	struct wps_er_ap_settings *settings;
 
-	ap = wps_er_ap_get(er, addr, NULL);
+	ap = wps_er_ap_get(er, addr, NULL, NULL);
 	if (ap == NULL || ap->ap_settings == NULL)
 		return -1;
 
@@ -636,7 +639,7 @@
 {
 	struct wps_er_ap *ap;
 
-	ap = wps_er_ap_get(er, addr, uuid);
+	ap = wps_er_ap_get(er, addr, uuid, NULL);
 	if (ap) {
 		/* Update advertisement timeout */
 		eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
@@ -1555,7 +1558,7 @@
 }
 
 
-int wps_er_pbc(struct wps_er *er, const u8 *uuid)
+int wps_er_pbc(struct wps_er *er, const u8 *uuid, const u8 *addr)
 {
 	int res;
 	struct wps_er_ap *ap;
@@ -1569,11 +1572,14 @@
 		return -2;
 	}
 
-	ap = wps_er_ap_get(er, NULL, uuid);
+	if (uuid)
+		ap = wps_er_ap_get(er, NULL, uuid, NULL);
+	else
+		ap = NULL;
 	if (ap == NULL) {
 		struct wps_er_sta *sta = NULL;
 		dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
-			sta = wps_er_sta_get(ap, NULL, uuid);
+			sta = wps_er_sta_get(ap, addr, uuid);
 			if (sta) {
 				uuid = ap->uuid;
 				break;
@@ -1619,6 +1625,19 @@
 }
 
 
+const u8 * wps_er_get_sta_uuid(struct wps_er *er, const u8 *addr)
+{
+	struct wps_er_ap *ap;
+	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
+		struct wps_er_sta *sta;
+		sta = wps_er_sta_get(ap, addr, NULL);
+		if (sta)
+			return sta->uuid;
+	}
+	return NULL;
+}
+
+
 static void wps_er_http_put_message_cb(void *ctx, struct http_client *c,
 				       enum http_client_event event)
 {
@@ -1877,20 +1896,22 @@
 }
 
 
-int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
-		 size_t pin_len)
+int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *addr,
+		 const u8 *pin, size_t pin_len)
 {
 	struct wps_er_ap *ap;
 
 	if (er == NULL)
 		return -1;
 
-	ap = wps_er_ap_get(er, NULL, uuid);
+	ap = wps_er_ap_get(er, NULL, uuid, addr);
 	if (ap == NULL) {
 		wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
 			   "request");
 		return -1;
 	}
+	if (uuid == NULL)
+		uuid = ap->uuid;
 	if (ap->wps) {
 		wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
 			   "with the AP - cannot start learn");
@@ -1908,7 +1929,7 @@
 }
 
 
-int wps_er_set_config(struct wps_er *er, const u8 *uuid,
+int wps_er_set_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
 		      const struct wps_credential *cred)
 {
 	struct wps_er_ap *ap;
@@ -1916,7 +1937,7 @@
 	if (er == NULL)
 		return -1;
 
-	ap = wps_er_ap_get(er, NULL, uuid);
+	ap = wps_er_ap_get(er, NULL, uuid, addr);
 	if (ap == NULL) {
 		wpa_printf(MSG_DEBUG, "WPS ER: AP not found for set config "
 			   "request");
@@ -1960,20 +1981,23 @@
 }
 
 
-int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
-		  size_t pin_len, const struct wps_credential *cred)
+int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
+		  const u8 *pin, size_t pin_len,
+		  const struct wps_credential *cred)
 {
 	struct wps_er_ap *ap;
 
 	if (er == NULL)
 		return -1;
 
-	ap = wps_er_ap_get(er, NULL, uuid);
+	ap = wps_er_ap_get(er, NULL, uuid, addr);
 	if (ap == NULL) {
 		wpa_printf(MSG_DEBUG, "WPS ER: AP not found for config "
 			   "request");
 		return -1;
 	}
+	if (uuid == NULL)
+		uuid = ap->uuid;
 	if (ap->wps) {
 		wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
 			   "with the AP - cannot start config");
@@ -1999,31 +2023,20 @@
 
 
 #ifdef CONFIG_WPS_NFC
-struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid)
+
+struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
+					      struct wps_credential *cred)
 {
-	struct wps_er_ap *ap;
 	struct wpabuf *ret;
 	struct wps_data data;
 
-	if (er == NULL)
-		return NULL;
-
-	ap = wps_er_ap_get(er, NULL, uuid);
-	if (ap == NULL)
-		return NULL;
-	if (ap->ap_settings == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
-			   "selected AP");
-		return NULL;
-	}
-
 	ret = wpabuf_alloc(500);
 	if (ret == NULL)
 		return NULL;
 
 	os_memset(&data, 0, sizeof(data));
-	data.wps = er->wps;
-	data.use_cred = ap->ap_settings;
+	data.wps = wps;
+	data.use_cred = cred;
 	if (wps_build_version(ret) ||
 	    wps_build_cred(&data, ret) ||
 	    wps_build_wfa_ext(ret, 0, NULL, 0)) {
@@ -2033,4 +2046,26 @@
 
 	return ret;
 }
+
+
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
+					const u8 *addr)
+{
+	struct wps_er_ap *ap;
+
+	if (er == NULL)
+		return NULL;
+
+	ap = wps_er_ap_get(er, NULL, uuid, addr);
+	if (ap == NULL)
+		return NULL;
+	if (ap->ap_settings == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
+			   "selected AP");
+		return NULL;
+	}
+
+	return wps_er_config_token_from_cred(er->wps, ap->ap_settings);
+}
+
 #endif /* CONFIG_WPS_NFC */
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index 2a1dda5..3d07109 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -259,16 +259,16 @@
 wps_er_stop
 - stop WPS ER functionality
 
-wps_er_learn <UUID> <AP PIN>
+wps_er_learn <UUID|BSSID> <AP PIN>
 - learn AP configuration
 
-wps_er_set_config <UUID> <network id>
+wps_er_set_config <UUID|BSSID> <network id>
 - use AP configuration from a locally configured network (e.g., from
   wps_reg command); this does not change the AP's configuration, but
   only prepares a configuration to be used when enrolling a new device
   to the AP
 
-wps_er_config <UUID> <AP PIN> <new SSID> <auth> <encr> <new key>
+wps_er_config <UUID|BSSID> <AP PIN> <new SSID> <auth> <encr> <new key>
 - examples:
   wps_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 testing WPA2PSK CCMP 12345678
   wpa_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 clear OPEN NONE ""
@@ -277,10 +277,10 @@
 <encr> must be one of the following: NONE WEP TKIP CCMP
 
 
-wps_er_pbc <Enrollee UUID>
+wps_er_pbc <Enrollee UUID|MAC address>
 - accept an Enrollee PBC using External Registrar
 
-wps_er_pin <Enrollee UUID> <PIN> [Enrollee MAC address]
+wps_er_pin <Enrollee UUID|"any"|MAC address> <PIN> [Enrollee MAC address]
 - add an Enrollee PIN to External Registrar
 - if Enrollee UUID is not known, "any" can be used to add a wildcard PIN
 - if the MAC address of the enrollee is known, it should be configured
@@ -346,6 +346,10 @@
 can be used to touch an NFC interface on a station to provision the
 credentials needed to access the network.
 
+The "wps_nfc_config_token <WPS/NDEF> <network id>" command can be used
+to build an NFC configuration token based on a locally configured
+network.
+
 If the station includes NFC interface and reads an NFC tag with a MIME
 media type "application/vnd.wfa.wsc", the NDEF message payload (with or
 without NDEF encapsulation) can be delivered to wpa_supplicant using the
@@ -368,12 +372,15 @@
 argument selects which type of connection handover is requested (WPS =
 Wi-Fi handover as specified in WSC 2.0).
 
-"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
-contents of a Handover Select Message for connection handover when this
-does not depend on the contents of the Handover Request Message. The
-first argument selects the format of the output data and the second
-argument selects which type of connection handover is requested (WPS =
-Wi-Fi handover as specified in WSC 2.0).
+"nfc_get_handover_sel <NDEF> <WPS> [UUID|BSSID]" command can be used to
+build the contents of a Handover Select Message for connection handover
+when this does not depend on the contents of the Handover Request
+Message. The first argument selects the format of the output data and
+the second argument selects which type of connection handover is
+requested (WPS = Wi-Fi handover as specified in WSC 2.0). If the options
+UUID|BSSID argument is included, this is a request to build the handover
+message for the specified AP when wpa_supplicant is operating as a WPS
+ER.
 
 "nfc_rx_handover_req <hexdump of payload>" is used to indicate receipt
 of NFC connection handover request. The payload may include multiple
@@ -392,3 +399,13 @@
 indicates whether the local device initiated or responded to the
 connection handover and the carrier records are the selected carrier
 from the handover request and select messages as a hexdump.
+
+The "wps_er_nfc_config_token <WPS/NDEF> <UUID|BSSID>" command can be
+used to build an NFC configuration token for the specified AP when
+wpa_supplicant is operating as a WPS ER. The output value from this
+command is a hexdump of the selected AP configuration (WPS parameter
+requests this to include only the WPS attributes; NDEF parameter
+requests additional NDEF encapsulation to be included). This data needs
+to be written to an NFC tag with an external program. Once written, the
+NFC configuration token can be used to touch an NFC interface on a
+station to provision the credentials needed to access the network.
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 6d2b3b1..ad0392f 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -784,7 +784,11 @@
 	int ndef;
 	struct wpabuf *buf;
 	int res;
+	char *pos;
 
+	pos = os_strchr(cmd, ' ');
+	if (pos)
+		*pos++ = '\0';
 	if (os_strcmp(cmd, "WPS") == 0)
 		ndef = 0;
 	else if (os_strcmp(cmd, "NDEF") == 0)
@@ -792,7 +796,7 @@
 	else
 		return -1;
 
-	buf = wpas_wps_nfc_config_token(wpa_s, ndef);
+	buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos);
 	if (buf == NULL)
 		return -1;
 
diff --git a/wpa_supplicant/examples/wps-nfc.py b/wpa_supplicant/examples/wps-nfc.py
index 86473cd..dbc143a 100755
--- a/wpa_supplicant/examples/wps-nfc.py
+++ b/wpa_supplicant/examples/wps-nfc.py
@@ -53,10 +53,12 @@
     print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
 
 
-def wpas_get_config_token():
+def wpas_get_config_token(id=None):
     wpas = wpas_connect()
     if (wpas == None):
         return None
+    if id:
+        return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF " + id).rstrip().decode("hex")
     return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
 
 
@@ -258,9 +260,9 @@
         time.sleep(0.1)
 
 
-def wps_write_config_tag(clf):
+def wps_write_config_tag(clf, id=None):
     print "Write WPS config token"
-    data = wpas_get_config_token()
+    data = wpas_get_config_token(id)
     if (data == None):
         print "Could not get WPS config token from wpa_supplicant"
         return
@@ -364,6 +366,10 @@
             wps_write_config_tag(clf)
             raise SystemExit
 
+        if len(sys.argv) > 2 and sys.argv[1] == "write-config-id":
+            wps_write_config_tag(clf, sys.argv[2])
+            raise SystemExit
+
         if len(sys.argv) > 2 and sys.argv[1] == "write-er-config":
             wps_write_er_config_tag(clf, sys.argv[2])
             raise SystemExit
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 603ce91..9af6084 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant / WPS integration
- * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -1605,91 +1605,128 @@
 			const char *uuid, const char *pin)
 {
 	u8 u[UUID_LEN];
-	int any = 0;
+	const u8 *use_uuid = NULL;
+	u8 addr_buf[ETH_ALEN];
 
-	if (os_strcmp(uuid, "any") == 0)
-		any = 1;
-	else if (uuid_str2bin(uuid, u))
+	if (os_strcmp(uuid, "any") == 0) {
+	} else if (uuid_str2bin(uuid, u) == 0) {
+		use_uuid = u;
+	} else if (hwaddr_aton(uuid, addr_buf) == 0) {
+		use_uuid = wps_er_get_sta_uuid(wpa_s->wps_er, addr_buf);
+		if (use_uuid == NULL)
+			return -1;
+	} else
 		return -1;
 	return wps_registrar_add_pin(wpa_s->wps->registrar, addr,
-				     any ? NULL : u,
+				     use_uuid,
 				     (const u8 *) pin, os_strlen(pin), 300);
 }
 
 
 int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid)
 {
-	u8 u[UUID_LEN];
+	u8 u[UUID_LEN], *use_uuid = NULL;
+	u8 addr[ETH_ALEN], *use_addr = NULL;
 
-	if (uuid_str2bin(uuid, u))
+	if (uuid_str2bin(uuid, u) == 0)
+		use_uuid = u;
+	else if (hwaddr_aton(uuid, addr) == 0)
+		use_addr = addr;
+	else
 		return -1;
-	return wps_er_pbc(wpa_s->wps_er, u);
+	return wps_er_pbc(wpa_s->wps_er, use_uuid, use_addr);
 }
 
 
 int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
 		      const char *pin)
 {
-	u8 u[UUID_LEN];
+	u8 u[UUID_LEN], *use_uuid = NULL;
+	u8 addr[ETH_ALEN], *use_addr = NULL;
 
-	if (uuid_str2bin(uuid, u))
+	if (uuid_str2bin(uuid, u) == 0)
+		use_uuid = u;
+	else if (hwaddr_aton(uuid, addr) == 0)
+		use_addr = addr;
+	else
 		return -1;
-	return wps_er_learn(wpa_s->wps_er, u, (const u8 *) pin,
+
+	return wps_er_learn(wpa_s->wps_er, use_uuid, use_addr, (const u8 *) pin,
 			    os_strlen(pin));
 }
 
 
+static int wpas_wps_network_to_cred(struct wpa_ssid *ssid,
+				    struct wps_credential *cred)
+{
+	os_memset(cred, 0, sizeof(*cred));
+	if (ssid->ssid_len > 32)
+		return -1;
+	os_memcpy(cred->ssid, ssid->ssid, ssid->ssid_len);
+	cred->ssid_len = ssid->ssid_len;
+	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
+		cred->auth_type = (ssid->proto & WPA_PROTO_RSN) ?
+			WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK;
+		if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
+			cred->encr_type = WPS_ENCR_AES;
+		else
+			cred->encr_type = WPS_ENCR_TKIP;
+		if (ssid->passphrase) {
+			cred->key_len = os_strlen(ssid->passphrase);
+			if (cred->key_len >= 64)
+				return -1;
+			os_memcpy(cred->key, ssid->passphrase, cred->key_len);
+		} else if (ssid->psk_set) {
+			cred->key_len = 32;
+			os_memcpy(cred->key, ssid->psk, 32);
+		} else
+			return -1;
+	} else {
+		cred->auth_type = WPS_AUTH_OPEN;
+		cred->encr_type = WPS_ENCR_NONE;
+	}
+
+	return 0;
+}
+
+
 int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
 			   int id)
 {
-	u8 u[UUID_LEN];
+	u8 u[UUID_LEN], *use_uuid = NULL;
+	u8 addr[ETH_ALEN], *use_addr = NULL;
 	struct wpa_ssid *ssid;
 	struct wps_credential cred;
 
-	if (uuid_str2bin(uuid, u))
+	if (uuid_str2bin(uuid, u) == 0)
+		use_uuid = u;
+	else if (hwaddr_aton(uuid, addr) == 0)
+		use_addr = addr;
+	else
 		return -1;
 	ssid = wpa_config_get_network(wpa_s->conf, id);
 	if (ssid == NULL || ssid->ssid == NULL)
 		return -1;
 
-	os_memset(&cred, 0, sizeof(cred));
-	if (ssid->ssid_len > 32)
+	if (wpas_wps_network_to_cred(ssid, &cred) < 0)
 		return -1;
-	os_memcpy(cred.ssid, ssid->ssid, ssid->ssid_len);
-	cred.ssid_len = ssid->ssid_len;
-	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
-		cred.auth_type = (ssid->proto & WPA_PROTO_RSN) ?
-			WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK;
-		if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
-			cred.encr_type = WPS_ENCR_AES;
-		else
-			cred.encr_type = WPS_ENCR_TKIP;
-		if (ssid->passphrase) {
-			cred.key_len = os_strlen(ssid->passphrase);
-			if (cred.key_len >= 64)
-				return -1;
-			os_memcpy(cred.key, ssid->passphrase, cred.key_len);
-		} else if (ssid->psk_set) {
-			cred.key_len = 32;
-			os_memcpy(cred.key, ssid->psk, 32);
-		} else
-			return -1;
-	} else {
-		cred.auth_type = WPS_AUTH_OPEN;
-		cred.encr_type = WPS_ENCR_NONE;
-	}
-	return wps_er_set_config(wpa_s->wps_er, u, &cred);
+	return wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &cred);
 }
 
 
 int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
 		       const char *pin, struct wps_new_ap_settings *settings)
 {
-	u8 u[UUID_LEN];
+	u8 u[UUID_LEN], *use_uuid = NULL;
+	u8 addr[ETH_ALEN], *use_addr = NULL;
 	struct wps_credential cred;
 	size_t len;
 
-	if (uuid_str2bin(uuid, u))
+	if (uuid_str2bin(uuid, u) == 0)
+		use_uuid = u;
+	else if (hwaddr_aton(uuid, addr) == 0)
+		use_addr = addr;
+	else
 		return -1;
 	if (settings->ssid_hex == NULL || settings->auth == NULL ||
 	    settings->encr == NULL || settings->key_hex == NULL)
@@ -1728,8 +1765,8 @@
 	else
 		return -1;
 
-	return wps_er_config(wpa_s->wps_er, u, (const u8 *) pin,
-			     os_strlen(pin), &cred);
+	return wps_er_config(wpa_s->wps_er, use_uuid, use_addr,
+			     (const u8 *) pin, os_strlen(pin), &cred);
 }
 
 
@@ -1738,15 +1775,20 @@
 					     int ndef, const char *uuid)
 {
 	struct wpabuf *ret;
-	u8 u[UUID_LEN];
+	u8 u[UUID_LEN], *use_uuid = NULL;
+	u8 addr[ETH_ALEN], *use_addr = NULL;
 
 	if (!wpa_s->wps_er)
 		return NULL;
 
-	if (uuid_str2bin(uuid, u))
+	if (uuid_str2bin(uuid, u) == 0)
+		use_uuid = u;
+	else if (hwaddr_aton(uuid, addr) == 0)
+		use_addr = addr;
+	else
 		return NULL;
 
-	ret = wps_er_nfc_config_token(wpa_s->wps_er, u);
+	ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
 	if (ndef && ret) {
 		struct wpabuf *tmp;
 		tmp = ndef_build_wifi(ret);
@@ -1854,9 +1896,52 @@
 
 #ifdef CONFIG_WPS_NFC
 
-struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
-					  int ndef)
+#ifdef CONFIG_WPS_ER
+static struct wpabuf *
+wpas_wps_network_config_token(struct wpa_supplicant *wpa_s, int ndef,
+			      struct wpa_ssid *ssid)
 {
+	struct wpabuf *ret;
+	struct wps_credential cred;
+
+	if (wpas_wps_network_to_cred(ssid, &cred) < 0)
+		return NULL;
+
+	ret = wps_er_config_token_from_cred(wpa_s->wps, &cred);
+
+	if (ndef && ret) {
+		struct wpabuf *tmp;
+		tmp = ndef_build_wifi(ret);
+		wpabuf_free(ret);
+		if (tmp == NULL)
+			return NULL;
+		ret = tmp;
+	}
+
+	return ret;
+}
+#endif /* CONFIG_WPS_ER */
+
+
+struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+					  int ndef, const char *id_str)
+{
+#ifdef CONFIG_WPS_ER
+	if (id_str) {
+		int id;
+		char *end = NULL;
+		struct wpa_ssid *ssid;
+
+		id = strtol(id_str, &end, 10);
+		if (end && *end)
+			return NULL;
+
+		ssid = wpa_config_get_network(wpa_s->conf, id);
+		if (ssid == NULL)
+			return NULL;
+		return wpas_wps_network_config_token(wpa_s, ndef, ssid);
+	}
+#endif /* CONFIG_WPS_ER */
 #ifdef CONFIG_AP
 	if (wpa_s->ap_iface)
 		return wpas_ap_wps_nfc_config_token(wpa_s, ndef);
@@ -1905,8 +1990,13 @@
 		return -1;
 	}
 	wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
-	if (wps->dh_ctx == NULL)
+	if (wps->dh_ctx == NULL) {
+		wpabuf_free(wps->dh_pubkey);
+		wps->dh_pubkey = NULL;
+		wpabuf_free(wps->dh_privkey);
+		wps->dh_privkey = NULL;
 		return -1;
+	}
 
 	wpa_snprintf_hex_uppercase(pw, sizeof(pw),
 				   wpabuf_head(wpa_s->conf->wps_nfc_dev_pw),
@@ -2033,19 +2123,26 @@
 {
 #ifdef CONFIG_WPS_ER
 	struct wpabuf *ret;
-	u8 u[UUID_LEN];
+	u8 u[UUID_LEN], *use_uuid = NULL;
+	u8 addr[ETH_ALEN], *use_addr = NULL;
 
 	if (!wpa_s->wps_er)
 		return NULL;
 
-	if (uuid == NULL || uuid_str2bin(uuid, u))
+	if (uuid == NULL)
+		return NULL;
+	if (uuid_str2bin(uuid, u) == 0)
+		use_uuid = u;
+	else if (hwaddr_aton(uuid, addr) == 0)
+		use_addr = addr;
+	else
 		return NULL;
 
 	/*
 	 * Handover Select carrier record for WPS uses the same format as
 	 * configuration token.
 	 */
-	ret = wps_er_nfc_config_token(wpa_s->wps_er, u);
+	ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
 	if (ndef && ret) {
 		struct wpabuf *tmp;
 		tmp = ndef_build_wifi(ret);
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index 8bb9546..2a212ca 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -63,7 +63,7 @@
 int wpas_wps_in_progress(struct wpa_supplicant *wpa_s);
 void wpas_wps_update_config(struct wpa_supplicant *wpa_s);
 struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
-					  int ndef);
+					  int ndef, const char *id_str);
 struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
 int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
 int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,