Patchwork [2/3] Transparent FST: hostapd integration

login
register
mail settings
Submitter Anton Nayshtut
Date Feb. 17, 2014, 2:43 p.m.
Message ID <1392648201-7416-3-git-send-email-Anton.Nayshtut@Wilocity.com>
Download mbox | patch
Permalink /patch/321012/
State New
Headers show

Comments

Anton Nayshtut - Feb. 17, 2014, 2:43 p.m.
From: Anton Nayshtut  <Anton.Nayshtut@wilocity.com>

This patch integrates the FST into the hostapd.

Signed-off-by: Anton Nayshtut <Anton.Nayshtut@wilocity.com>
Signed-off-by: Erez Kirshenbaum <Erez.Kirshenbaum@wilocity.com>
---
 hostapd/config_file.c          | 17 +++++++++++++
 hostapd/defconfig              |  3 +++
 hostapd/hostapd.conf           | 20 +++++++++++++++
 hostapd/main.c                 | 25 ++++++++++++++++++-
 src/ap/ap_config.h             |  5 ++++
 src/ap/ap_drv_ops.c            | 15 +++++++++++
 src/ap/beacon.c                | 28 ++++++++++++++++++++-
 src/ap/drv_callbacks.c         | 27 ++++++++++++++++++++
 src/ap/hostapd.c               | 56 +++++++++++++++++++++++++++++++++++++++++-
 src/ap/hostapd.h               |  4 +++
 src/ap/ieee802_11.c            | 28 ++++++++++++++++++++-
 src/ap/sta_info.c              | 15 +++++++++++
 src/ap/sta_info.h              |  3 +++
 src/ap/utils.c                 | 12 ++++++++-
 src/common/ieee802_11_common.c | 34 +++++++++++++++++++++++++
 src/common/ieee802_11_common.h | 15 +++++++++++
 src/drivers/driver_nl80211.c   | 11 +++++++++
 17 files changed, 313 insertions(+), 5 deletions(-)

Patch

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 19d6ad3..2f3fc14 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2907,6 +2907,23 @@  static int hostapd_config_fill(struct hostapd_config *conf,
 					   "sae_groups value '%s'", line, pos);
 				return 1;
 			}
+#ifdef CONFIG_FST
+		} else if (os_strcmp(buf, "fst_bond") == 0) {
+			size_t len = os_strlen(pos);
+			if (!len || len > IFNAMSIZ) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "fst_bond value '%s'", line, pos);
+				errors++;
+			} else if (conf->fst_bond[0]) {
+				wpa_printf(MSG_ERROR, "Line %d: Duplicate "
+					   "fst_bond value '%s'", line, pos);
+				errors++;
+			} else
+				os_strlcpy(conf->fst_bond, pos,
+						sizeof(conf->fst_bond));
+		} else if (os_strcmp(buf, "fst_default") == 0) {
+			conf->fst_default = atoi(pos);
+#endif
 		} else {
 			wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
 				   "item '%s'", line, buf);
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 8c8f0ea..3132fe6 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -286,6 +286,9 @@  CONFIG_IPV6=y
 # Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
 #CONFIG_SQLITE=y
 
+# Enable Fast Session Transfer (FST)
+# CONFIG_FST=y
+
 # Testing options
 # This can be used to enable some testing options (see also the example
 # configuration file) that are really useful only for testing clients that
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index c503ce2..8504130 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1666,3 +1666,23 @@  own_ip_addr=127.0.0.1
 #bss=wlan0_1
 #bssid=00:13:10:95:fe:0b
 # ...
+
+##### Fast Session Transfer (FST) support #####################################
+#
+# 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
diff --git a/hostapd/main.c b/hostapd/main.c
index 3026929..e69c77d 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -27,7 +27,9 @@ 
 #include "config_file.h"
 #include "eap_register.h"
 #include "ctrl_iface.h"
-
+#ifdef CONFIG_FST
+#include "fst/fst.h"
+#endif
 
 struct hapd_global {
 	void **drv_priv;
@@ -654,6 +656,13 @@  int main(int argc, char *argv[])
 		return -1;
 	}
 
