diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2dd7054..c26cf6f 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1998,6 +1998,9 @@ void wpa_config_free(struct wpa_config *config)
 	os_free(config->ext_password_backend);
 	os_free(config->sae_groups);
 	wpabuf_free(config->ap_vendor_elements);
+#ifdef CONFIG_FST
+	os_free(config->fst_bond);
+#endif
 	os_free(config);
 }
 
@@ -3401,6 +3404,10 @@ static const struct global_parse_data global_fields[] = {
 	{ INT(scan_cur_freq), 0 },
 	{ INT(sched_scan_interval), 0 },
 	{ INT(tdls_external_control), 0},
+#ifdef CONFIG_FST
+	{ STR(fst_bond), 0 },
+	{ INT_RANGE(fst_default, 0, 1), 0 },
+#endif
 };
 
 #undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index e7bdaa5..4d58077 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -953,6 +953,11 @@ struct wpa_config {
 	u8 ip_addr_mask[4];
 	u8 ip_addr_start[4];
 	u8 ip_addr_end[4];
+
+#ifdef CONFIG_FST
+	char *fst_bond;
+	int fst_default;
+#endif
 };
 
 
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 6684782..75af101 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -495,3 +495,6 @@ CONFIG_PEERKEY=y
 #
 # External password backend for testing purposes (developer use)
 #CONFIG_EXT_PASSWORD_TEST=y
+
+# Enable Fast Session Transfer (FST)
+# CONFIG_FST=y
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 47434e4..4a8fc2c 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -42,7 +42,9 @@
 #include "scan.h"
 #include "offchannel.h"
 #include "interworking.h"
-
+#ifdef CONFIG_FST
+#include "fst/fst.h"
+#endif
 
 #ifndef CONFIG_NO_SCAN_PROCESSING
 static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
@@ -1780,6 +1782,43 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
 	if (wpa_found || rsn_found)
 		wpa_s->ap_ies_from_associnfo = 1;
 
+#ifdef CONFIG_FST
+	wpabuf_free(wpa_s->received_mb_ies);
+	wpa_s->received_mb_ies = NULL;
+	if (wpa_s->fst) {
+		struct mb_ies_info mb_ies;
+
+		os_memset(&mb_ies, 0, sizeof(mb_ies));
+
+		wpa_printf(MSG_DEBUG, "Looking for MB IE...");
+
+		p = data->assoc_info.beacon_ies;
+		l = data->assoc_info.beacon_ies_len;
+		p = data->assoc_info.resp_ies;
+	        l = data->assoc_info.resp_ies_len;
+
+		while (p && l >= 2 && mb_ies.nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
+			len = p[1] + 2;
+			if (len > l) {
+				wpa_hexdump(MSG_DEBUG, "Truncated IE in beacon_ies",
+					p, l);
+				break;
+			}
+
+			if (p[0] == WLAN_EID_MULTI_BAND) {
+				wpa_printf(MSG_DEBUG, "MB IE of %u bytes found", len);
+				mb_ies.ies[mb_ies.nof_ies].ie = p + 2;
+				mb_ies.ies[mb_ies.nof_ies].ie_len = len - 2;
+				++mb_ies.nof_ies;
+			}
+
+			l -= len;
+			p += len;
+		}
+		wpa_s->received_mb_ies = mb_ies_by_info(&mb_ies);
+	}
+#endif
+
 	if (wpa_s->assoc_freq && data->assoc_info.freq &&
 	    wpa_s->assoc_freq != data->assoc_info.freq) {
 		wpa_printf(MSG_DEBUG, "Operating frequency changed from "
@@ -2767,6 +2806,13 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
 	}
 #endif /* CONFIG_INTERWORKING */
 
+#ifdef CONFIG_FST
+	if (mgmt->u.action.category == WLAN_ACTION_FST && wpa_s->fst) {
+		fst_rx_action(wpa_s->fst, mgmt, len);
+		return;
+	}
+#endif
+
 #ifdef CONFIG_P2P
 	wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
 			   category, payload, plen, freq);
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index d56935d..f015de0 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -16,6 +16,11 @@
 #include "driver_i.h"
 #include "p2p_supplicant.h"
 
+#ifdef CONFIG_FST
+#include "fst/fst.h"
+#endif
+
+extern struct wpa_driver_ops *wpa_drivers[];
 
 static void usage(void)
 {
@@ -325,9 +330,20 @@ int main(int argc, char *argv[])
 #endif /* CONFIG_P2P */
 	}
 
