Cumulative patch from commits: a7f5271 and 7465640

a7f5271 Update pending connect radio work BSS pointer on scan update
7465640 Invoke connect work done for all the connection failure cases

Bug: 18312770

Change-Id: I5e59edaac24c30bbfdab2e38e8ea902300b0308d
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 7d01a5f..1de51e5 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -174,6 +174,31 @@
 }
 
 
+static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s,
+					   struct wpa_bss *old_bss,
+					   struct wpa_bss *new_bss)
+{
+	struct wpa_radio_work *work;
+	struct wpa_connect_work *cwork;
+
+	work = radio_work_pending(wpa_s, "sme-connect");
+	if (!work)
+		work = radio_work_pending(wpa_s, "connect");
+	if (!work)
+		return;
+
+	cwork = work->ctx;
+	if (cwork->bss != old_bss)
+		return;
+
+	wpa_printf(MSG_DEBUG,
+		   "Update BSS pointer for the pending connect radio work");
+	cwork->bss = new_bss;
+	if (!new_bss)
+		cwork->bss_removed = 1;
+}
+
+
 static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 			   const char *reason)
 {
@@ -190,6 +215,7 @@
 			}
 		}
 	}
+	wpa_bss_update_pending_connect(wpa_s, bss, NULL);
 	dl_list_del(&bss->list);
 	dl_list_del(&bss->list_id);
 	wpa_s->num_bss--;
@@ -543,6 +569,7 @@
 			}
 			if (wpa_s->current_bss == bss)
 				wpa_s->current_bss = nbss;
+			wpa_bss_update_pending_connect(wpa_s, bss, nbss);
 			bss = nbss;
 			os_memcpy(bss + 1, res + 1,
 				  res->ie_len + res->beacon_ie_len);
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 36b4f87..e616319 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -487,7 +487,8 @@
 
 	wpa_s->connect_work = work;
 
-	if (!wpas_valid_bss_ssid(wpa_s, cwork->bss, cwork->ssid)) {
+	if (cwork->bss_removed ||
+	    !wpas_valid_bss_ssid(wpa_s, cwork->bss, cwork->ssid)) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "SME: BSS/SSID entry for authentication not valid anymore - drop connection attempt");
 		wpas_connect_work_done(wpa_s);
 		return;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 397d2f6..eef3d21 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1584,7 +1584,7 @@
 
 	wpa_s->connect_work = work;
 
-	if (!wpas_valid_bss_ssid(wpa_s, bss, ssid)) {
+	if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid)) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
 		wpas_connect_work_done(wpa_s);
 		return;
@@ -1621,6 +1621,7 @@
 		   (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
 		/* Use ap_scan==1 style network selection to find the network
 		 */
+		wpas_connect_work_done(wpa_s);
 		wpa_s->scan_req = MANUAL_SCAN_REQ;
 		wpa_s->reassociate = 1;
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -1671,6 +1672,7 @@
 					      wpa_ie, &wpa_ie_len)) {
 			wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
 				"key management and encryption suites");
+			wpas_connect_work_done(wpa_s);
 			return;
 		}
 	} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
@@ -1690,6 +1692,7 @@
 			wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
 				"key management and encryption suites (no "
 				"scan results)");
+			wpas_connect_work_done(wpa_s);
 			return;
 		}
 #ifdef CONFIG_WPS
@@ -1959,8 +1962,10 @@
 				   "Assoc conflicting freq found (%d != %d)",
 				   freq, params.freq.freq);
 			if (wpas_p2p_handle_frequency_conflicts(
-				    wpa_s, params.freq.freq, ssid) < 0)
+				    wpa_s, params.freq.freq, ssid) < 0) {
+				wpas_connect_work_done(wpa_s);
 				return;
+			}
 		}
 	}
 #endif /* CONFIG_P2P */
@@ -3512,17 +3517,18 @@
 }
 
 
-int radio_work_pending(struct wpa_supplicant *wpa_s, const char *type)
+struct wpa_radio_work *
+radio_work_pending(struct wpa_supplicant *wpa_s, const char *type)
 {
 	struct wpa_radio_work *work;
 	struct wpa_radio *radio = wpa_s->radio;
 
 	dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
 		if (work->wpa_s == wpa_s && os_strcmp(work->type, type) == 0)
-			return 1;
+			return work;
 	}
 
-	return 0;
+	return NULL;
 }
 
 
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index cbe3e49..ae9dddd 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -320,10 +320,12 @@
 void radio_remove_works(struct wpa_supplicant *wpa_s,
 			const char *type, int remove_all);
 void radio_work_check_next(struct wpa_supplicant *wpa_s);
-int radio_work_pending(struct wpa_supplicant *wpa_s, const char *type);
+struct wpa_radio_work *
+radio_work_pending(struct wpa_supplicant *wpa_s, const char *type);
 
 struct wpa_connect_work {
 	unsigned int sme:1;
+	unsigned int bss_removed:1;
 	struct wpa_bss *bss;
 	struct wpa_ssid *ssid;
 };