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/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 851c183..b3574ba 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -1158,8 +1158,8 @@
 
 int gas_serv_init(struct hostapd_data *hapd)
 {
-	hapd->public_action_cb = gas_serv_rx_public_action;
-	hapd->public_action_cb_ctx = hapd;
+	hapd->public_action_cb2 = gas_serv_rx_public_action;
+	hapd->public_action_cb2_ctx = hapd;
 	hapd->gas_frag_limit = 1400;
 	if (hapd->conf->gas_frag_limit > 0)
 		hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index c9087b3..2827232 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -151,6 +151,9 @@
 	void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
 				 int freq);
 	void *public_action_cb_ctx;
+	void (*public_action_cb2)(void *ctx, const u8 *buf, size_t len,
+				  int freq);
+	void *public_action_cb2_ctx;
 
 	int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len,
 				int freq);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 79235df..129c5b5 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1599,8 +1599,14 @@
 			hapd->public_action_cb(hapd->public_action_cb_ctx,
 					       (u8 *) mgmt, len,
 					       hapd->iface->freq);
-			return;
 		}
+		if (hapd->public_action_cb2) {
+			hapd->public_action_cb2(hapd->public_action_cb_ctx,
+						(u8 *) mgmt, len,
+						hapd->iface->freq);
+		}
+		if (hapd->public_action_cb || hapd->public_action_cb2)
+			return;
 		break;
 	case WLAN_ACTION_VENDOR_SPECIFIC:
 		if (hapd->vendor_action_cb) {
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index e530911..d133bad 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -178,7 +178,6 @@
 };
 
 static void nl80211_global_deinit(void *priv);
-static void wpa_driver_nl80211_deinit(void *priv);
 
 struct i802_bss {
 	struct wpa_driver_nl80211_data *drv;
@@ -286,6 +285,7 @@
 };
 
 
+static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
 static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
 					    void *timeout_ctx);
 static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
@@ -301,7 +301,8 @@
 				  unsigned int freq, unsigned int wait,
 				  const u8 *buf, size_t buf_len, u64 *cookie,
 				  int no_cck, int no_ack, int offchanok);
-static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
+static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
+					       int report);
 #ifdef ANDROID
 static int android_pno_start(struct i802_bss *bss,
 			     struct wpa_driver_scan_params *params);
@@ -320,7 +321,7 @@
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
-static int wpa_driver_nl80211_if_remove(void *priv,
+static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
 					enum wpa_driver_if_type type,
 					const char *ifname);
 #else /* HOSTAPD */
@@ -342,7 +343,8 @@
 					 size_t buf_len);
 #endif
 
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
+				       struct hostapd_freq_params *freq);
 static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
 				     int ifindex, int disabled);
 
@@ -3499,14 +3501,13 @@
 
 /**
  * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
- * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
+ * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
  *
  * Shut down driver interface and processing of driver events. Free
  * private data buffer if one was allocated in wpa_driver_nl80211_init().
  */
-static void wpa_driver_nl80211_deinit(void *priv)
+static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
 	bss->in_deinit = 1;
@@ -3542,7 +3543,7 @@
 		struct hostapd_freq_params freq;
 		os_memset(&freq, 0, sizeof(freq));
 		freq.freq = drv->last_freq;
-		i802_set_freq(priv, &freq);
+		wpa_driver_nl80211_set_freq(bss, &freq);
 	}
 
 	if (drv->eapol_sock >= 0) {
@@ -3682,14 +3683,13 @@
 
 /**
  * wpa_driver_nl80211_scan - Request the driver to initiate scan
- * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
  * @params: Scan parameters
  * Returns: 0 on success, -1 on failure
  */
-static int wpa_driver_nl80211_scan(void *priv,
+static int wpa_driver_nl80211_scan(struct i802_bss *bss,
 				   struct wpa_driver_scan_params *params)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret = -1, timeout;
 	struct nl_msg *msg, *rates = NULL;
@@ -3737,7 +3737,7 @@
 				    bss, NL80211_IFTYPE_STATION))
 				goto nla_put_failure;
 
-			if (wpa_driver_nl80211_scan(drv, params)) {
+			if (wpa_driver_nl80211_scan(bss, params)) {
 				wpa_driver_nl80211_set_mode(bss, drv->nlmode);
 				goto nla_put_failure;
 			}
@@ -4274,13 +4274,12 @@
 }
 
 
-static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
+static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
 				      enum wpa_alg alg, const u8 *addr,
 				      int key_idx, int set_tx,
 				      const u8 *seq, size_t seq_len,
 				      const u8 *key, size_t key_len)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ifindex = if_nametoindex(ifname);
 	struct nl_msg *msg;
@@ -4607,10 +4606,9 @@
 }
 
 
-static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
-					     int reason_code)
+static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
+					     const u8 *addr, int reason_code)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
 		return wpa_driver_nl80211_disconnect(drv, reason_code);
@@ -4671,9 +4669,8 @@
 
 
 static int wpa_driver_nl80211_authenticate(
-	void *priv, struct wpa_driver_auth_params *params)
+	struct i802_bss *bss, struct wpa_driver_auth_params *params)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret = -1, i;
 	struct nl_msg *msg;
