Cumulative patch from commit f3ff948753ebe5643b5c2d16546a4d16e2c9d20a

f3ff948 P2P: Add NFC_HANDOVER commands to p2p_redir list
efd11c0 Add reassociate command to dbus doxygen
481e66b Fix reassociate dbus method
2150c33 wpa_cli: Fix wrong comparison in wpa_cli_cmd_interface
83c4cb5 nl80211: Handle multiple interface combinations for P2P
0133591 HS 2.0 SPP server: Fix aaa_trust_root_cert_url example to use DER
0e0e1e5 P2P: Add retry mechanism for GO Negotiation Confirmation
8235f89 P2P: Mark the scan in p2p_in_invitation as p2p_probe
9392c9b nl80211: Use LEAVE_IBSS with driver-based-SME
38ce8e2 Android: Add qca-vendor.h to be exported

Change-Id: I34771c58e2de5e0a3133326d4b3171341ac07b17
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hs20/server/sql-example.txt b/hs20/server/sql-example.txt
index a25e2cd..20dcf2f 100644
--- a/hs20/server/sql-example.txt
+++ b/hs20/server/sql-example.txt
@@ -3,7 +3,7 @@
 INSERT INTO osu_config(realm,field,value) VALUES('example.com','spp_http_auth_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com');
 INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/spp-root-ca.der');
 INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647');
-INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/aaa-root-ca.pem');
+INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/aaa-root-ca.der');
 INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647');
 INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_account','free');
 INSERT INTO osu_config(realm,field,value) VALUES('example.com','policy_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com');
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 27b4c48..e531e22 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -3444,10 +3444,12 @@
 	}
 
 	if (combination_has_p2p && combination_has_mgd) {
-		info->p2p_concurrent = 1;
-		info->num_multichan_concurrent =
+		unsigned int num_channels =
 			nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]);
-		return 1;
+
+		info->p2p_concurrent = 1;
+		if (info->num_multichan_concurrent < num_channels)
+			info->num_multichan_concurrent = num_channels;
 	}
 
 	return 0;
@@ -5876,13 +5878,16 @@
 					     const u8 *addr, int reason_code)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
+		nl80211_mark_disconnected(drv);
+		return nl80211_leave_ibss(drv);
+	}
 	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
 		return wpa_driver_nl80211_disconnect(drv, reason_code);
 	wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
 		   __func__, MAC2STR(addr), reason_code);
 	nl80211_mark_disconnected(drv);
-	if (drv->nlmode == NL80211_IFTYPE_ADHOC)
-		return nl80211_leave_ibss(drv);
 	return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
 				       reason_code, 0);
 }
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index ea16761..bcc7e64 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -218,6 +218,8 @@
 	os_memset(&res, 0, sizeof(res));
 	res.status = status;
 	if (peer) {
+		wpabuf_free(peer->go_neg_conf);
+		peer->go_neg_conf = NULL;
 		os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr,
 			  ETH_ALEN);
 		os_memcpy(res.peer_interface_addr, peer->intended_addr,
@@ -802,6 +804,7 @@
 	}
 
 	wpabuf_free(dev->info.wfd_subelems);
+	wpabuf_free(dev->go_neg_conf);
 
 	os_free(dev);
 }
@@ -1611,6 +1614,8 @@
 	peer->go_neg_req_sent = 0;
 	peer->wps_method = WPS_NOT_READY;
 	peer->oob_pw_id = 0;
+	wpabuf_free(peer->go_neg_conf);
+	peer->go_neg_conf = NULL;
 
 	p2p_set_state(p2p, P2P_PROVISIONING);
 	p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
@@ -2952,13 +2957,44 @@
 	struct p2p_device *dev;
 
 	p2p_dbg(p2p, "GO Negotiation Confirm TX callback: result=%d", result);
-	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 	if (result == P2P_SEND_ACTION_FAILED) {
+		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 		p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
 		return;
 	}
+
+	dev = p2p->go_neg_peer;
+
 	if (result == P2P_SEND_ACTION_NO_ACK) {
 		/*
+		 * Retry GO Negotiation Confirmation
+		 * P2P_GO_NEG_CNF_MAX_RETRY_COUNT times if we did not receive
+		 * ACK for confirmation.
+		 */
+		if (dev && dev->go_neg_conf &&
+		    dev->go_neg_conf_sent <= P2P_GO_NEG_CNF_MAX_RETRY_COUNT) {
+			p2p_dbg(p2p, "GO Negotiation Confirm retry %d",
+				dev->go_neg_conf_sent);
+			p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
+			if (p2p_send_action(p2p, dev->go_neg_conf_freq,
+					    dev->info.p2p_device_addr,
+					    p2p->cfg->dev_addr,
+					    dev->info.p2p_device_addr,
+					    wpabuf_head(dev->go_neg_conf),
+					    wpabuf_len(dev->go_neg_conf), 0) >=
+			    0) {
+				dev->go_neg_conf_sent++;
+				return;
+			}
+			p2p_dbg(p2p, "Failed to re-send Action frame");
+
+			/*
+			 * Continue with the assumption that the first attempt
+			 * went through and just the ACK frame was lost.
+			 */
+		}
+
+		/*
 		 * It looks like the TX status for GO Negotiation Confirm is
 		 * often showing failure even when the peer has actually
 		 * received the frame. Since the peer may change channels
@@ -2971,7 +3007,8 @@
 		p2p_dbg(p2p, "Assume GO Negotiation Confirm TX was actually received by the peer even though Ack was not reported");
 	}
 
-	dev = p2p->go_neg_peer;
+	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+
 	if (dev == NULL)
 		return;
 
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index a32cfac..ac93902 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -896,7 +896,6 @@
 			     const u8 *data, size_t len, int rx_freq)
 {
 	struct p2p_device *dev;
-	struct wpabuf *conf;
 	int go = -1;
 	struct p2p_message msg;
 	u8 status = P2P_SC_SUCCESS;
@@ -1101,10 +1100,13 @@
 	os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
 
 fail:
-	conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token, status,
-				     msg.operating_channel, go);
+	/* Store GO Negotiation Confirmation to allow retransmission */
+	wpabuf_free(dev->go_neg_conf);
+	dev->go_neg_conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token,
+						 status, msg.operating_channel,
+						 go);
 	p2p_parse_free(&msg);
