Cumulative patch from commit cf28c66bcb8883e6be921d6406a534e4a5b45b96

cf28c66 HS 2.0: Extend ANQP_GET to accept Hotspot 2.0 subtypes
163f801 nl80211: Indicate HS 2.0 OSEN AKM in connect/associate command
c201f93 WPS: Enable WSC 2.0 support unconditionally
91364b7 P2P: Set a timeout for a persistent reinvoke on a P2P Client
41d5ce9 P2P: Optimize scan for GO during persistent group invocation
4d1e38b ACS: Fix number of error path issues

Change-Id: I31a51d3dba055d1a906516bb08894effec327da9
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index b8690f5..a60a26a 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -617,10 +617,6 @@
 endif
 
 ifdef CONFIG_WPS
-ifdef CONFIG_WPS2
-L_CFLAGS += -DCONFIG_WPS2
-endif
-
 # EAP-WSC
 L_CFLAGS += -DCONFIG_WPS -DEAP_WSC
 OBJS += wps_supplicant.c
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index ce98068..19dae70 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -622,10 +622,6 @@
 endif
 
 ifdef CONFIG_WPS
-ifdef CONFIG_WPS2
-CFLAGS += -DCONFIG_WPS2
-endif
-
 # EAP-WSC
 CFLAGS += -DCONFIG_WPS -DEAP_WSC
 OBJS += wps_supplicant.o
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index 18b0cca..a33b0f0 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -60,7 +60,6 @@
 
 CONFIG_DRIVER_NL80211=y
 CONFIG_WPS=y
-CONFIG_WPS2=y
 
 If you want to enable WPS external registrar (ER) functionality, you
 will also need to add following line:
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 7c80528..ffa2f01 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -141,8 +141,6 @@
 
 # Wi-Fi Protected Setup (WPS)
 CONFIG_WPS=y
-# Enable WSC 2.0 support
-CONFIG_WPS2=y
 # Enable WPS external registrar functionality
 CONFIG_WPS_ER=y
 # Disable credentials for an open network by default when acting as a WPS
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 12cb4b6..e7d59de 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -311,12 +311,10 @@
 	if (bss->ssid.security_policy != SECURITY_WPA_PSK &&
 	    bss->ssid.security_policy != SECURITY_PLAINTEXT)
 		goto no_wps;