@@ -4691,7 +4688,7 @@
 	nlmode = params->p2p ?
 		NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
 	if (drv->nlmode != nlmode &&
-	    wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
+	    wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
 		return -1;
 
 retry:
@@ -4707,7 +4704,7 @@
 	for (i = 0; i < 4; i++) {
 		if (!params->wep_key[i])
 			continue;
-		wpa_driver_nl80211_set_key(bss->ifname, priv, WPA_ALG_WEP,
+		wpa_driver_nl80211_set_key(bss->ifname, bss, WPA_ALG_WEP,
 					   NULL, i,
 					   i == params->wep_tx_keyidx, NULL, 0,
 					   params->wep_key[i],
@@ -5421,12 +5418,11 @@
 }
 
 
-static int wpa_driver_nl80211_send_mlme_freq(struct i802_bss *bss,
-					     const u8 *data,
-					     size_t data_len, int noack,
-					     unsigned int freq, int no_cck,
-					     int offchanok,
-					     unsigned int wait_time)
+static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
+					size_t data_len, int noack,
+					unsigned int freq, int no_cck,
+					int offchanok,
+					unsigned int wait_time)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct ieee80211_mgmt *mgmt;
@@ -5482,15 +5478,6 @@
 }
 
 
-static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
-					size_t data_len, int noack)
-{
-	struct i802_bss *bss = priv;
-	return wpa_driver_nl80211_send_mlme_freq(bss, data, data_len, noack,
-						 0, 0, 0, 0);
-}
-
-
 static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
 			   int slot, int ht_opmode, int ap_isolate,
 			   int *basic_rates)
@@ -5869,9 +5856,8 @@
 }
 
 
-static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
+static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	int ret;
@@ -7598,10 +7584,10 @@
 	return NL_SKIP;
 }
 
-static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
+static int i802_read_sta_data(struct i802_bss *bss,
+			      struct hostap_sta_driver_data *data,
 			      const u8 *addr)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 
@@ -7683,10 +7669,9 @@
 }
 
 
-static int i802_set_sta_vlan(void *priv, const u8 *addr,
+static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
 			     const char *ifname, int vlan_id)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	int ret = -ENOBUFS;
@@ -7758,7 +7743,8 @@
 	mgmt.u.deauth.reason_code = host_to_le16(reason);
 	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
 					    IEEE80211_HDRLEN +
-					    sizeof(mgmt.u.deauth), 0);
+					    sizeof(mgmt.u.deauth), 0, 0, 0, 0,
+					    0);
 }
 
 
@@ -7781,7 +7767,8 @@
 	mgmt.u.disassoc.reason_code = host_to_le16(reason);
 	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
 					    IEEE80211_HDRLEN +
-					    sizeof(mgmt.u.disassoc), 0);
+					    sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
+					    0);
 }
 
 #endif /* HOSTAPD || CONFIG_AP */
@@ -8059,7 +8046,8 @@
 
 static void i802_deinit(void *priv)
 {
-	wpa_driver_nl80211_deinit(priv);
+	struct i802_bss *bss = priv;
+	wpa_driver_nl80211_deinit(bss);
 }
 
 #endif /* HOSTAPD */
@@ -8237,11 +8225,10 @@
 }
 
 
-static int wpa_driver_nl80211_if_remove(void *priv,
+static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
 					enum wpa_driver_if_type type,
 					const char *ifname)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ifindex = if_nametoindex(ifname);
 
@@ -8362,14 +8349,14 @@
 }
 
 
-static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
+static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
+					  unsigned int freq,
 					  unsigned int wait_time,
 					  const u8 *dst, const u8 *src,
 					  const u8 *bssid,
 					  const u8 *data, size_t data_len,
 					  int no_cck)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret = -1;
 	u8 *buf;
@@ -8391,10 +8378,9 @@
 	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
 	if (is_ap_interface(drv->nlmode))
-		ret = wpa_driver_nl80211_send_mlme_freq(priv, buf,
-							24 + data_len,
-							0, freq, no_cck, 1,
-							wait_time);
+		ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
+						   0, freq, no_cck, 1,
+						   wait_time);
 	else
 		ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
 					     24 + data_len,
@@ -8510,9 +8496,8 @@
 }
 
 
-static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
+static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
 	if (!report) {
@@ -9027,7 +9012,8 @@
 	os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
 	os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
 
-	if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
+	if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
+					 0, 0) < 0)
 		wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
 			   "send poll frame");
 }
@@ -9325,34 +9311,140 @@
 #endif /* ANDROID */
 
 
