Accumulative patch from commit  cc03d0fef3bf5913f8e11b7e998c10bf36a3c07f

  Author: Amar Singhal <asinghal@qca.qualcomm.com>
  Date:   Wed Feb 6 00:31:34 2013 +0200
    Add "BSS LAST ..." command

 - Add "BSS LAST ..." command
 - HS 2.0: Fix IE buffer length for extra scan IEs
 - TDLS: Several fixes
 - P2P: Fix P2P-GROUP-STARTED event for p2p_connect-join
 - P2P: Fix Action frame processing if Interworking is enabled
 - wpa_supplicant: Fix access to the freed memory when removing all networks
 - Add driver for OpenBSD net80211 layer
 - Make wpas_select_network_from_last_scan() static
 - wpa_supplicant: Implement fast-associate on SelectNetwork
 - Update scan interval gracefully
 - eloop: Add a timer cancel that returns the remaining time
 - nl80211: Do not use void pointer for driver_ops used internally
 - hostapd: Fix crash when scan fails

Change-Id: I083747a0b1f7000730a9ab3ea80f3ee7e6247181
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 8c186bd..d3c87da 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -554,13 +554,12 @@
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
 		   MAC2STR(peer));
 
-	ret = wpa_tdls_reneg(wpa_s->wpa, peer);
-	if (ret) {
-		if (wpa_tdls_is_external_setup(wpa_s->wpa))
-			ret = wpa_tdls_start(wpa_s->wpa, peer);
-		else
-			ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
-	}
+	wpa_tdls_remove(wpa_s->wpa, peer);
+
+	if (wpa_tdls_is_external_setup(wpa_s->wpa))
+		ret = wpa_tdls_start(wpa_s->wpa, peer);
+	else
+		ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
 
 	return ret;
 }
@@ -2130,14 +2129,6 @@
 	/* cmd: "<network id>" or "all" */
 	if (os_strcmp(cmd, "all") == 0) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
-		ssid = wpa_s->conf->ssid;
-		while (ssid) {
-			struct wpa_ssid *remove_ssid = ssid;
-			id = ssid->id;
-			ssid = ssid->next;
-			wpas_notify_network_removed(wpa_s, remove_ssid);
-			wpa_config_remove_network(wpa_s->conf, id);
-		}
 		eapol_sm_invalidate_cached_session(wpa_s->eapol);
 		if (wpa_s->current_ssid) {
 #ifdef CONFIG_SME
@@ -2148,6 +2139,14 @@
 			wpa_supplicant_deauthenticate(
 				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 		}
+		ssid = wpa_s->conf->ssid;
+		while (ssid) {
+			struct wpa_ssid *remove_ssid = ssid;
+			id = ssid->id;
+			ssid = ssid->next;
+			wpas_notify_network_removed(wpa_s, remove_ssid);
+			wpa_config_remove_network(wpa_s->conf, id);
+		}
 		return 0;
 	}
 
@@ -3200,8 +3199,10 @@
 				}
 			}
 		}
-	} else if (os_strcmp(cmd, "FIRST") == 0)
+	} else if (os_strncmp(cmd, "FIRST", 5) == 0)
 		bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
+	else if (os_strncmp(cmd, "LAST", 4) == 0)
+		bss = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id);
 	else if (os_strncmp(cmd, "ID-", 3) == 0) {
 		i = atoi(cmd + 3);
 		bss = wpa_bss_get_id(wpa_s, i);
@@ -5161,13 +5162,13 @@
 		wpa_supplicant_cancel_scan(wpa_s);
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
-	} else if ((os_strcmp(buf, "SCAN") == 0) ||
-		   (os_strncmp(buf, "SCAN ", 5) == 0)) {
+	} else if (os_strcmp(buf, "SCAN") == 0 ||
+		   os_strncmp(buf, "SCAN ", 5) == 0) {
 		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
 			reply_len = -1;
 		else {
-			if ((os_strlen(buf) > 4) &&
-			    (os_strncasecmp(buf + 5, "TYPE=ONLY", 9) == 0))
+			if (os_strlen(buf) > 4 &&
+			    os_strncasecmp(buf + 5, "TYPE=ONLY", 9) == 0)
 				wpa_s->scan_res_handler = scan_only_handler;
 			if (!wpa_s->sched_scanning && !wpa_s->scanning &&
 			    ((wpa_s->wpa_state <= WPA_SCANNING) ||
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 2b62e6b..d1b58eb 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -44,6 +44,9 @@
 #include "interworking.h"
 
 
+static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s);
+
+
 static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
 			      struct wpa_ssid *ssid)
 {
@@ -1109,8 +1112,8 @@
 						   data ? &data->scan_info :
 						   NULL, 1);
 	if (scan_res == NULL) {
-		if ((wpa_s->conf->ap_scan == 2 || ap) ||
-		    (wpa_s->scan_res_handler == scan_only_handler))
+		if (wpa_s->conf->ap_scan == 2 || ap ||
+		    wpa_s->scan_res_handler == scan_only_handler)
 			return -1;
 		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try "
 			"scanning again");
@@ -1205,7 +1208,7 @@
 }
 
 
-int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s)
+static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_bss *selected;
 	struct wpa_ssid *ssid = NULL;
@@ -1348,6 +1351,26 @@
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 
 