+#ifdef CONFIG_FST
+	if (fst_global_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initilize global FST context");
+		goto out;
+	}
+#endif
+
 	/* Allocate and parse configuration for full interface files */
 	for (i = 0; i < interfaces.count; i++) {
 		interfaces.iface[i] = hostapd_interface_init(&interfaces,
@@ -716,6 +725,13 @@  int main(int argc, char *argv[])
 			goto out;
 	}
 
+#ifdef CONFIG_FST
+	if (fst_global_start())	{
+		wpa_printf(MSG_ERROR, "Failed to start FST");
+		goto out;
+	}
+#endif
+
 	hostapd_global_ctrl_iface_init(&interfaces);
 
 	if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
@@ -727,6 +743,9 @@  int main(int argc, char *argv[])
 
  out:
 	hostapd_global_ctrl_iface_deinit(&interfaces);
+#ifdef CONFIG_FST
+	fst_global_stop();
+#endif
 	/* Deinitialize all interfaces */
 	for (i = 0; i < interfaces.count; i++)
 		hostapd_interface_deinit_free(interfaces.iface[i]);
@@ -741,6 +760,10 @@  int main(int argc, char *argv[])
 
 	os_free(bss_config);
 
+#ifdef CONFIG_FST
+	fst_global_deinit();
+#endif
+
 	os_program_deinit();
 
 	return ret;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 4631ca9..d9fc525 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -543,6 +543,11 @@  struct hostapd_config {
 	u8 vht_oper_centr_freq_seg0_idx;
 	u8 vht_oper_centr_freq_seg1_idx;
 
+#ifdef CONFIG_FST
+	char fst_bond[IFNAMSIZ + 1];
+	int fst_default;
+#endif
+
 #ifdef CONFIG_TESTING_OPTIONS
 	double ignore_probe_probability;
 	double ignore_auth_probability;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index e998fc6..de25cfc 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -172,6 +172,21 @@  int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
 	}
 #endif /* CONFIG_HS20 */
 
+#ifdef CONFIG_FST
+	if (hapd->iface->fst_ies) {
+		size_t add = wpabuf_len(hapd->iface->fst_ies);
+		if (wpabuf_resize(&beacon, add) < 0)
+			goto fail;
+		wpabuf_put_buf(beacon, hapd->iface->fst_ies);
+		if (wpabuf_resize(&proberesp, add) < 0)
+			goto fail;
+		wpabuf_put_buf(proberesp, hapd->iface->fst_ies);
+		if (wpabuf_resize(&assocresp, add) < 0)
+			goto fail;
+		wpabuf_put_buf(assocresp, hapd->iface->fst_ies);
+	}
+#endif
+
 	if (hapd->conf->vendor_elements) {
 		size_t add = wpabuf_len(hapd->conf->vendor_elements);
 		if (wpabuf_resize(&beacon, add) == 0)
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index b1ebf6e..b130d7b 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -27,7 +27,9 @@ 
 #include "ap_drv_ops.h"
 #include "beacon.h"
 #include "hs20.h"
-
+#ifdef CONFIG_FST
+#include "fst/fst.h"
+#endif
 
 #ifdef NEED_AP_MLME
 
@@ -279,6 +281,10 @@  static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 	if (hapd->p2p_probe_resp_ie)
 		buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
 #endif /* CONFIG_P2P */
+#ifdef CONFIG_FST
+	if (hapd->iface->fst_ies)
+		buflen += wpabuf_len(hapd->iface->fst_ies);
+#endif
 	if (hapd->conf->vendor_elements)
 		buflen += wpabuf_len(hapd->conf->vendor_elements);
 	resp = os_zalloc(buflen);
@@ -376,6 +382,14 @@  static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 	pos = hostapd_eid_hs20_indication(hapd, pos);
 #endif /* CONFIG_HS20 */
 
+#ifdef CONFIG_FST
+	if (hapd->iface->fst_ies) {
+		os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies),
+			wpabuf_len(hapd->iface->fst_ies));
+		pos += wpabuf_len(hapd->iface->fst_ies);
+	}
+#endif
+
 	if (hapd->conf->vendor_elements) {
 		os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
 			  wpabuf_len(hapd->conf->vendor_elements));
@@ -669,6 +683,11 @@  int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	if (hapd->p2p_beacon_ie)
 		tail_len += wpabuf_len(hapd->p2p_beacon_ie);
 #endif /* CONFIG_P2P */
+#ifdef CONFIG_FST
+	if (hapd->iface->fst_ies) {
+		tail_len += wpabuf_len(hapd->iface->fst_ies);
+	}
+#endif
 	if (hapd->conf->vendor_elements)
 		tail_len += wpabuf_len(hapd->conf->vendor_elements);
 	tailpos = tail = os_malloc(tail_len);
@@ -780,6 +799,13 @@  int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	    P2P_MANAGE)
 		tailpos = hostapd_eid_p2p_manage(hapd, tailpos);
 #endif /* CONFIG_P2P_MANAGER */