-#ifdef CONFIG_WPS2
 	if (bss->ssid.security_policy == SECURITY_WPA_PSK &&
 	    (!(bss->rsn_pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
 		goto no_wps; /* WPS2 does not allow WPA/TKIP-only
 			      * configuration */
-#endif /* CONFIG_WPS2 */
 	bss->eap_server = 1;
 
 	if (!ssid->ignore_broadcast_ssid)
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 704caa1..925ece1 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2163,10 +2163,8 @@
 		return pos;
 	if (wps_is_selected_pbc_registrar(wps_ie))
 		txt = "[WPS-PBC]";
-#ifdef CONFIG_WPS2
 	else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
 		txt = "[WPS-AUTH]";
-#endif /* CONFIG_WPS2 */
 	else if (wps_is_selected_pin_registrar(wps_ie))
 		txt = "[WPS-PIN]";
 	else
@@ -4947,15 +4945,27 @@
 #define MAX_ANQP_INFO_ID 100
 	u16 id[MAX_ANQP_INFO_ID];
 	size_t num_id = 0;
+	u32 subtypes = 0;
 
 	used = hwaddr_aton2(dst, dst_addr);
 	if (used < 0)
 		return -1;
 	pos = dst + used;
 	while (num_id < MAX_ANQP_INFO_ID) {
-		id[num_id] = atoi(pos);
-		if (id[num_id])
-			num_id++;
+		if (os_strncmp(pos, "hs20:", 5) == 0) {
+#ifdef CONFIG_HS20
+			int num = atoi(pos + 5);
+			if (num <= 0 || num > 31)
+				return -1;
+			subtypes |= BIT(num);
+#else /* CONFIG_HS20 */
+			return -1;
+#endif /* CONFIG_HS20 */
+		} else {
+			id[num_id] = atoi(pos);
+			if (id[num_id])
+				num_id++;
+		}
 		pos = os_strchr(pos + 1, ',');
 		if (pos == NULL)
 			break;
@@ -4965,7 +4975,7 @@
 	if (num_id == 0)
 		return -1;
 
-	return anqp_send_req(wpa_s, dst_addr, id, num_id);
+	return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes);
 }
 
 
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 91eea35..d194eb8 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -152,8 +152,6 @@
 
 # Wi-Fi Protected Setup (WPS)
 #CONFIG_WPS=y
-# Enable WSC 2.0 support
-#CONFIG_WPS2=y
 # Enable WPS external registrar functionality
 #CONFIG_WPS_ER=y
 # Disable credentials for an open network by default when acting as a WPS
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index f8bb356..ce11e98 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1430,7 +1430,8 @@
 				return 0;
 
 			if (wpa_s->p2p_in_provisioning ||
-			    wpa_s->show_group_started) {
+			    wpa_s->show_group_started ||
+			    wpa_s->p2p_in_invitation) {
 				/*
 				 * Use shorter wait during P2P Provisioning
 				 * state and during P2P join-a-group operation
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index b342d5d..c242c33 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -121,15 +121,13 @@
 }
 
 
-struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
-				    size_t payload_len)
+void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
+		       struct wpabuf *buf)
 {
-	struct wpabuf *buf;
 	u8 *len_pos;
 
-	buf = gas_anqp_build_initial_req(0, 100 + payload_len);
 	if (buf == NULL)
-		return NULL;
+		return;
 
 	len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
 	wpabuf_put_be24(buf, OUI_WFA);
@@ -156,6 +154,19 @@
 	gas_anqp_set_element_len(buf, len_pos);
 
 	gas_anqp_set_len(buf);
+}
+
+
+struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+				    size_t payload_len)
+{
+	struct wpabuf *buf;
+
+	buf = gas_anqp_build_initial_req(0, 100 + payload_len);
+	if (buf == NULL)
+		return NULL;
+
+	hs20_put_anqp_req(stypes, payload, payload_len, buf);
 
 	return buf;
 }
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index 88e5062..f6c4d44 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -14,6 +14,8 @@
 		       const u8 *payload, size_t payload_len);
 struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
 				    size_t payload_len);
+void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
+		       struct wpabuf *buf);
 void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
 				  const u8 *sa, const u8 *data, size_t slen);
 int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index e3ad931..71163c3 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -2531,9 +2531,10 @@
 
 
 int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
-		  u16 info_ids[], size_t num_ids)
+		  u16 info_ids[], size_t num_ids, u32 subtypes)
 {
 	struct wpabuf *buf;
+	struct wpabuf *hs20_buf = NULL;
 	int ret = 0;
 	int freq;
 	struct wpa_bss *bss;
@@ -2551,7 +2552,17 @@
 	wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
 		   MAC2STR(dst), (unsigned int) num_ids);
 
-	buf = anqp_build_req(info_ids, num_ids, NULL);
+#ifdef CONFIG_HS20
+	if (subtypes != 0) {
+		hs20_buf = wpabuf_alloc(100);
+		if (hs20_buf == NULL)
+			return -1;
+		hs20_put_anqp_req(subtypes, NULL, 0, hs20_buf);
+	}
+#endif /* CONFIG_HS20 */
+
+	buf = anqp_build_req(info_ids, num_ids, hs20_buf);
+	wpabuf_free(hs20_buf);
 	if (buf == NULL)
 		return -1;
 
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index bb0ceb8..38ef745 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -12,7 +12,7 @@
 enum gas_query_result;
 
 int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
-		  u16 info_ids[], size_t num_ids);
+		  u16 info_ids[], size_t num_ids, u32 subtypes);
 void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
 		  enum gas_query_result result,
 		  const struct wpabuf *adv_proto,
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 6f9f217..5e36a67 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -57,7 +57,8 @@
 #ifndef P2P_MAX_INITIAL_CONN_WAIT
 /*
  * How many seconds to wait for initial 4-way handshake to get completed after
- * WPS provisioning step.
+ * WPS provisioning step or after the re-invocation of a persistent group on a
+ * P2P Client.
  */
 #define P2P_MAX_INITIAL_CONN_WAIT 10
 #endif /* P2P_MAX_INITIAL_CONN_WAIT */
@@ -501,6 +502,8 @@
 		wpa_s->p2p_in_provisioning = 0;
 	}
 