+static int driver_nl80211_set_key(const char *ifname, void *priv,
+				  enum wpa_alg alg, const u8 *addr,
+				  int key_idx, int set_tx,
+				  const u8 *seq, size_t seq_len,
+				  const u8 *key, size_t key_len)
+{
+	struct i802_bss *bss = priv;
+	return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx,
+					  set_tx, seq, seq_len, key, key_len);
+}
+
+
+static int driver_nl80211_scan2(void *priv,
+				struct wpa_driver_scan_params *params)
+{
+	struct i802_bss *bss = priv;
+	return wpa_driver_nl80211_scan(bss, params);
+}
+
+
+static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
+					 int reason_code)
+{
+	struct i802_bss *bss = priv;
+	return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
+}
+
+
+static int driver_nl80211_authenticate(void *priv,
+				       struct wpa_driver_auth_params *params)
+{
+	struct i802_bss *bss = priv;
+	return wpa_driver_nl80211_authenticate(bss, params);
+}
+
+
+static void driver_nl80211_deinit(void *priv)
+{
+	struct i802_bss *bss = priv;
+	wpa_driver_nl80211_deinit(bss);
+}
+
+
+static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
+				    const char *ifname)
+{
+	struct i802_bss *bss = priv;
+	return wpa_driver_nl80211_if_remove(bss, type, ifname);
+}
+
+
+static int driver_nl80211_send_mlme(void *priv, const u8 *data,
+				    size_t data_len, int noack)
+{
+	struct i802_bss *bss = priv;
+	return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
+					    0, 0, 0, 0);
+}
+
+
+static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
+{
+	struct i802_bss *bss = priv;
+	return wpa_driver_nl80211_sta_remove(bss, addr);
+}
+
+
+#if defined(HOSTAPD) || defined(CONFIG_AP)
+static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
+				       const char *ifname, int vlan_id)
+{
+	struct i802_bss *bss = priv;
+	return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
+}
+#endif /* HOSTAPD || CONFIG_AP */
+
+
+static int driver_nl80211_read_sta_data(void *priv,
+					struct hostap_sta_driver_data *data,
+					const u8 *addr)
+{
+	struct i802_bss *bss = priv;
+	return i802_read_sta_data(bss, data, addr);
+}
+
+
+static int driver_nl80211_send_action(void *priv, unsigned int freq,
+				      unsigned int wait_time,
+				      const u8 *dst, const u8 *src,
+				      const u8 *bssid,
+				      const u8 *data, size_t data_len,
+				      int no_cck)
+{
+	struct i802_bss *bss = priv;
+	return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
+					      bssid, data, data_len, no_cck);
+}
+
+
+static int driver_nl80211_probe_req_report(void *priv, int report)
+{
+	struct i802_bss *bss = priv;
+	return wpa_driver_nl80211_probe_req_report(bss, report);
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
 	.get_bssid = wpa_driver_nl80211_get_bssid,
 	.get_ssid = wpa_driver_nl80211_get_ssid,
-	.set_key = wpa_driver_nl80211_set_key,
-	.scan2 = wpa_driver_nl80211_scan,
+	.set_key = driver_nl80211_set_key,
+	.scan2 = driver_nl80211_scan2,
 	.sched_scan = wpa_driver_nl80211_sched_scan,
 	.stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
 	.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
-	.deauthenticate = wpa_driver_nl80211_deauthenticate,
-	.authenticate = wpa_driver_nl80211_authenticate,
+	.deauthenticate = driver_nl80211_deauthenticate,
+	.authenticate = driver_nl80211_authenticate,
 	.associate = wpa_driver_nl80211_associate,
 	.global_init = nl80211_global_init,
 	.global_deinit = nl80211_global_deinit,
 	.init2 = wpa_driver_nl80211_init,
-	.deinit = wpa_driver_nl80211_deinit,
+	.deinit = driver_nl80211_deinit,
 	.get_capa = wpa_driver_nl80211_get_capa,
 	.set_operstate = wpa_driver_nl80211_set_operstate,
 	.set_supp_port = wpa_driver_nl80211_set_supp_port,
 	.set_country = wpa_driver_nl80211_set_country,
 	.set_ap = wpa_driver_nl80211_set_ap,
 	.if_add = wpa_driver_nl80211_if_add,
-	.if_remove = wpa_driver_nl80211_if_remove,
-	.send_mlme = wpa_driver_nl80211_send_mlme,
+	.if_remove = driver_nl80211_if_remove,
+	.send_mlme = driver_nl80211_send_mlme,
 	.get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
 	.sta_add = wpa_driver_nl80211_sta_add,
-	.sta_remove = wpa_driver_nl80211_sta_remove,
+	.sta_remove = driver_nl80211_sta_remove,
 	.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
 	.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
 #ifdef HOSTAPD
@@ -9368,18 +9460,18 @@
 	.set_rts = i802_set_rts,
 	.set_frag = i802_set_frag,
 	.set_tx_queue_params = i802_set_tx_queue_params,
-	.set_sta_vlan = i802_set_sta_vlan,
+	.set_sta_vlan = driver_nl80211_set_sta_vlan,
 	.sta_deauth = i802_sta_deauth,
 	.sta_disassoc = i802_sta_disassoc,
 #endif /* HOSTAPD || CONFIG_AP */
-	.read_sta_data = i802_read_sta_data,
+	.read_sta_data = driver_nl80211_read_sta_data,
 	.set_freq = i802_set_freq,
-	.send_action = wpa_driver_nl80211_send_action,
+	.send_action = driver_nl80211_send_action,
 	.send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
 	.remain_on_channel = wpa_driver_nl80211_remain_on_channel,
 	.cancel_remain_on_channel =
 	wpa_driver_nl80211_cancel_remain_on_channel,
-	.probe_req_report = wpa_driver_nl80211_probe_req_report,
+	.probe_req_report = driver_nl80211_probe_req_report,
 	.deinit_ap = wpa_driver_nl80211_deinit_ap,
 	.deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
 	.resume = wpa_driver_nl80211_resume,
diff --git a/src/drivers/driver_openbsd.c b/src/drivers/driver_openbsd.c
new file mode 100644
index 0000000..e94eda0
--- /dev/null
+++ b/src/drivers/driver_openbsd.c
@@ -0,0 +1,136 @@
+/*
+ * Driver interaction with OpenBSD net80211 layer
+ * Copyright (c) 2013, Mark Kettenis
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+
+#include "common.h"
+#include "driver.h"
+
+struct openbsd_driver_data {
+	char ifname[IFNAMSIZ + 1];
+	void *ctx;
+
+	int sock;			/* open socket for 802.11 ioctls */
+};
+
+
+static int
+wpa_driver_openbsd_get_ssid(void *priv, u8 *ssid)
+{
+	struct openbsd_driver_data *drv = priv;
+	struct ieee80211_nwid nwid;
+	struct ifreq ifr;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+	ifr.ifr_data = (void *)&nwid;
+	if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 ||
+	    nwid.i_len > IEEE80211_NWID_LEN)
+		return -1;
+
+	os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
+	return nwid.i_len;
+}
+
+static int
+wpa_driver_openbsd_get_bssid(void *priv, u8 *bssid)
+{
+	struct openbsd_driver_data *drv = priv;
+	struct ieee80211_bssid id;
+
+	os_strlcpy(id.i_name, drv->ifname, sizeof(id.i_name));
+	if (ioctl(drv->sock, SIOCG80211BSSID, &id) < 0)
+		return -1;
+
+	os_memcpy(bssid, id.i_bssid, IEEE80211_ADDR_LEN);
+	return 0;
+}
+
+
+static int
+wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+	os_memset(capa, 0, sizeof(*capa));
+	capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+	return 0;
+}
+
+
+static int
+wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
+	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
+	    size_t seq_len, const u8 *key, size_t key_len)
+{
+	struct openbsd_driver_data *drv = priv;
+	struct ieee80211_keyavail keyavail;
+
+	if (alg != WPA_ALG_PMK || key_len > IEEE80211_PMK_LEN)
+		return -1;
+
+	memset(&keyavail, 0, sizeof(keyavail));
+	os_strlcpy(keyavail.i_name, drv->ifname, sizeof(keyavail.i_name));
+	if (wpa_driver_openbsd_get_bssid(priv, keyavail.i_macaddr) < 0)
+		return -1;
+	memcpy(keyavail.i_key, key, key_len);
+
+	if (ioctl(drv->sock, SIOCS80211KEYAVAIL, &keyavail) < 0)
+		return -1;
+
+	return 0;
+}
+
+static void *
+wpa_driver_openbsd_init(void *ctx, const char *ifname)
+{
+	struct openbsd_driver_data *drv;
+
+	drv = os_zalloc(sizeof(*drv));
+	if (drv == NULL)
+		return NULL;
+
+	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (drv->sock < 0)
+		goto fail;
+
+	drv->ctx = ctx;
+	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+	return drv;
+
+fail:
+	os_free(drv);
+	return NULL;
+}
+
+
+static void
+wpa_driver_openbsd_deinit(void *priv)
+{
+	struct openbsd_driver_data *drv = priv;
+
+	close(drv->sock);
+	os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_openbsd_ops = {
+	.name = "openbsd",
+	.desc = "OpenBSD 802.11 support",
+	.get_ssid = wpa_driver_openbsd_get_ssid,
+	.get_bssid = wpa_driver_openbsd_get_bssid,
+	.get_capa = wpa_driver_openbsd_get_capa,
+	.set_key = wpa_driver_openbsd_set_key,
+	.init = wpa_driver_openbsd_init,
+	.deinit = wpa_driver_openbsd_deinit,
+};
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index a92eddf..1d0ff6e 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -24,6 +24,9 @@
 #ifdef CONFIG_DRIVER_BSD
 extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
 #endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_OPENBSD
+extern struct wpa_driver_ops wpa_driver_openbsd_ops; /* driver_openbsd.c */
+#endif /* CONFIG_DRIVER_OPENBSD */
 #ifdef CONFIG_DRIVER_NDIS
 extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
 #endif /* CONFIG_DRIVER_NDIS */
@@ -62,6 +65,9 @@
 #ifdef CONFIG_DRIVER_BSD
 	&wpa_driver_bsd_ops,
 #endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_OPENBSD
+	&wpa_driver_openbsd_ops,
+#endif /* CONFIG_DRIVER_OPENBSD */
 #ifdef CONFIG_DRIVER_NDIS
 	&wpa_driver_ndis_ops,
 #endif /* CONFIG_DRIVER_NDIS */
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index c7a98d3..68ff910 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -55,6 +55,14 @@
 CONFIG_DNET_PCAP=y
 endif
 
+ifdef CONFIG_DRIVER_OPENBSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_OPENBSD
+DRV_OBJS += ../src/drivers/driver_openbsd.o
+endif
+
 ifdef CONFIG_DRIVER_TEST
 DRV_CFLAGS += -DCONFIG_DRIVER_TEST
 DRV_OBJS += ../src/drivers/driver_test.o
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 23fcbb7..db8561a 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -55,6 +55,14 @@
 CONFIG_DNET_PCAP=y
 endif
 
+ifdef CONFIG_DRIVER_OPENBSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_OPENBSD
+DRV_OBJS += src/drivers/driver_openbsd.c
+endif
+
 ifdef CONFIG_DRIVER_TEST
 DRV_CFLAGS += -DCONFIG_DRIVER_TEST
 DRV_OBJS += src/drivers/driver_test.c
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index f318c52..6f3dfb3 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -72,7 +72,7 @@
 
 static inline struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
-				 void *ctx, int reason),
+				 void *ctx, enum pmksa_free_reason reason),
 		 void *ctx, struct wpa_sm *sm)
 {
 	return (void *) -1;
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index c38fada..9a79d28 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -680,8 +680,11 @@
 		return -1;
 	pos = rbuf;
 
-	if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success)
+	if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) {
+		/* Overwrite the reason code */
+		reason_code = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
 		goto skip_ies;
+	}
 
 	ftie = (struct wpa_tdls_ftie *) pos;
 	ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