+#ifdef CONFIG_FST
+	if (hapd->iface->fst_ies) {
+		os_memcpy(tailpos, wpabuf_head(hapd->iface->fst_ies),
+			wpabuf_len(hapd->iface->fst_ies));
+		tailpos += wpabuf_len(hapd->iface->fst_ies);
+	}
+#endif
 
 #ifdef CONFIG_HS20
 	tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 9af9646..c546e82 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -31,6 +31,9 @@ 
 #include "hw_features.h"
 #include "dfs.h"
 
+#ifdef CONFIG_FST
+#include "fst/fst.h"
+#endif
 
 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
 			const u8 *req_ies, size_t req_ies_len, int reassoc)
@@ -131,6 +134,14 @@  int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
 		sta->hs20_ie = NULL;
 #endif /* CONFIG_HS20 */
 
+#ifdef CONFIG_FST
+	wpabuf_free(sta->mb_ies);
+	if (hapd->iface->fst) {
+		sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
+	} else
+		sta->mb_ies = NULL;
+#endif
+
 	if (hapd->conf->wpa) {
 		if (ie == NULL || ielen == 0) {
 #ifdef CONFIG_WPS
@@ -301,6 +312,15 @@  skip_wpa_check:
 	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
 	sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
 
+	if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
+	    sta->auth_alg == WLAN_AUTH_FT) {
+		/*
+		 * Open, static WEP, or FT protocol; no separate authorization
+		 * step.
+		 */
+		ap_sta_set_authorized(hapd, sta, 1);
+	}
+
 	if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
 		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
 	else
@@ -602,6 +622,13 @@  static void hostapd_action_rx(struct hostapd_data *hapd,
 		ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
 	}
 #endif /* CONFIG_WNM */
+#ifdef CONFIG_FST
+	if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) {
+		fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len);
+		return;
+	}
+#endif
+
 }
 
 
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index f9edf3b..477dccf 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -34,6 +34,9 @@ 
 #include "gas_serv.h"
 #include "dfs.h"
 
+#ifdef CONFIG_FST
+#include "fst/fst.h"
+#endif
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
 static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
@@ -533,7 +536,6 @@  static int hostapd_das_nas_mismatch(struct hostapd_data *hapd,
 	return 0;
 }
 
-
 static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
 					      struct radius_das_attrs *attr)
 {
@@ -1072,6 +1074,37 @@  static int setup_interface2(struct hostapd_iface *iface)
 	return hostapd_setup_interface_complete(iface, 0);
 }
 
+#ifdef CONFIG_FST
+static const u8 * fst_hostapd_get_bssid_cb(void *ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	return hapd->own_addr;
+}
+
+static void fst_hostapd_get_channel_info_cb(void *ctx,
+		enum hostapd_hw_mode *hw_mode, u8 *channel)
+{
+	struct hostapd_data *hapd = ctx;
+	*hw_mode = ieee80211_freq_to_chan(hapd->iface->freq, channel);
+}
+
+
+static void fst_hostapd_set_ies_cb(void *ctx, struct wpabuf *fst_ies)
+{
+	struct hostapd_data *hapd = ctx;
+	if (hapd->iface->fst_ies != fst_ies) {
+		hapd->iface->fst_ies = fst_ies;
+		ieee802_11_set_beacon(hapd);
+	}
+}
+
+static int fst_hostapd_send_action_cb(void *ctx, const u8 *da, struct wpabuf *buf)
+{
+	struct hostapd_data *hapd = ctx;
+	return hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
+			da, wpabuf_head(buf), wpabuf_len(buf));
+}
+#endif
 
 /**
  * hostapd_setup_interface_complete - Complete interface setup
@@ -1095,6 +1128,27 @@  int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
 		return -1;
 	}
 
+#ifdef CONFIG_FST
+	if (hapd->iconf->fst_bond[0]) {
+		struct fst_wpa_obj iface_obj = {
+			.ctx = hapd,
+			.get_bssid         = fst_hostapd_get_bssid_cb,
+			.get_channel_info  = fst_hostapd_get_channel_info_cb,
+			.set_ies           = fst_hostapd_set_ies_cb,
+			.send_action       = fst_hostapd_send_action_cb,
+		};
+		iface->fst = fst_attach(hapd->iconf->fst_bond,
+				hapd->iconf->fst_default, &iface_obj, hapd->conf->iface);
+		if (!iface->fst) {
+			wpa_printf(MSG_ERROR, "Could not attach to FST %s",
+					hapd->iconf->fst_bond);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "FST attached to %s (default=%d)",
+			hapd->iconf->fst_bond, hapd->iconf->fst_default);
+	}
+#endif
+
 	wpa_printf(MSG_DEBUG, "Completing interface initialization");
 	if (iface->conf->channel) {
 #ifdef NEED_AP_MLME
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 489ab16..866b96f 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -272,6 +272,10 @@  struct hostapd_iface {
 
 	unsigned int wait_channel_update:1;
 	unsigned int cac_started:1;
+#ifdef CONFIG_FST
+	struct fst_iface  *fst;
+	struct wpabuf     *fst_ies;
+#endif
 
 	int num_ap; /* number of entries in ap_list */
 	struct ap_info *ap_list; /* AP info list head */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 9251ac3..7c6cebc 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -38,7 +38,9 @@ 
 #include "ap_drv_ops.h"
 #include "wnm_ap.h"
 #include "ieee802_11.h"
