Accumulative patch from commit b618a469c42120e984ab1c85ed6058504d1fca78

  Author: Jouni Malinen <jouni@qca.qualcomm.com>
  Date:   Sat Feb 16 19:54:09 2013 +0200
    Interworking: Select highest priority cred if multiple matches

Interworking: Select highest priority cred if multiple matches
GAS server: Fix a regression in GAS server callback
hostapd: Fix Max SP Length derivation from QoS Info
nl80211: Configure STA Capabilities and Extended Capabilities
Synchronize with wireless-testing.git include/uapi/linux/nl80211.h
WPS: Fix build without CONFIG_WPS_NFC
WPS: Add support for NFC handover select generation with wpa_supplicant
WPS: Update NFC connection handover documentation
WPS: Add support for config token generation with wpa_supplicant
WPS: Allow password token to be written with nfcpy
WPS: Use pre-configured NFC password token instead of overriding it
TDLS: Pass peer's Capability and Ext Capability info during sta_add
TDLS: Pass peer's HT Capability and QOS information during sta_add
nl80211: Add debug prints for STA add/set operations
TDLS: Fix add/set STA operation
Synchronize with wireless-testing.git include/uapi/linux/nl80211.h
WPS: Allow Device Password to be changed from M1 to M2
WPS: Fix wps_reg nfc-pw option
TDLS: Tear down peers when disconnecting from the AP
P2P: Do not use old scan result data for peer discovery
Use more accurate timestamps for scan results
P2P: Postpone P2P-DEVICE-FOUND if config_methods not known
P2P: Do not allow peer update to clear config_methods
WPS: Report NFC connection handover completion differently
P2P: Avoid concurrent scans during all steps of group formation
P2P: Cancel group formation timeout on group removal (on client)
WPS: Change listen time to match nfcpy default (250 ms)
WPS: Report only the carrier record from NFC to wpa_supplicant
WPS: Fetch only the carrier record from wpa_supplicant for NFC
WPS: Update nfcpy script to support AP mode NFC connection handover
WPS: Add command for fetching carrier record for NFC handover
WPS: Clean up debug prints with nfcpy
WPS: Remove 0.5 sec extra wait from NFC handover with nfcpy
WPS: Use alternating poll/listen for NFC peer discovery with nfcpy
WPS: Configure logging to show nfcpy log message
WPS: Add an example python script for NFC operations with hostapd
hostapd: Do not change HT40 capability due to OBSS scan
dbus: Add missing signal description for WPS (7)
EAP peer: Add Session-Id derivation to more EAP methods
EAP peer: Add Session-Id derivation
EAP-IKEV2 server: Fix invalid memory freeing operation
eap_proxy: Add a dummy implementation for compilation testing
eap_proxy: Add mechanism for allowing EAP methods to be offloaded
Android: Allow setgroups to be overridden from build configuration
P2P: Send p2p_stop_find event on failure to start pending p2p_find
P2P: Fix GO Probe Response IEs when Wi-Fi Display is enabled
Capability matching for 60 GHz band
nl80211: Add ctrl_iface message for AP mode connection rejection
P2P: Allow local configuration to use 5 GHz band 40 MHz channels
Fix BSS RANGE command for no exact id match cases

Change-Id: Iac9284bba31db40911aecc3adf2843c9b1576db1
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/wps/ndef.c b/src/wps/ndef.c
index a48a2d7..96685d2 100644
--- a/src/wps/ndef.c
+++ b/src/wps/ndef.c
@@ -170,10 +170,30 @@
 }
 
 
