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/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 */