-
+#ifdef CONFIG_FST
+#include "fst/fst.h"
+#endif
 
 u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
 {
@@ -1084,6 +1086,16 @@  static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
 		sta->hs20_ie = NULL;
 #endif /* CONFIG_HS20 */
 
+#ifdef CONFIG_FST
+	wpabuf_free(sta->mb_ies);
+	if (hapd->iface->fst) {
+		sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
+	}
+	else {
+		sta->mb_ies = NULL;
+	}
+#endif
+
 	return WLAN_STATUS_SUCCESS;
 }
 
@@ -1215,6 +1227,14 @@  static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 		p = hostapd_eid_p2p_manage(hapd, p);
 #endif /* CONFIG_P2P_MANAGER */
 
+#ifdef CONFIG_FST
+	if (hapd->iface->fst_ies) {
+		os_memcpy(p, wpabuf_head(hapd->iface->fst_ies),
+			wpabuf_len(hapd->iface->fst_ies));
+		p += wpabuf_len(hapd->iface->fst_ies);
+	}
+#endif
+
 	send_len += p - reply->u.assoc_resp.variable;
 
 	if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0)
@@ -1607,6 +1627,12 @@  static int handle_action(struct hostapd_data *hapd,
 		ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
 		return 1;
 #endif /* CONFIG_WNM */
+#ifdef CONFIG_FST
+	case WLAN_ACTION_FST:
+		if (hapd->iface->fst)
+			fst_rx_action(hapd->iface->fst, mgmt, len);
+		return 1;
+#endif /* CONFIG_FST */
 	case WLAN_ACTION_PUBLIC:
 	case WLAN_ACTION_PROTECTED_DUAL:
 		if (hapd->public_action_cb) {
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 24e764d..cd70436 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -31,6 +31,9 @@ 
 #include "ap_drv_ops.h"
 #include "gas_serv.h"
 #include "sta_info.h"
+#ifdef CONFIG_FST
+#include "fst/fst.h"
+#endif
 
 static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
 				       struct sta_info *sta);
@@ -259,6 +262,9 @@  void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 	wpabuf_free(sta->wps_ie);
 	wpabuf_free(sta->p2p_ie);
 	wpabuf_free(sta->hs20_ie);
+#ifdef CONFIG_FST
+	wpabuf_free(sta->mb_ies);
+#endif
 
 	os_free(sta->ht_capabilities);
 	os_free(sta->vht_capabilities);
@@ -962,6 +968,15 @@  void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
 		sta->flags &= ~WLAN_STA_AUTHORIZED;
 	}
 