@@ -715,8 +718,7 @@
 
 	/* request driver to send Teardown using this FTIE */
 	wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0,
-			  WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, rbuf,
-			  pos - rbuf);
+			  reason_code, rbuf, pos - rbuf);
 	os_free(rbuf);
 
 	/* clear the Peerkey statemachine */
@@ -868,10 +870,20 @@
 
 
 static struct wpa_tdls_peer *
-wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr)
+wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr, int *existing)
 {
 	struct wpa_tdls_peer *peer;
 
+	if (existing)
+		*existing = 0;
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) {
+			if (existing)
+				*existing = 1;
+			return peer; /* re-use existing entry */
+		}
+	}
+
 	wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR,
 		   MAC2STR(addr));
 
@@ -1282,7 +1294,7 @@
 		return -1;
 	}
 
-	peer = wpa_tdls_add_peer(sm, addr);
+	peer = wpa_tdls_add_peer(sm, addr, NULL);
 	if (peer == NULL)
 		return -1;
 
@@ -1352,18 +1364,9 @@
 
 	wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken);
 
-	for (peer = sm->tdls; peer; peer = peer->next) {
-		if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) {
-			existing_peer = 1;
-			break;
-		}
-	}
-
-	if (peer == NULL) {
-		peer = wpa_tdls_add_peer(sm, src_addr);
-		if (peer == NULL)
-			goto error;
-	}
+	peer = wpa_tdls_add_peer(sm, src_addr, &existing_peer);
+	if (peer == NULL)
+		goto error;
 
 	/* capability information */
 	peer->capability = WPA_GET_LE16(cpos);