+int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_NO_SCAN_PROCESSING
+	return -1;
+#else /* CONFIG_NO_SCAN_PROCESSING */
+	struct os_time now;
+
+	if (wpa_s->last_scan_res_used <= 0)
+		return -1;
+
+	os_get_time(&now);
+	if (now.sec - wpa_s->last_scan.sec > 5) {
+		wpa_printf(MSG_DEBUG, "Fast associate: Old scan results");
+		return -1;
+	}
+
+	return wpas_select_network_from_last_scan(wpa_s);
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+}
+
 #ifdef CONFIG_WNM
 
 static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx)
@@ -2178,10 +2201,14 @@
 		return;
 	switch (data->tdls.oper) {
 	case TDLS_REQUEST_SETUP:
-		wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
+		wpa_tdls_remove(wpa_s->wpa, data->tdls.peer);
+		if (wpa_tdls_is_external_setup(wpa_s->wpa))
+			wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
+		else
+			wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, data->tdls.peer);
 		break;
 	case TDLS_REQUEST_TEARDOWN:
-		wpa_tdls_send_teardown(wpa_s->wpa, data->tdls.peer,
+		wpa_tdls_teardown_link(wpa_s->wpa, data->tdls.peer,
 				       data->tdls.reason_code);
 		break;
 	}
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index b8a8bb2..e1f58a6 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -54,16 +54,8 @@
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
 
-	if (wpa_s->last_scan_res_used > 0) {
-		struct os_time now;
-		os_get_time(&now);
-		if (now.sec - wpa_s->last_scan.sec <= 5) {
-			wpa_printf(MSG_DEBUG, "Interworking: Old scan results "
-				   "are fresh - connect without new scan");
-			if (wpas_select_network_from_last_scan(wpa_s) >= 0)
-				return;
-		}
-	}
+	if (wpa_supplicant_fast_associate(wpa_s) >= 0)
+		return;
 
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
 }
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 523178f..3e02099 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -3580,10 +3580,18 @@
 		os_memcpy(group->p2p_pin, wpa_s->p2p_pin,
 			  sizeof(group->p2p_pin));
 		group->p2p_wps_method = wpa_s->p2p_wps_method;
+	} else {
+		/*
+		 * Need to mark the current interface for p2p_group_formation
+		 * when a separate group interface is not used. This is needed
+		 * to allow p2p_cancel stop a pending p2p_connect-join.
+		 * wpas_p2p_init_group_interface() addresses this for the case
+		 * where a separate group interface is used.
+		 */
+		wpa_s->global->p2p_group_formation = wpa_s;
 	}
 
 	group->p2p_in_provisioning = 1;
-	wpa_s->global->p2p_group_formation = wpa_s;
 	group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
 
 	os_memset(&res, 0, sizeof(res));
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 4b2b9fd..9b71400 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -749,7 +749,7 @@
 	extra_ie = wpa_supplicant_extra_ies(wpa_s);
 
 #ifdef CONFIG_HS20
-	if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 6) == 0)
+	if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0)
 		wpas_hs20_add_indication(extra_ie);
 #endif /* CONFIG_HS20 */
 
@@ -830,6 +830,27 @@
 }
 
 
+void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec)
+{
+	struct os_time remaining, new_int;
+	int cancelled;
+
+	cancelled = eloop_cancel_timeout_one(wpa_supplicant_scan, wpa_s, NULL,
+					     &remaining);
+
+	new_int.sec = sec;
+	new_int.usec = 0;
+	if (cancelled && os_time_before(&remaining, &new_int)) {
+		new_int.sec = remaining.sec;
+		new_int.usec = remaining.usec;
+	}
+
+	eloop_register_timeout(new_int.sec, new_int.usec, wpa_supplicant_scan,
+			       wpa_s, NULL);
+	wpa_s->scan_interval = sec;
+}
+
+
 /**
  * wpa_supplicant_req_scan - Schedule a scan for neighboring access points
  * @wpa_s: Pointer to wpa_supplicant data
@@ -1592,6 +1613,8 @@
 void scan_only_handler(struct wpa_supplicant *wpa_s,
 		       struct wpa_scan_results *scan_res)
 {
+	wpa_dbg(wpa_s, MSG_DEBUG, "Scan-only results received");
 	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
 	wpas_notify_scan_results(wpa_s);
+	wpas_notify_scan_done(wpa_s, 1);
 }
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 098f0f3..5ecfa00 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -32,6 +32,7 @@
 					     u32 vendor_type);
 int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
 				      const u8 *bssid);
+void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec);
 void scan_only_handler(struct wpa_supplicant *wpa_s,
 		       struct wpa_scan_results *scan_res);
 
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 2278138..6d8b1f5 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1459,9 +1459,7 @@
 
 static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-	if (argc > 0)
-		return wpa_cli_cmd(ctrl, "SCAN", 1, argc, argv);
-	return wpa_ctrl_command(ctrl, "SCAN");
+	return wpa_cli_cmd(ctrl, "SCAN", 0, argc, argv);
 }
 
 
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index ee1a06c..725364a 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1896,7 +1896,9 @@
 	wpa_s->connect_without_scan = NULL;
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
-	wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
+
+	if (wpa_supplicant_fast_associate(wpa_s) != 1)
+		wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
 
 	if (ssid)
 		wpas_notify_network_selected(wpa_s, ssid);
@@ -2001,7 +2003,7 @@
 	}
 	wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
 		scan_interval);
-	wpa_s->scan_interval = scan_interval;
+	wpa_supplicant_update_scan_int(wpa_s, scan_interval);
 
 	return 0;
 }
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index ecbdedf..0f51f8e 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -785,7 +785,7 @@
 void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx);
 void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
 void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s);
-int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s);
 
 /* eap_register.c */
 int eap_register_methods(void);