+struct wpabuf * ndef_build_wifi_hc(int begin)
+{
+	struct wpabuf *hc, *carrier;
+
+	carrier = wpabuf_alloc(2 + os_strlen(wifi_handover_type));
+	if (carrier == NULL)
+		return NULL;
+	wpabuf_put_u8(carrier, 0x02); /* Carrier Type Format */
+	wpabuf_put_u8(carrier, os_strlen(wifi_handover_type));
+	wpabuf_put_str(carrier, wifi_handover_type);
+
+	hc = ndef_build_record((begin ? FLAG_MESSAGE_BEGIN : 0) |
+			       FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "Hc", 2,
+			       "0", 1, carrier);
+	wpabuf_free(carrier);
+
+	return hc;
+}
+
+
 struct wpabuf * ndef_build_wifi_hr(void)
 {
 	struct wpabuf *rn, *cr, *ac_payload, *ac, *hr_payload, *hr;
-	struct wpabuf *carrier, *hc;
+	struct wpabuf *hc;
 
 	rn = wpabuf_alloc(2);
 	if (rn == NULL)
@@ -224,18 +244,7 @@
 	if (hr == NULL)
 		return NULL;
 
-	carrier = wpabuf_alloc(2 + os_strlen(wifi_handover_type));
-	if (carrier == NULL) {
-		wpabuf_free(hr);
-		return NULL;
-	}
-	wpabuf_put_u8(carrier, 0x02); /* Carrier Type Format */
-	wpabuf_put_u8(carrier, os_strlen(wifi_handover_type));
-	wpabuf_put_str(carrier, wifi_handover_type);
-
-	hc = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "Hc", 2,
-			       "0", 1, carrier);
-	wpabuf_free(carrier);
+	hc = ndef_build_wifi_hc(0);
 	if (hc == NULL) {
 		wpabuf_free(hr);
 		return NULL;
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 2575705..ff4b20d 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -53,12 +53,18 @@
 		}
 		os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
 		data->dev_password_len = cfg->pin_len;
+		wpa_hexdump_key(MSG_DEBUG, "WPS: AP PIN dev_password",
+				data->dev_password, data->dev_password_len);
 	}
 
 #ifdef CONFIG_WPS_NFC
 	if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) {
+		/* Keep AP PIN as alternative Device Password */
+		data->alt_dev_pw_id = data->dev_pw_id;
+		data->alt_dev_password = data->dev_password;
+		data->alt_dev_password_len = data->dev_password_len;
+
 		data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id;
-		os_free(data->dev_password);
 		data->dev_password =
 			os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw));
 		if (data->dev_password == NULL) {
@@ -69,6 +75,8 @@
 			  wpabuf_head(cfg->wps->ap_nfc_dev_pw),
 			  wpabuf_len(cfg->wps->ap_nfc_dev_pw));
 		data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw);
+		wpa_hexdump_key(MSG_DEBUG, "WPS: NFC dev_password",
+			    data->dev_password, data->dev_password_len);
 	}
 #endif /* CONFIG_WPS_NFC */
 
@@ -155,6 +163,7 @@
 	wpabuf_free(data->dh_pubkey_r);
 	wpabuf_free(data->last_msg);
 	os_free(data->dev_password);
+	os_free(data->alt_dev_password);
 	os_free(data->new_psk);
 	wps_device_data_free(&data->peer_dev);
 	os_free(data->new_ap_settings);
diff --git a/src/wps/wps.h b/src/wps/wps.h
index c6b7099..39fce56 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -810,6 +810,8 @@
 struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
 				       const struct wpabuf *pubkey,
 				       const struct wpabuf *dev_pw);
+struct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey,
+				    struct wpabuf *dev_pw);
 struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
 				  struct wpabuf **privkey,
 				  struct wpabuf **dev_pw);
@@ -817,6 +819,7 @@
 /* ndef.c */
 struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
 struct wpabuf * ndef_build_wifi(const struct wpabuf *buf);
+struct wpabuf * ndef_build_wifi_hc(int begin);
 struct wpabuf * ndef_build_wifi_hr(void);
 
 #ifdef CONFIG_WPS_STRICT
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 68d9f0a..0897b7b 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -562,11 +562,34 @@
 
 
 #ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey,