@@ -1397,15 +1400,9 @@
 
 #ifdef CONFIG_TDLS_TESTING
 	if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
-		for (peer = sm->tdls; peer; peer = peer->next) {
-			if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
-				break;
-		}
-		if (peer == NULL) {
-			peer = wpa_tdls_add_peer(sm, src_addr);
-			if (peer == NULL)
-				goto error;
-		}
+		peer = wpa_tdls_add_peer(sm, src_addr, NULL);
+		if (peer == NULL)
+			goto error;
 		wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of "
 			   "TDLS setup - send own request");
 		peer->initiator = 1;
@@ -2058,18 +2055,9 @@
 		return -1;
 	}
 
-	/* Find existing entry and if found, use that instead of adding
-	 * a new one */
-	for (peer = sm->tdls; peer; peer = peer->next) {
-		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
-			break;
-	}
-
-	if (peer == NULL) {
-		peer = wpa_tdls_add_peer(sm, addr);
-		if (peer == NULL)
-			return -1;
-	}
+	peer = wpa_tdls_add_peer(sm, addr, NULL);
+	if (peer == NULL)
+		return -1;
 
 	peer->initiator = 1;
 
@@ -2085,12 +2073,12 @@
 }
 
 
-int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr)
+void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr)
 {
 	struct wpa_tdls_peer *peer;
 
 	if (sm->tdls_disabled || !sm->tdls_supported)
-		return -1;
+		return;
 
 	for (peer = sm->tdls; peer; peer = peer->next) {
 		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
@@ -2098,7 +2086,7 @@
 	}
 
 	if (peer == NULL || !peer->tpk_success)
-		return -1;
+		return;
 
 	if (sm->tdls_external_setup) {
 		/*
@@ -2107,8 +2095,6 @@
 		 */
 		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
 	}
-
-	return wpa_tdls_start(sm, addr);
 }
 
 
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 791974c..2c989b7 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -355,7 +355,7 @@
 void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
 void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
 int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr);
-int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr);
+void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr);
 int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
 int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
 int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr);
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index d01ae64..2de3e01 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -556,6 +556,33 @@
 }
 
 
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+			     void *eloop_data, void *user_data,
+			     struct os_time *remaining)
+{
+	struct eloop_timeout *timeout, *prev;
+	int removed = 0;
+	struct os_time now;
+
+	os_get_time(&now);
+	remaining->sec = remaining->usec = 0;
+
+	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+			      struct eloop_timeout, list) {
+		if (timeout->handler == handler &&
+		    (timeout->eloop_data == eloop_data) &&
+		    (timeout->user_data == user_data)) {
+			removed = 1;
+			if (os_time_before(&now, &timeout->time))
+				os_time_sub(&timeout->time, &now, remaining);
+			eloop_remove_timeout(timeout);
+			break;
+		}
+	}
+	return removed;
+}
+
+
 int eloop_is_timeout_registered(eloop_timeout_handler handler,
 				void *eloop_data, void *user_data)
 {
diff --git a/src/utils/eloop.h b/src/utils/eloop.h
index db03a73..0037c63 100644
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
@@ -195,6 +195,21 @@
 			 void *eloop_data, void *user_data);
 
 /**
+ * eloop_cancel_timeout_one - Cancel a single timeout
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * @remaining: Time left on the cancelled timer
+ * Returns: Number of cancelled timeouts
+ *
+ * Cancel matching <handler,eloop_data,user_data> timeout registered with
+ * eloop_register_timeout() and return the remaining time left.
+ */
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+			     void *eloop_data, void *user_data,
+			     struct os_time *remaining);
+
+/**
  * eloop_is_timeout_registered - Check if a timeout is already registered
  * @handler: Matching callback function
  * @eloop_data: Matching eloop_data
diff --git a/src/utils/eloop_none.c b/src/utils/eloop_none.c
index c67ece4..cb5e922 100644
--- a/src/utils/eloop_none.c
+++ b/src/utils/eloop_none.c
@@ -1,6 +1,6 @@
 /*
  * Event loop - empty template (basic structure, but no OS specific operations)
- * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -9,6 +9,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "list.h"
 #include "eloop.h"
 
 
@@ -16,21 +17,21 @@
 	int sock;
 	void *eloop_data;
 	void *user_data;
-	void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
+	eloop_sock_handler handler;
 };
 
 struct eloop_timeout {
+	struct dl_list list;
 	struct os_time time;
 	void *eloop_data;
 	void *user_data;
-	void (*handler)(void *eloop_ctx, void *sock_ctx);
-	struct eloop_timeout *next;
+	eloop_timeout_handler handler;
 };
 
 struct eloop_signal {
 	int sig;
 	void *user_data;
-	void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
+	eloop_signal_handler handler;
 	int signaled;
 };
 
@@ -38,7 +39,7 @@
 	int max_sock, reader_count;
 	struct eloop_sock *readers;
 
-	struct eloop_timeout *timeout;
+	struct dl_list timeout;
 
 	int signal_count;
 	struct eloop_signal *signals;
@@ -54,21 +55,19 @@
 
 int eloop_init(void)
 {
-	memset(&eloop, 0, sizeof(eloop));
+	os_memset(&eloop, 0, sizeof(eloop));
+	dl_list_init(&eloop.timeout);
 	return 0;
 }
 
 
-int eloop_register_read_sock(int sock,
-			     void (*handler)(int sock, void *eloop_ctx,
-					     void *sock_ctx),
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
 			     void *eloop_data, void *user_data)
 {
 	struct eloop_sock *tmp;
 
-	tmp = (struct eloop_sock *)
-		realloc(eloop.readers,
-			(eloop.reader_count + 1) * sizeof(struct eloop_sock));
+	tmp = os_realloc_array(eloop.readers, eloop.reader_count + 1,
+			       sizeof(struct eloop_sock));
 	if (tmp == NULL)
 		return -1;
 
@@ -100,9 +99,9 @@
 	if (i == eloop.reader_count)
 		return;
 	if (i != eloop.reader_count - 1) {
-		memmove(&eloop.readers[i], &eloop.readers[i + 1],
-			(eloop.reader_count - i - 1) *
-			sizeof(struct eloop_sock));
+		os_memmove(&eloop.readers[i], &eloop.readers[i + 1],
+			   (eloop.reader_count - i - 1) *
+			   sizeof(struct eloop_sock));
 	}
 	eloop.reader_count--;
 	eloop.reader_table_changed = 1;
@@ -110,16 +109,31 @@
 
 
 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
-			   void (*handler)(void *eloop_ctx, void *timeout_ctx),
+			   eloop_timeout_handler handler,
 			   void *eloop_data, void *user_data)
 {
-	struct eloop_timeout *timeout, *tmp, *prev;
+	struct eloop_timeout *timeout, *tmp;
+	os_time_t now_sec;
 
-	timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
+	timeout = os_zalloc(sizeof(*timeout));
 	if (timeout == NULL)
 		return -1;
-	os_get_time(&timeout->time);
+	if (os_get_time(&timeout->time) < 0) {
+		os_free(timeout);
+		return -1;
+	}
+	now_sec = timeout->time.sec;
 	timeout->time.sec += secs;
+	if (timeout->time.sec < now_sec) {
+		/*
+		 * Integer overflow - assume long enough timeout to be assumed
+		 * to be infinite, i.e., the timeout would never happen.
+		 */
+		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
+			   "ever happen - ignore it", secs);
+		os_free(timeout);
+		return 0;
+	}
 	timeout->time.usec += usecs;
 	while (timeout->time.usec >= 1000000) {
 		timeout->time.sec++;
@@ -128,80 +142,86 @@
 	timeout->eloop_data = eloop_data;
 	timeout->user_data = user_data;
 	timeout->handler = handler;
-	timeout->next = NULL;
 
-	if (eloop.timeout == NULL) {
-		eloop.timeout = timeout;
-		return 0;
+	/* Maintain timeouts in order of increasing time */
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (os_time_before(&timeout->time, &tmp->time)) {
+			dl_list_add(tmp->list.prev, &timeout->list);
+			return 0;
+		}
 	}
-
-	prev = NULL;
-	tmp = eloop.timeout;
-	while (tmp != NULL) {
-		if (os_time_before(&timeout->time, &tmp->time))
-			break;
-		prev = tmp;
-		tmp = tmp->next;
-	}
-
-	if (prev == NULL) {
-		timeout->next = eloop.timeout;
-		eloop.timeout = timeout;
-	} else {
-		timeout->next = prev->next;
-		prev->next = timeout;
-	}
+	dl_list_add_tail(&eloop.timeout, &timeout->list);
 
 	return 0;
 }
 
 