+	wpa_s->p2p_in_invitation = 0;
+
 	/*
 	 * Make sure wait for the first client does not remain active after the
 	 * group has been removed.
@@ -3070,7 +3073,7 @@
 		if (s) {
 			int go = s->mode == WPAS_MODE_P2P_GO;
 			wpas_p2p_group_add_persistent(
-				wpa_s, s, go, 0, go ? op_freq : 0, 0, 0, NULL,
+				wpa_s, s, go, 0, op_freq, 0, 0, NULL,
 				go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0);
 		} else if (bssid) {
 			wpa_s->user_initiated_pd = 0;
@@ -3177,10 +3180,12 @@
 
 static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
 				   const struct p2p_channels *channels,
-				   const u8 *peer, int neg_freq)
+				   const u8 *peer, int neg_freq,
+				   int peer_oper_freq)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_ssid *ssid;
+	int freq;
 
 	if (bssid) {
 		wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
@@ -3236,10 +3241,21 @@
 		"starting persistent group");
 	os_sleep(0, 50000);
 
+	if (neg_freq > 0 && ssid->mode == WPAS_MODE_P2P_GO &&
+	    freq_included(channels, neg_freq))
+		freq = neg_freq;
+	else if (peer_oper_freq > 0 && ssid->mode != WPAS_MODE_P2P_GO &&
+		 freq_included(channels, peer_oper_freq))
+		freq = peer_oper_freq;
+	else
+		freq = 0;
+
+	wpa_printf(MSG_DEBUG, "P2P: Persistent group invitation success - op_freq=%d MHz SSID=%s",
+		   freq, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
 	wpas_p2p_group_add_persistent(wpa_s, ssid,
 				      ssid->mode == WPAS_MODE_P2P_GO,
 				      wpa_s->p2p_persistent_go_freq,
-				      neg_freq,
+				      freq,
 				      wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
 				      channels,
 				      ssid->mode == WPAS_MODE_P2P_GO ?
@@ -5150,7 +5166,8 @@
 
 
 static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
-				 struct wpa_ssid *params, int addr_allocated)
+				 struct wpa_ssid *params, int addr_allocated,
+				 int freq)
 {
 	struct wpa_ssid *ssid;
 
@@ -5187,7 +5204,14 @@
 		ssid->passphrase = os_strdup(params->passphrase);
 
 	wpa_s->show_group_started = 1;
+	wpa_s->p2p_in_invitation = 1;
+	wpa_s->p2p_invite_go_freq = freq;
 
+	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
+			     NULL);
+	eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
+			       wpas_p2p_group_formation_timeout,
+			       wpa_s->parent, NULL);
 	wpa_supplicant_select_network(wpa_s, ssid);
 
 	return 0;
@@ -5221,12 +5245,6 @@
 
 	wpa_s->p2p_fallback_to_go_neg = 0;
 
-	if (ssid->mode == WPAS_MODE_INFRA)
-		return wpas_start_p2p_client(wpa_s, ssid, addr_allocated);
-
-	if (ssid->mode != WPAS_MODE_P2P_GO)
-		return -1;
-
 	if (force_freq > 0) {
 		freq = wpas_p2p_select_go_freq(wpa_s, force_freq);
 		if (freq < 0)
@@ -5237,6 +5255,12 @@
 			freq = 0;
 	}
 
+	if (ssid->mode == WPAS_MODE_INFRA)
+		return wpas_start_p2p_client(wpa_s, ssid, addr_allocated, freq);
+
+	if (ssid->mode != WPAS_MODE_P2P_GO)
+		return -1;
+
 	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, channels))
 		return -1;
 
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 48e94b6..1d4e6e5 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -326,6 +326,32 @@
 		}
 		wpa_s->p2p_in_provisioning++;
 	}
+
+	if (params->freqs == NULL && wpa_s->p2p_in_invitation) {
+		/*
+		 * Optimize scan based on GO information during persistent
+		 * group reinvocation
+		 */
+		if (wpa_s->p2p_in_invitation < 5 ||
+		    wpa_s->p2p_invite_go_freq > 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO preferred frequency %d MHz during invitation",
+				wpa_s->p2p_invite_go_freq);
+			params->freqs = os_zalloc(2 * sizeof(int));
+			if (params->freqs)
+				params->freqs[0] = wpa_s->p2p_invite_go_freq;
+		}
+		wpa_s->p2p_in_invitation++;
+		if (wpa_s->p2p_in_invitation > 20) {
+			/*
+			 * This should not really happen since the variable is
+			 * cleared on group removal, but if it does happen, make
+			 * sure we do not get stuck in special invitation scan
+			 * mode.
+			 */
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Clear p2p_in_invitation");
+			wpa_s->p2p_in_invitation = 0;
+		}
+	}
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_WPS
@@ -639,6 +665,19 @@
 		params.num_ssids = 1;
 		goto ssid_list_set;
 	}
+
+	if (wpa_s->p2p_in_invitation) {
+		if (wpa_s->current_ssid) {
+			wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during invitation");
+			params.ssids[0].ssid = wpa_s->current_ssid->ssid;
+			params.ssids[0].ssid_len =
+				wpa_s->current_ssid->ssid_len;
+			params.num_ssids = 1;
+		} else {
+			wpa_printf(MSG_DEBUG, "P2P: No specific SSID known for scan during invitation");
+		}
+		goto ssid_list_set;
+	}
 #endif /* CONFIG_P2P */
 
 	/* Find the starting point from which to continue scanning */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index f01844e..a860afb 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -711,6 +711,8 @@
 	params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
 	params.pairwise_suite = wpa_s->pairwise_cipher;
 	params.group_suite = wpa_s->group_cipher;
+	params.key_mgmt_suite = wpa_s->key_mgmt;
+	params.wpa_proto = wpa_s->wpa_proto;
 #ifdef CONFIG_HT_OVERRIDES
 	os_memset(&htcaps, 0, sizeof(htcaps));
 	os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 8a33286..b5e137c 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -687,6 +687,8 @@
 	u8 p2p_auth_invite[ETH_ALEN];
 	int p2p_sd_over_ctrl_iface;
 	int p2p_in_provisioning;
+	int p2p_in_invitation;
+	int p2p_invite_go_freq;
 	int pending_invite_ssid_id;
 	int show_group_started;
 	u8 go_dev_addr[ETH_ALEN];
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index c87fa3d..b086c47 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1301,7 +1301,6 @@
 
 static u16 wps_fix_config_methods(u16 config_methods)
 {
-#ifdef CONFIG_WPS2
 	if ((config_methods &
 	     (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY |
 	      WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) {
@@ -1316,7 +1315,6 @@
 			   "virtual_push_button for WPS 2.0 compliance");
 		config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
 	}
-#endif /* CONFIG_WPS2 */
 
 	return config_methods;
 }