+#ifdef CONFIG_FST
+	if (hapd->iface->fst) {
+		if (authorized)
+			fst_notify_peer_connected(hapd->iface->fst, sta->addr, sta->mb_ies);
+		else
+			fst_notify_peer_disconnected(hapd->iface->fst, sta->addr);
+	}
+#endif
+
 	if (hapd->sta_authorized_cb)
 		hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
 					sta->addr, authorized, dev_addr);
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 240b926..66db800 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -125,6 +125,9 @@  struct sta_info {
 	struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
 	struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
 	struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
+#ifdef CONFIG_FST
+	struct wpabuf *mb_ies; /* MB IEs from (Re)Association Request */
+#endif
 
 	struct os_reltime connected_time;
 
diff --git a/src/ap/utils.c b/src/ap/utils.c
index 931968c..b97bebb 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -12,7 +12,9 @@ 
 #include "common/ieee802_11_defs.h"
 #include "sta_info.h"
 #include "hostapd.h"
-
+#ifdef CONFIG_FST
+#include "fst/fst.h"
+#endif
 
 int hostapd_register_probereq_cb(struct hostapd_data *hapd,
 				 int (*cb)(void *ctx, const u8 *sa,
@@ -55,6 +57,14 @@  static int prune_associations(struct hostapd_iface *iface, void *ctx)
 		ohapd = iface->bss[j];
 		if (ohapd == data->hapd)
 			continue;
+#ifdef CONFIG_FST
+		/* Don't prune STAs belong to same FST */
+		if (ohapd->iface->fst &&
+			data->hapd->iface->fst &&
+			fst_are_ifaces_aggregated(ohapd->iface->fst,
+				data->hapd->iface->fst))
+			continue;
+#endif
 		osta = ap_get_sta(ohapd, data->addr);
 		if (!osta)
 			continue;
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 50bdc01..10afc17 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -285,6 +285,18 @@  ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
 			elems->ssid_list = pos;
 			elems->ssid_list_len = elen;
 			break;
+		case WLAN_EID_MULTI_BAND:
+			if (elems->mb_ies.nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
+				elems->mb_ies.ies[elems->mb_ies.nof_ies].ie = pos;
+				elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen;
+				++elems->mb_ies.nof_ies;
+			}
+			else {
+				wpa_printf(MSG_WARNING, "IEEE 802.11 element parse "
+					"ignored MB IE (id=%d elen=%d)",
+					id, elen);
+			}
+			break;
 		default:
 			unknown++;
 			if (!show_errors)
@@ -541,3 +553,25 @@  int supp_rates_11b_only(struct ieee802_11_elems *elems)
 
 	return num_11b > 0 && num_others == 0;
 }
+
+struct wpabuf *mb_ies_by_info(struct mb_ies_info *info)
+{
+	struct wpabuf *mb_ies = NULL;
+	WPA_ASSERT(info != NULL);
+	if (info->nof_ies) {
+		u8 i;
+		size_t mb_ies_size = 0;
+		for (i = 0; i < info->nof_ies; i++) {
+			mb_ies_size += info->ies[i].ie_len + 2;
+		}
+		mb_ies = wpabuf_alloc(mb_ies_size);
+		if (mb_ies) {
+			for (i = 0; i < info->nof_ies; i++) {
+				wpabuf_put_data(mb_ies,
+					info->ies[i].ie - 2,
+					info->ies[i].ie_len + 2);
+			}
+		}
+	}
+	return mb_ies;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 4fb2e84..62fcb1c 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -9,6 +9,18 @@ 
 #ifndef IEEE802_11_COMMON_H
 #define IEEE802_11_COMMON_H
 
+#define MAX_NOF_MB_IES_SUPPORTED 5
+
+struct mb_ies_info
+{
+	struct
+	{
+		const u8 *ie;
+		u8        ie_len;
+	} ies[MAX_NOF_MB_IES_SUPPORTED];
+	u8 nof_ies;
+};
+
 /* Parsed Information Elements */
 struct ieee802_11_elems {
 	const u8 *ssid;
@@ -69,6 +81,8 @@  struct ieee802_11_elems {
 	u8 hs20_len;
 	u8 ext_capab_len;
 	u8 ssid_list_len;
+
+	struct mb_ies_info mb_ies;
 };
 
 typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -95,5 +109,6 @@  int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
 enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
 
 int supp_rates_11b_only(struct ieee802_11_elems *elems);
+struct wpabuf *mb_ies_by_info(struct mb_ies_info *info);
 
 #endif /* IEEE802_11_COMMON_H */
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 32a371d..7d9ff25 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -3827,6 +3827,11 @@  static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
 	drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
 
 	if (drv->device_ap_sme && drv->use_monitor) {
+#ifdef CONFIG_FST
+		wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
+			   "with device_ap_sme due to FST");
+		drv->use_monitor = 0;
+#else
 		/*
 		 * Non-mac80211 drivers may not support monitor interface.
 		 * Make sure we do not get stuck with incorrect capability here
@@ -3838,6 +3843,7 @@  static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
 				   "support detected");
 			drv->use_monitor = 0;
 		}
+#endif
 	}
 
 	/*
@@ -4358,6 +4364,11 @@  static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 			ret = -1;
 	}
 #endif /* CONFIG_TDLS */
+#ifdef CONFIG_FST
+	/* FST Action frames */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
+		ret = -1;
+#endif /* CONFIG_FST */
 
 	/* FT Action frames */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)