-int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+static void eloop_remove_timeout(struct eloop_timeout *timeout)
+{
+	dl_list_del(&timeout->list);
+	os_free(timeout);
+}
+
+
+int eloop_cancel_timeout(eloop_timeout_handler handler,
 			 void *eloop_data, void *user_data)
 {
-	struct eloop_timeout *timeout, *prev, *next;
+	struct eloop_timeout *timeout, *prev;
 	int removed = 0;
 
-	prev = NULL;
-	timeout = eloop.timeout;
-	while (timeout != NULL) {
-		next = timeout->next;
-
+	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+			      struct eloop_timeout, list) {
 		if (timeout->handler == handler &&
 		    (timeout->eloop_data == eloop_data ||
 		     eloop_data == ELOOP_ALL_CTX) &&
 		    (timeout->user_data == user_data ||
 		     user_data == ELOOP_ALL_CTX)) {
-			if (prev == NULL)
-				eloop.timeout = next;
-			else
-				prev->next = next;
-			free(timeout);
+			eloop_remove_timeout(timeout);
 			removed++;
-		} else
-			prev = timeout;
-
-		timeout = next;
+		}
 	}
 
 	return removed;
 }
 
 
-int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx,
-						void *timeout_ctx),
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+			     void *eloop_data, void *user_data,
+			     struct os_time *remaining)
+{
+	struct eloop_timeout *timeout, *prev;
+	int removed = 0;
+	struct os_time now;
+
+	os_get_time(&now);
+	remaining->sec = remaining->usec = 0;
+
+	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+			      struct eloop_timeout, list) {
+		if (timeout->handler == handler &&
+		    (timeout->eloop_data == eloop_data) &&
+		    (timeout->user_data == user_data)) {
+			removed = 1;
+			if (os_time_before(&now, &timeout->time))
+				os_time_sub(&timeout->time, &now, remaining);
+			eloop_remove_timeout(timeout);
+			break;
+		}
+	}
+	return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
 				void *eloop_data, void *user_data)
 {
 	struct eloop_timeout *tmp;
 
-	tmp = eloop.timeout;
-	while (tmp != NULL) {
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
 		if (tmp->handler == handler &&
 		    tmp->eloop_data == eloop_data &&
 		    tmp->user_data == user_data)
 			return 1;
-
-		tmp = tmp->next;
 	}
 
 	return 0;
@@ -241,24 +261,19 @@
 		if (eloop.signals[i].signaled) {
 			eloop.signals[i].signaled = 0;
 			eloop.signals[i].handler(eloop.signals[i].sig,
-						 eloop.user_data,
 						 eloop.signals[i].user_data);
 		}
 	}
 }
 
 