-	if (conf == NULL)
+	if (dev->go_neg_conf == NULL)
 		return;
 	p2p_dbg(p2p, "Sending GO Negotiation Confirm");
 	if (status == P2P_SC_SUCCESS) {
@@ -1116,13 +1118,18 @@
 		freq = rx_freq;
 	else
 		freq = dev->listen_freq;
+
+	dev->go_neg_conf_freq = freq;
+	dev->go_neg_conf_sent = 0;
+
 	if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
-			    wpabuf_head(conf), wpabuf_len(conf), 200) < 0) {
+			    wpabuf_head(dev->go_neg_conf),
+			    wpabuf_len(dev->go_neg_conf), 200) < 0) {
 		p2p_dbg(p2p, "Failed to send Action frame");
 		p2p_go_neg_failed(p2p, dev, -1);
 		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
-	}
-	wpabuf_free(conf);
+	} else
+		dev->go_neg_conf_sent++;
 	if (status != P2P_SC_SUCCESS) {
 		p2p_dbg(p2p, "GO Negotiation failed");
 		p2p_go_neg_failed(p2p, dev, status);
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 8c225ec..44b66c4 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -12,6 +12,8 @@
 #include "utils/list.h"
 #include "p2p.h"
 
+#define P2P_GO_NEG_CNF_MAX_RETRY_COUNT 1
+
 enum p2p_role_indication;
 
 enum p2p_go_state {
@@ -108,6 +110,22 @@
 
 	u8 go_timeout;
 	u8 client_timeout;
+
+	/**
+	 * go_neg_conf_sent - Number of GO Negotiation Confirmation retries
+	 */
+	u8 go_neg_conf_sent;
+
+	/**
+	 * freq - Frquency on which the GO Negotiation Confirmation is sent
+	 */
+	int go_neg_conf_freq;
+
+	/**
+	 * go_neg_conf - GO Negotiation Confirmation frame
+	 */
+	struct wpabuf *go_neg_conf;
+
 	int sd_pending_bcast_queries;
 };
 
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index a60a26a..c8fe1c2 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -1617,4 +1617,5 @@
 LOCAL_SHARED_LIBRARIES := libcutils liblog
 LOCAL_COPY_HEADERS_TO := libwpa_client
 LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h
+LOCAL_COPY_HEADERS += src/common/qca-vendor.h
 include $(BUILD_SHARED_LIBRARY)
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index f50154e..01be089 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -6843,6 +6843,9 @@
 		"P2P_PRESENCE_REQ ",
 		"P2P_EXT_LISTEN ",
 		"P2P_REMOVE_CLIENT ",
+		"NFC_GET_HANDOVER_SEL ",
+		"NFC_GET_HANDOVER_REQ ",
+		"NFC_REPORT_HANDOVER ",
 		NULL
 	};
 	int found = 0;
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 61c480a..7aee923 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -91,6 +91,8 @@
 
 #define WPAS_DBUS_ERROR_IFACE_EXISTS \
 	WPAS_DBUS_NEW_INTERFACE ".InterfaceExists"
+#define WPAS_DBUS_ERROR_IFACE_DISABLED            \
+	WPAS_DBUS_NEW_INTERFACE ".InterfaceDisabled"
 #define WPAS_DBUS_ERROR_IFACE_UNKNOWN \
 	WPAS_DBUS_NEW_INTERFACE ".InterfaceUnknown"
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 5466d16..ffa59b2 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1465,10 +1465,10 @@
 
 
 /**
- * wpas_dbus_handler_reassociate - Reassociate to current AP
+ * wpas_dbus_handler_reassociate - Reassociate
  * @message: Pointer to incoming dbus message
  * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NotConnected DBus error message if not connected
+ * Returns: InterfaceDisabled DBus error message if disabled
  * or NULL otherwise.
  *
  * Handler function for "Reassociate" method call of network interface.
@@ -1476,13 +1476,13 @@
 DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
 					    struct wpa_supplicant *wpa_s)
 {
-	if (wpa_s->current_ssid != NULL) {
+	if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
 		wpas_request_connection(wpa_s);
 		return NULL;
 	}
 
-	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
-				      "This interface is not connected");
+	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED,
+				      "This interface is disabled");
 }
 
 
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 1d4e6e5..bc0daeb 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -870,7 +870,7 @@
 	}
 
 #ifdef CONFIG_P2P
-	if (wpa_s->p2p_in_provisioning ||
+	if (wpa_s->p2p_in_provisioning || wpa_s->p2p_in_invitation ||
 	    (wpa_s->show_group_started && wpa_s->go_params)) {
 		/*
 		 * The interface may not yet be in P2P mode, so we have to
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 28e186e..77c5295 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1552,7 +1552,7 @@
 	os_free(ctrl_ifname);
 	ctrl_ifname = os_strdup(argv[0]);
 
-	if (wpa_cli_open_connection(ctrl_ifname, 1)) {
+	if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
 		printf("Connected to interface '%s.\n", ctrl_ifname);
 	} else {
 		printf("Could not connect to interface '%s' - re-trying\n",