+				    struct wpabuf *dev_pw)
+{
+	struct wpabuf *ret;
+
+	if (pubkey == NULL || dev_pw == NULL)
+		return NULL;
+
+	ret = wps_build_nfc_pw_token(id, pubkey, dev_pw);
+	if (ndef && ret) {
+		struct wpabuf *tmp;
+		tmp = ndef_build_wifi(ret);
+		wpabuf_free(ret);
+		if (tmp == NULL)
+			return NULL;
+		ret = tmp;
+	}
+
+	return ret;
+}
+
+
 struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
 				  struct wpabuf **privkey,
 				  struct wpabuf **dev_pw)
 {
-	struct wpabuf *priv = NULL, *pub = NULL, *pw, *ret;
+	struct wpabuf *priv = NULL, *pub = NULL, *pw;
 	void *dh_ctx;
 	u16 val;
 
@@ -596,16 +619,7 @@
 	wpabuf_free(*dev_pw);
 	*dev_pw = pw;
 
-	ret = wps_build_nfc_pw_token(*id, *pubkey, *dev_pw);
-	if (ndef && ret) {
-		struct wpabuf *tmp;
-		tmp = ndef_build_wifi(ret);
-		wpabuf_free(ret);
-		if (tmp == NULL)
-			return NULL;
-		ret = tmp;
-	}
-
-	return ret;
+	return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw);
 }
+
 #endif /* CONFIG_WPS_NFC */
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 837b941..9c0cebb 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -837,6 +837,39 @@
 }
 
 
+static int wps_process_dev_pw_id(struct wps_data *wps, const u8 *dev_pw_id)
+{
+	u16 id;
+
+	if (dev_pw_id == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Device Password ID");
+		return -1;
+	}
+
+	id = WPA_GET_BE16(dev_pw_id);
+	if (wps->dev_pw_id == id) {
+		wpa_printf(MSG_DEBUG, "WPS: Device Password ID %u", id);
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password "
+		   "ID from %u to %u", wps->dev_pw_id, id);
+
+	if (wps->alt_dev_password && wps->alt_dev_pw_id == id) {
+		wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password");
+		os_free(wps->dev_password);
+		wps->dev_pw_id = wps->alt_dev_pw_id;
+		wps->dev_password = wps->alt_dev_password;
+		wps->dev_password_len = wps->alt_dev_password_len;
+		wps->alt_dev_password = NULL;
+		wps->alt_dev_password_len = 0;
+		return 0;
+	}
+
+	return -1;
+}
+
+
 static enum wps_process_res wps_process_m2(struct wps_data *wps,
 					   const struct wpabuf *msg,
 					   struct wps_parse_attr *attr)
@@ -852,7 +885,8 @@
 
 	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
 	    wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
-	    wps_process_uuid_r(wps, attr->uuid_r)) {
+	    wps_process_uuid_r(wps, attr->uuid_r) ||
+	    wps_process_dev_pw_id(wps, attr->dev_password_id)) {
 		wps->state = SEND_WSC_NACK;
 		return WPS_CONTINUE;
 	}
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index 8110894..6efc3bf 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -71,6 +71,9 @@
 	size_t dev_password_len;
 	u16 dev_pw_id;
 	int pbc;
+	u8 *alt_dev_password;
+	size_t alt_dev_password_len;
+	u16 alt_dev_pw_id;
 
 	/**
 	 * request_type - Request Type attribute from (Re)AssocReq
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 11e7e84..f01e3b3 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -1363,6 +1363,14 @@
 	} else {
 		pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e,
 					    &pin_len);
+		if (pin && wps->dev_pw_id >= 0x10) {
+			wpa_printf(MSG_DEBUG, "WPS: No match for OOB Device "
+				   "Password ID, but PIN found");
+			/*
+			 * See whether Enrollee is willing to use PIN instead.
+			 */
+			wps->dev_pw_id = DEV_PW_DEFAULT;
+		}
 	}
 	if (pin == NULL) {
 		wpa_printf(MSG_DEBUG, "WPS: No Device Password available for "