-int eloop_register_signal(int sig,
-			  void (*handler)(int sig, void *eloop_ctx,
-					  void *signal_ctx),
+int eloop_register_signal(int sig, eloop_signal_handler handler,
 			  void *user_data)
 {
 	struct eloop_signal *tmp;
 
-	tmp = (struct eloop_signal *)
-		realloc(eloop.signals,
-			(eloop.signal_count + 1) *
-			sizeof(struct eloop_signal));
+	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
+			       sizeof(struct eloop_signal));
 	if (tmp == NULL)
 		return -1;
 
@@ -275,8 +290,7 @@
 }
 
 
-int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx,
-						    void *signal_ctx),
+int eloop_register_signal_terminate(eloop_signal_handler handler,
 				    void *user_data)
 {
 #if 0
@@ -290,8 +304,7 @@
 }
 
 
-int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx,
-						   void *signal_ctx),
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
 				   void *user_data)
 {
 #if 0
@@ -308,11 +321,14 @@
 	struct os_time tv, now;
 
 	while (!eloop.terminate &&
-		(eloop.timeout || eloop.reader_count > 0)) {
-		if (eloop.timeout) {
+		(!dl_list_empty(&eloop.timeout) || eloop.reader_count > 0)) {
+		struct eloop_timeout *timeout;
+		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+					list);
+		if (timeout) {
 			os_get_time(&now);
-			if (os_time_before(&now, &eloop.timeout->time))
-				os_time_sub(&eloop.timeout->time, &now, &tv);
+			if (os_time_before(&now, &timeout->time))
+				os_time_sub(&timeout->time, &now, &tv);
 			else
 				tv.sec = tv.usec = 0;
 		}
@@ -326,16 +342,17 @@
 		eloop_process_pending_signals();
 
 		/* check if some registered timeouts have occurred */
-		if (eloop.timeout) {
-			struct eloop_timeout *tmp;
-
+		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+					list);
+		if (timeout) {
 			os_get_time(&now);
-			if (!os_time_before(&now, &eloop.timeout->time)) {
-				tmp = eloop.timeout;
-				eloop.timeout = eloop.timeout->next;
-				tmp->handler(tmp->eloop_data,
-					     tmp->user_data);
-				free(tmp);
+			if (!os_time_before(&now, &timeout->time)) {
+				void *eloop_data = timeout->eloop_data;
+				void *user_data = timeout->user_data;
+				eloop_timeout_handler handler =
+					timeout->handler;
+				eloop_remove_timeout(timeout);
+				handler(eloop_data, user_data);
 			}
 
 		}
@@ -369,14 +386,12 @@
 {
 	struct eloop_timeout *timeout, *prev;
 
-	timeout = eloop.timeout;
-	while (timeout != NULL) {
-		prev = timeout;
-		timeout = timeout->next;
-		free(prev);
+	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+			      struct eloop_timeout, list) {
+		eloop_remove_timeout(timeout);
 	}
-	free(eloop.readers);
-	free(eloop.signals);
+	os_free(eloop.readers);
+	os_free(eloop.signals);
 }
 
 
diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c
index 1fafeb2..eda412f 100644
--- a/src/utils/eloop_win.c
+++ b/src/utils/eloop_win.c
@@ -1,6 +1,6 @@
 /*
  * Event loop based on Windows events and WaitForMultipleObjects
- * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +10,7 @@
 #include <winsock2.h>
 
 #include "common.h"
+#include "list.h"
 #include "eloop.h"
 
 
@@ -29,11 +30,11 @@
 };
 
 struct eloop_timeout {
+	struct dl_list list;
 	struct os_time time;
 	void *eloop_data;
 	void *user_data;
 	eloop_timeout_handler handler;
-	struct eloop_timeout *next;
 };
 
 struct eloop_signal {
@@ -51,7 +52,7 @@
 	size_t event_count;
 	struct eloop_event *events;
 
-	struct eloop_timeout *timeout;
+	struct dl_list timeout;
 
 	int signal_count;
 	struct eloop_signal *signals;
@@ -74,6 +75,7 @@
 int eloop_init(void)
 {
 	os_memset(&eloop, 0, sizeof(eloop));
+	dl_list_init(&eloop.timeout);
 	eloop.num_handles = 1;
 	eloop.handles = os_malloc(eloop.num_handles *
 				  sizeof(eloop.handles[0]));
@@ -236,13 +238,16 @@
 			   eloop_timeout_handler handler,
 			   void *eloop_data, void *user_data)
 {
-	struct eloop_timeout *timeout, *tmp, *prev;
+	struct eloop_timeout *timeout, *tmp;
 	os_time_t now_sec;
 
-	timeout = os_malloc(sizeof(*timeout));
+	timeout = os_zalloc(sizeof(*timeout));
 	if (timeout == NULL)
 		return -1;
-	os_get_time(&timeout->time);
+	if (os_get_time(&timeout->time) < 0) {
+		os_free(timeout);
+		return -1;
+	}
 	now_sec = timeout->time.sec;
 	timeout->time.sec += secs;
 	if (timeout->time.sec < now_sec) {
@@ -263,79 +268,86 @@
 	timeout->eloop_data = eloop_data;
 	timeout->user_data = user_data;
 	timeout->handler = handler;
-	timeout->next = NULL;
 
-	if (eloop.timeout == NULL) {
-		eloop.timeout = timeout;
-		return 0;
+	/* Maintain timeouts in order of increasing time */
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (os_time_before(&timeout->time, &tmp->time)) {
+			dl_list_add(tmp->list.prev, &timeout->list);
+			return 0;
+		}
 	}
-
-	prev = NULL;
-	tmp = eloop.timeout;
-	while (tmp != NULL) {
-		if (os_time_before(&timeout->time, &tmp->time))
-			break;
-		prev = tmp;
-		tmp = tmp->next;
-	}
-
-	if (prev == NULL) {
-		timeout->next = eloop.timeout;
-		eloop.timeout = timeout;
-	} else {
-		timeout->next = prev->next;
-		prev->next = timeout;
-	}
+	dl_list_add_tail(&eloop.timeout, &timeout->list);
 
 	return 0;
 }
 
 
+static void eloop_remove_timeout(struct eloop_timeout *timeout)
+{
+	dl_list_del(&timeout->list);
+	os_free(timeout);
+}
+
+
 int eloop_cancel_timeout(eloop_timeout_handler handler,
 			 void *eloop_data, void *user_data)
 {
-	struct eloop_timeout *timeout, *prev, *next;
+	struct eloop_timeout *timeout, *prev;
 	int removed = 0;
 
-	prev = NULL;
-	timeout = eloop.timeout;
-	while (timeout != NULL) {
-		next = timeout->next;
-
+	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+			      struct eloop_timeout, list) {
 		if (timeout->handler == handler &&
 		    (timeout->eloop_data == eloop_data ||
 		     eloop_data == ELOOP_ALL_CTX) &&
 		    (timeout->user_data == user_data ||
 		     user_data == ELOOP_ALL_CTX)) {
-			if (prev == NULL)
-				eloop.timeout = next;
-			else
-				prev->next = next;
-			os_free(timeout);
+			eloop_remove_timeout(timeout);
 			removed++;
-		} else
-			prev = timeout;
-
-		timeout = next;
+		}
 	}
 
 	return removed;
 }
 
 
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+			     void *eloop_data, void *user_data,
+			     struct os_time *remaining)
+{
+	struct eloop_timeout *timeout, *prev;
+	int removed = 0;
+	struct os_time now;
+
+	os_get_time(&now);
+	remaining->sec = remaining->usec = 0;
+
+	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+			      struct eloop_timeout, list) {
+		if (timeout->handler == handler &&
+		    (timeout->eloop_data == eloop_data) &&
+		    (timeout->user_data == user_data)) {
+			removed = 1;
+			if (os_time_before(&now, &timeout->time))
+				os_time_sub(&timeout->time, &now, remaining);
+			eloop_remove_timeout(timeout);
+			break;
+		}
+	}
+	return removed;
+}
+
+
 int eloop_is_timeout_registered(eloop_timeout_handler handler,
 				void *eloop_data, void *user_data)
 {
 	struct eloop_timeout *tmp;
 
-	tmp = eloop.timeout;
-	while (tmp != NULL) {
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
 		if (tmp->handler == handler &&
 		    tmp->eloop_data == eloop_data &&
 		    tmp->user_data == user_data)
 			return 1;
-
-		tmp = tmp->next;
 	}
 
 	return 0;
@@ -457,17 +469,20 @@
 void eloop_run(void)
 {
 	struct os_time tv, now;
-	DWORD count, ret, timeout, err;
+	DWORD count, ret, timeout_val, err;
 	size_t i;
 
 	while (!eloop.terminate &&
-	       (eloop.timeout || eloop.reader_count > 0 ||
+	       (!dl_list_empty(&eloop.timeout) || eloop.reader_count > 0 ||
 		eloop.event_count > 0)) {
+		struct eloop_timeout *timeout;
 		tv.sec = tv.usec = 0;
-		if (eloop.timeout) {
+		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+					list);
+		if (timeout) {
 			os_get_time(&now);
-			if (os_time_before(&now, &eloop.timeout->time))
-				os_time_sub(&eloop.timeout->time, &now, &tv);
+			if (os_time_before(&now, &timeout->time))
+				os_time_sub(&timeout->time, &now, &tv);
 		}
 
 		count = 0;
@@ -480,10 +495,10 @@
 		if (eloop.term_event)
 			eloop.handles[count++] = eloop.term_event;
 
-		if (eloop.timeout)
-			timeout = tv.sec * 1000 + tv.usec / 1000;
+		if (timeout)
+			timeout_val = tv.sec * 1000 + tv.usec / 1000;
 		else
-			timeout = INFINITE;
+			timeout_val = INFINITE;
 
 		if (count > MAXIMUM_WAIT_OBJECTS) {
 			printf("WaitForMultipleObjects: Too many events: "
@@ -493,26 +508,27 @@
 		}
 #ifdef _WIN32_WCE
 		ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
-					     timeout);
+					     timeout_val);
 #else /* _WIN32_WCE */
 		ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
-					       timeout, TRUE);
+					       timeout_val, TRUE);
 #endif /* _WIN32_WCE */
 		err = GetLastError();
 
 		eloop_process_pending_signals();
 
 		/* check if some registered timeouts have occurred */
-		if (eloop.timeout) {
-			struct eloop_timeout *tmp;
-
+		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+					list);
+		if (timeout) {
 			os_get_time(&now);
-			if (!os_time_before(&now, &eloop.timeout->time)) {
-				tmp = eloop.timeout;
-				eloop.timeout = eloop.timeout->next;
-				tmp->handler(tmp->eloop_data,
-					     tmp->user_data);
-				os_free(tmp);
+			if (!os_time_before(&now, &timeout->time)) {
+				void *eloop_data = timeout->eloop_data;
+				void *user_data = timeout->user_data;
+				eloop_timeout_handler handler =
+					timeout->handler;
+				eloop_remove_timeout(timeout);
+				handler(eloop_data, user_data);
 			}
 
 		}
@@ -571,11 +587,9 @@
 {
 	struct eloop_timeout *timeout, *prev;
 
-	timeout = eloop.timeout;
-	while (timeout != NULL) {
-		prev = timeout;
-		timeout = timeout->next;
-		os_free(prev);
+	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+			      struct eloop_timeout, list) {
+		eloop_remove_timeout(timeout);
 	}
 	os_free(eloop.readers);
 	os_free(eloop.signals);
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);