+#ifdef CONFIG_FST
+	if (exitcode == 0 && fst_global_start()) {
+		wpa_printf(MSG_ERROR, "Failed to start FST");
+		exitcode = -1;
+	}
+#endif
+
 	if (exitcode == 0)
 		exitcode = wpa_supplicant_run(global);
 
+#ifdef CONFIG_FST
+	fst_global_stop();
+#endif
+
 	wpa_supplicant_deinit(global);
 
 out:
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index a82fbf3..d99b93b 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -22,6 +22,9 @@
 #include "p2p_supplicant.h"
 #include "sme.h"
 #include "notify.h"
+#ifdef CONFIG_FST
+#include "fst/fst.h"
+#endif
 
 int wpas_notify_supplicant_initialized(struct wpa_global *global)
 {
@@ -79,6 +82,16 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
 	/* notify the new DBus API */
 	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATE);
 
+#ifdef CONFIG_FST
+	if (wpa_s->fst && !is_zero_ether_addr(wpa_s->bssid)) {
+		if (new_state == WPA_COMPLETED)
+			fst_notify_peer_connected(wpa_s->fst,
+				wpa_s->bssid, wpa_s->received_mb_ies);
+		else if (old_state >= WPA_ASSOCIATED && new_state < WPA_ASSOCIATED)
+			fst_notify_peer_disconnected(wpa_s->fst, wpa_s->bssid);
+	}
+#endif
+
 #ifdef CONFIG_P2P
 	if (new_state == WPA_COMPLETED)
 		wpas_p2p_notif_connected(wpa_s);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 6c742d6..3f6ad67 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -428,6 +428,13 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
 		wpas_hs20_add_indication(extra_ie);
 #endif /* CONFIG_HS20 */
 
+#ifdef CONFIG_FST
+	if (wpa_s->fst_ies) {
+		if (wpabuf_resize(&extra_ie, wpabuf_len(wpa_s->fst_ies)) == 0)
+			wpabuf_put_buf(extra_ie, wpa_s->fst_ies);
+	}
+#endif
+
 	return extra_ie;
 }
 
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index e712ac4..61765a2 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -370,6 +370,20 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
 	}
 #endif /* CONFIG_HS20 */
 
+#ifdef CONFIG_FST
+	if (wpa_s->fst_ies) {
+		int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
+		if (wpa_s->sme.assoc_req_ie_len + fst_ies_len <=
+			sizeof(wpa_s->sme.assoc_req_ie)) {
+				os_memcpy(wpa_s->sme.assoc_req_ie +
+					wpa_s->sme.assoc_req_ie_len,
+					wpabuf_head(wpa_s->fst_ies),
+					fst_ies_len);
+			wpa_s->sme.assoc_req_ie_len += fst_ies_len;
+		}
+	}
+#endif
+
 	ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
 	if (ext_capab_len > 0) {
 		u8 *pos = wpa_s->sme.assoc_req_ie;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index e942b62..3df2476 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -51,6 +51,9 @@
 #include "offchannel.h"
 #include "hs20_supplicant.h"
 #include "wnm_sta.h"
+#ifdef CONFIG_FST
+#include "fst/fst.h"
+#endif
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
@@ -1613,6 +1616,19 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 		}
 	}
 
+#ifdef CONFIG_FST
+	if (wpa_s->fst_ies)
+	{
+		int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
+		if (wpa_ie_len + fst_ies_len <= sizeof(wpa_ie)) {
+			os_memcpy(wpa_ie + wpa_ie_len,
+					wpabuf_head(wpa_s->fst_ies),
+					fst_ies_len);
+			wpa_ie_len += fst_ies_len;
+		}
+	}
+#endif
+
 	wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
 	use_crypt = 1;
 	cipher_pairwise = wpa_s->pairwise_cipher;
@@ -2995,6 +3011,37 @@ int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
 	return 0;
 }
 
+#ifdef CONFIG_FST
+static const u8 * fst_wpa_supplicant_get_bssid_cb(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return is_zero_ether_addr(wpa_s->bssid) ? NULL : wpa_s->bssid;
+}
+
+static void fst_wpa_supplicant_get_channel_info_cb(void *ctx,
+		enum hostapd_hw_mode *hw_mode, u8 *channel)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	*hw_mode = ieee80211_freq_to_chan(wpa_s->current_bss->freq, channel);
+}
+
+static void fst_wpa_supplicant_set_ies_cb(void *ctx,
+	struct wpabuf *fst_ies)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	wpa_s->fst_ies = fst_ies;
+}
+
+static int fst_wpa_supplicant_send_action_cb(void *ctx, const u8 *da,
+		struct wpabuf *data)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	WPA_ASSERT(os_memcmp(wpa_s->bssid, da, ETH_ALEN) == 0);
+	return wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+					  wpa_s->own_addr, wpa_s->bssid,
+					  wpabuf_head(data), wpabuf_len(data), 0);
+}
+#endif
 
 static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
 					      const char *rn)
@@ -3472,6 +3519,27 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
 		return -1;
 	}
 
+#ifdef CONFIG_FST
+	if (wpa_s->conf->fst_bond[0]) {
+		struct fst_wpa_obj iface_obj = {
+			.ctx = wpa_s,
+			.get_bssid         = fst_wpa_supplicant_get_bssid_cb,
+			.get_channel_info  = fst_wpa_supplicant_get_channel_info_cb,
+			.set_ies           = fst_wpa_supplicant_set_ies_cb,
+			.send_action       = fst_wpa_supplicant_send_action_cb,
+		};
+		wpa_s->fst = fst_attach(wpa_s->conf->fst_bond,
+				wpa_s->conf->fst_default, &iface_obj, wpa_s->ifname);
+		if (!wpa_s->fst) {
+			wpa_msg(wpa_s, MSG_ERROR, "Could not find FST %s",
+				wpa_s->conf->fst_bond);
+			return -1;
+		}
+		wpa_msg(wpa_s, MSG_DEBUG, "FST set: %s",
+			wpa_s->conf->fst_bond);
+	}
+#endif
+
 	if (wpas_wps_init(wpa_s))
 		return -1;
 
@@ -3559,6 +3627,17 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
 	wpas_ctrl_radio_work_flush(wpa_s);
 	radio_remove_interface(wpa_s);
 
+#ifdef CONFIG_FST
+	if (wpa_s->fst) {
+		fst_detach(wpa_s->fst);
+		wpa_s->fst = NULL;
+	}
+	if (wpa_s->received_mb_ies) {
+		wpabuf_free(wpa_s->received_mb_ies);
+		wpa_s->received_mb_ies = NULL;
+	}
+#endif
+
 	if (wpa_s->drv_priv)
 		wpa_drv_deinit(wpa_s);
 
@@ -3824,6 +3903,14 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
 
 	wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);
 
+#ifdef CONFIG_FST
+	if (fst_global_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize FST");
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+#endif
+
 	if (eloop_init()) {
 		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
 		wpa_supplicant_deinit(global);
@@ -3943,6 +4030,10 @@ void wpa_supplicant_deinit(struct wpa_global *global)
 
 	eloop_destroy();
 
+#ifdef CONFIG_FST
+	fst_global_deinit();
+#endif
+
 	if (global->params.pid_file) {
 		os_daemonize_terminate(global->params.pid_file);
 		os_free(global->params.pid_file);
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 9d3bf6d..874cf69 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -920,6 +920,26 @@ fast_reauth=1
 #  2: MCS 0-9
 #  3: not supported
 
+# Fast Session Transfer (FST)
+#
+# The options in this section are only available when the build configuration
+# option CONFIG_FST is set while compiling hostapd. They allow this interface
+# to be a part of FST setup.
+#
+# FST is the transfer of a session from a channel to another channel, in the
+# same or different frequency bands.
+#
+# For detals, see WGA Specification.
+#
+# Bonding to be used for FST operations
+##fst_bond=bond0
+#
+# Whether the interface is the FST default
+# Each fst_bond must have one and only one fst_default interface defined.
+# 0 = don't use this interface as FST default
+# 1 = use this interface as FST default
+#fst_default=1
+
 # Example blocks:
 
 # Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index bcdb4d0..d0eb599 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -811,6 +811,12 @@ struct wpa_supplicant {
 	struct wpa_radio_work *connect_work;
 
 	unsigned int ext_work_id;
+
+#ifdef CONFIG_FST
+	struct fst_iface *fst;
+	struct wpabuf    *fst_ies;
+	struct wpabuf    *received_mb_ies;
+#endif
 };
 
 
