[rdkb][common][bsp][Refactor and sync wifi from openwrt]

[Description]
a0c7684 [MAC80211][mt76][update mt76 patches]
a2e0f7c [MAC80211][core][Remove start disabled patch in eagle]
4562ef0 [MAC80211][hostapd][Refactor hostapd patch for git am]
22614f8 [mt76][Add vendor cmd to get available color bitmap]
b7b4fef [mac80211][Track obss color bitmap]
3f4ab41 [hostapd][Add hostapd_cli cmd to get available color bitmap]
cb120e7 [MAC80211][core][remove ba timer disabled patches]
24f983f [MAC80211][misc][sync iproute2 package]
3e866ee [MAC80211][core][Mark DFS channel available for CSA]
bdc6428 [MAC80211][hostapd][Mark DFS channel available for CSA]
9113e92 [MAC80211][app][Add eagle testmode iwpriv wrapper support]
d6bd8f4 [mac80211][mt76][Refactor mt76 patches]
7829a83 [MAC80211][mt76][Add monitor vif check in testmode]
19ead62 [mt76][eagle][hostapd mbssid and ema support]

[Release-log]

Change-Id: I75bf6ff01bc50054404bca23fd31cff9d1bc8d86
diff --git a/recipes-wifi/wpa-supplicant/files/patches/mtk-0010-hostapd-mtk-Add-DFS-detection-mode.patch b/recipes-wifi/wpa-supplicant/files/patches/mtk-0010-hostapd-mtk-Add-DFS-detection-mode.patch
index 2ceb639..7ec986a 100644
--- a/recipes-wifi/wpa-supplicant/files/patches/mtk-0010-hostapd-mtk-Add-DFS-detection-mode.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches/mtk-0010-hostapd-mtk-Add-DFS-detection-mode.patch
@@ -63,7 +63,7 @@
  					      char *buf, char *reply,
  					      int reply_size,
 @@ -4081,6 +4101,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
- 		reply_len = hostapd_ctrl_iface_get_hemu(hapd, reply, reply_size);
+ 		reply_len = hostapd_ctrl_iface_get_mu(hapd, reply, reply_size);
  	} else if (os_strncmp(buf, "GET_IBF", 7) == 0) {
  		reply_len = hostapd_ctrl_iface_get_ibf(hapd, reply, reply_size);
 +	} else if (os_strncmp(buf, "DFS_DETECT_MODE ", 16) == 0) {
diff --git a/recipes-wifi/wpa-supplicant/files/patches/mtk-0016-hostapd-mtk-Add-available-color-bitmap.patch b/recipes-wifi/wpa-supplicant/files/patches/mtk-0016-hostapd-mtk-Add-available-color-bitmap.patch
new file mode 100644
index 0000000..9bbbf87
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches/mtk-0016-hostapd-mtk-Add-available-color-bitmap.patch
@@ -0,0 +1,337 @@
+From e7790a1bceca6b7612f29b00c429cf23f5dd9e3a Mon Sep 17 00:00:00 2001
+From: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
+Date: Thu, 26 Jan 2023 09:16:00 +0800
+Subject: [PATCH] hostapd: mtk: Add available color bitmap
+
+Signed-off-by: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
+---
+ hostapd/ctrl_iface.c              | 74 +++++++++++++++++++++++++++++++
+ hostapd/hostapd_cli.c             | 18 ++++++++
+ src/ap/ap_drv_ops.c               | 10 ++++-
+ src/ap/ap_drv_ops.h               |  2 +
+ src/common/mtk_vendor.h           | 11 +++++
+ src/drivers/driver.h              |  8 ++++
+ src/drivers/driver_nl80211.c      | 66 +++++++++++++++++++++++++++
+ src/drivers/driver_nl80211.h      |  1 +
+ src/drivers/driver_nl80211_capa.c |  3 ++
+ 9 files changed, 192 insertions(+), 1 deletion(-)
+
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index 0ad8451..b0d5ded 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -3635,6 +3635,76 @@ hostapd_ctrl_iface_get_amsdu(struct hostapd_data *hapd, char *buf,
+ 	return ret;
+ }
+ 
++static int
++hostapd_ctrl_iface_get_bss_color(struct hostapd_data *hapd, char *buf,
++		size_t buflen)
++{
++	int ret;
++	char *pos, *end;
++	int i;
++
++	pos = buf;
++	end = buf + buflen;
++
++	if (hapd->iface->conf->he_op.he_bss_color_disabled)
++		ret = os_snprintf(buf, buflen, "BSS Color disabled\n");
++	else
++		ret = os_snprintf(buf, buflen, "BSS Color=%u\n",
++				  hapd->iface->conf->he_op.he_bss_color);
++
++	pos += ret;
++
++	return pos - buf;
++}
++
++
++static int
++hostapd_ctrl_iface_get_aval_color_bmp(struct hostapd_data *hapd, char *buf,
++		size_t buflen)
++{
++	int ret;
++	char *pos, *end;
++	int i;
++	u64 aval_color_bmp = 0;
++
++	hostapd_drv_get_aval_bss_color_bmp(hapd, &aval_color_bmp);
++	hapd->color_collision_bitmap = ~aval_color_bmp;
++
++	pos = buf;
++	end = buf + buflen;
++
++	ret = os_snprintf(buf, buflen,
++			"available color bitmap=0x%llx\n",
++			aval_color_bmp);
++	if (os_snprintf_error(end - pos, ret))
++		return pos - buf;
++	pos += ret;
++
++	for (i = 0; i < HE_OPERATION_BSS_COLOR_MAX; i++) {
++		int bit = !!((aval_color_bmp >> i) & 1LLU);
++
++		if (i % 8 == 0) {
++			ret = os_snprintf(pos, end - pos, "%2d: ", i);
++			if (os_snprintf_error(end - pos, ret))
++				return pos - buf;
++			pos += ret;
++		}
++
++		ret = os_snprintf(pos, end - pos, "%d ", bit);
++		if (os_snprintf_error(end - pos, ret))
++			return pos - buf;
++		pos += ret;
++
++		if (i % 8 == 7) {
++			ret = os_snprintf(pos, end - pos, "\n");
++			if (os_snprintf_error(end - pos, ret))
++				return pos - buf;
++			pos += ret;
++		}
++	}
++	return pos - buf;
++}
++
+ 
+ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ 					      char *buf, char *reply,
+@@ -4202,6 +4272,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ 		reply_len = hostapd_ctrl_iface_set_offchan_ctrl(hapd, buf + 16, reply, reply_size);
+ 	} else if (os_strncmp(buf, "GET_AMSDU", 9) == 0) {
+ 		reply_len = hostapd_ctrl_iface_get_amsdu(hapd, reply, reply_size);
++	} else if (os_strncmp(buf, "GET_BSS_COLOR", 13) == 0) {
++		reply_len = hostapd_ctrl_iface_get_bss_color(hapd, reply, reply_size);
++	} else if (os_strncmp(buf, "AVAL_COLOR_BMP", 14) == 0) {
++		reply_len = hostapd_ctrl_iface_get_aval_color_bmp(hapd, reply, reply_size);
+ 	} else {
+ 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+ 		reply_len = 16;
+diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
+index 30b3392..b6cf52e 100644
+--- a/hostapd/hostapd_cli.c
++++ b/hostapd/hostapd_cli.c
+@@ -1578,6 +1578,20 @@ static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc,
+ }
+ 
+ 
++static int hostapd_cli_cmd_get_bss_color(struct wpa_ctrl *ctrl, int argc,
++					  char *argv[])
++{
++	return wpa_ctrl_command(ctrl, "GET_BSS_COLOR");
++}
++
++
++static int hostapd_cli_cmd_get_aval_color_bmp(struct wpa_ctrl *ctrl, int argc,
++					  char *argv[])
++{
++	return wpa_ctrl_command(ctrl, "AVAL_COLOR_BMP");
++}
++
++
+ #ifdef ANDROID
+ static int hostapd_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
+ {
+@@ -1795,6 +1809,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
+ 	  "<addr> [req_mode=] <measurement request hexdump>  = send a Beacon report request to a station" },
+ 	{ "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL,
+ 	  "= reload wpa_psk_file only" },
++	{ "get_bss_color", hostapd_cli_cmd_get_bss_color, NULL,
++	  "= get current BSS color" },
++	{ "get_color_bmp", hostapd_cli_cmd_get_aval_color_bmp, NULL,
++	  "= get available BSS color bitmap" },
+ #ifdef ANDROID
+ 	{ "driver", hostapd_cli_cmd_driver, NULL,
+ 	  "<driver sub command> [<hex formatted data>] = send driver command data" },
+diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
+index 1a82f23..decffdd 100644
+--- a/src/ap/ap_drv_ops.c
++++ b/src/ap/ap_drv_ops.c
+@@ -1091,4 +1091,12 @@ int hostapd_drv_amsdu_dump(struct hostapd_data *hapd, u8 *amsdu)
+ 	if (!hapd->driver || !hapd->driver->amsdu_dump)
+ 		return 0;
+ 	return hapd->driver->amsdu_dump(hapd->drv_priv, amsdu);
+-}
+\ No newline at end of file
++}
++
++int hostapd_drv_get_aval_bss_color_bmp(struct hostapd_data *hapd, u64 *aval_color_bmp)
++{
++	if (!hapd->driver || !hapd->driver->get_aval_color_bmp ||
++	    hapd->iface->conf->he_op.he_bss_color_disabled)
++		return 0;
++	return hapd->driver->get_aval_color_bmp(hapd->drv_priv, aval_color_bmp);
++}
+diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
+index 4406666..61c1360 100644
+--- a/src/ap/ap_drv_ops.h
++++ b/src/ap/ap_drv_ops.h
+@@ -149,6 +149,8 @@ int hostapd_drv_ibf_ctrl(struct hostapd_data *hapd);
+ int hostapd_drv_ibf_dump(struct hostapd_data *hapd, u8 *ibf_enable);
+ int hostapd_drv_amsdu_ctrl(struct hostapd_data *hapd);
+ int hostapd_drv_amsdu_dump(struct hostapd_data *hapd, u8 *amsdu);
++int hostapd_drv_get_aval_bss_color_bmp(struct hostapd_data *hapd,
++				       u64 *aval_color_bmp);
+ 
+ #include "drivers/driver.h"
+ 
+diff --git a/src/common/mtk_vendor.h b/src/common/mtk_vendor.h
+index 0999ea9..f2afb2e 100644
+--- a/src/common/mtk_vendor.h
++++ b/src/common/mtk_vendor.h
+@@ -15,6 +15,7 @@ enum mtk_nl80211_vendor_subcmds {
+ 	MTK_NL80211_VENDOR_SUBCMD_EDCCA_CTRL = 0xc7,
+ 	MTK_NL80211_VENDOR_SUBCMD_3WIRE_CTRL = 0xc8,
+ 	MTK_NL80211_VENDOR_SUBCMD_IBF_CTRL = 0xc9,
++	MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL = 0xca,
+ };
+ 
+ enum mtk_vendor_attr_edcca_ctrl {
+@@ -252,6 +253,16 @@ ibf_dump_policy[NUM_MTK_VENDOR_ATTRS_IBF_DUMP] = {
+ 	[MTK_VENDOR_ATTR_IBF_DUMP_ENABLE] = { .type = NLA_U8 },
+ };
+ 
++enum mtk_vendor_attr_bss_color_ctrl {
++	MTK_VENDOR_ATTR_BSS_COLOR_CTRL_UNSPEC,
++
++	MTK_VENDOR_ATTR_AVAL_BSS_COLOR_BMP,
++
++	/* keep last */
++	NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL,
++	MTK_VENDOR_ATTR_BSS_COLOR_CTRL_MAX =
++		NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL - 1
++};
+ 
+ #define CSI_MAX_COUNT 256
+ #define ETH_ALEN 6
+diff --git a/src/drivers/driver.h b/src/drivers/driver.h
+index b07aaf3..266c630 100644
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -4736,6 +4736,14 @@ struct wpa_driver_ops {
+ 	 */
+ 	int (*amsdu_ctrl)(void *priv, u8 amsdu);
+ 	int (*amsdu_dump)(void *priv, u8 *amsdu);
++
++	/**
++	 * get_aval_color_bmp - get available BSS color bitmap
++	 * @priv: Private driver interface data
++	 * @aval_color_bmp: available bss color bitmap
++	 *
++	 */
++	int (*get_aval_color_bmp)(void *priv, u64 *aval_color_bmp);
+ };
+ 
+ /**
+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
+index 6702384..c8771f7 100644
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -12433,6 +12433,71 @@ static int nl80211_dpp_listen(void *priv, bool enable)
+ }
+ #endif /* CONFIG_DPP */
+ 
++static int nl80211_get_aval_color_bmp_handler(struct nl_msg *msg, void *arg)
++{
++	u64 *aval_color_bmp = arg;
++	struct nlattr *tb[NL80211_ATTR_MAX + 1];
++	struct nlattr *tb_vendor[MTK_VENDOR_ATTR_BSS_COLOR_CTRL_MAX + 1];
++	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
++	struct nlattr *nl_vend, *attr;
++
++	static const struct nla_policy
++	bss_color_ctrl_policy[NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL + 1] = {
++		[MTK_VENDOR_ATTR_AVAL_BSS_COLOR_BMP] = { .type = NLA_U64 },
++	};
++
++	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
++			genlmsg_attrlen(gnlh, 0), NULL);
++
++	nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
++	if (!nl_vend)
++		return NL_SKIP;
++
++	nla_parse(tb_vendor, MTK_VENDOR_ATTR_BSS_COLOR_CTRL_MAX,
++			nla_data(nl_vend), nla_len(nl_vend), NULL);
++
++	*aval_color_bmp = nla_get_u64(tb_vendor[MTK_VENDOR_ATTR_AVAL_BSS_COLOR_BMP]);
++
++	return 0;
++}
++
++static int nl80211_get_aval_color_bmp(void *priv, u64 *aval_color_bmp)
++{
++	struct i802_bss *bss = priv;
++	struct wpa_driver_nl80211_data *drv = bss->drv;
++	struct nl_msg *msg;
++	struct nlattr *attr;
++	int ret;
++
++	if (!drv->mtk_bss_color_vendor_cmd_avail) {
++		wpa_printf(MSG_INFO,
++			   "nl80211: Driver does not support BSS COLOR vendor cmd");
++		return 0;
++	}
++
++	if (!(msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_VENDOR)) ||
++	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_MTK) ||
++	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
++			MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL))
++		return -ENOBUFS;
++
++	attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
++	if (!attr) {
++		nlmsg_free(msg);
++		return -1;
++	}
++
++	nla_nest_end(msg, attr);
++
++	ret = send_and_recv_msgs(drv, msg,
++		nl80211_get_aval_color_bmp_handler, aval_color_bmp, NULL, NULL);
++
++	if (ret) {
++		wpa_printf(MSG_ERROR, "Failed to send BSS COLOR vendor cmd. ret=%d (%s) ",
++			   ret, strerror(-ret));
++	}
++	return ret;
++}
+ 
+ #ifdef CONFIG_TESTING_OPTIONS
+ 
+@@ -13073,4 +13138,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+ 	.start_disabled = nl80211_start_disabled,
+ 	.amsdu_ctrl = nl80211_enable_amsdu,
+ 	.amsdu_dump = nl80211_dump_amsdu,
++	.get_aval_color_bmp = nl80211_get_aval_color_bmp,
+ };
+diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
+index e570224..b90c8fa 100644
+--- a/src/drivers/driver_nl80211.h
++++ b/src/drivers/driver_nl80211.h
+@@ -186,6 +186,7 @@ struct wpa_driver_nl80211_data {
+ 	unsigned int mtk_3wire_vendor_cmd_avail:1;
+ 	unsigned int mtk_ibf_vendor_cmd_avail:1;
+ 	unsigned int mtk_wireless_vendor_cmd_avail:1;
++	unsigned int mtk_bss_color_vendor_cmd_avail:1;
+ 
+ 	u64 vendor_scan_cookie;
+ 	u64 remain_on_chan_cookie;
+diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
+index fcfa68b..c3c7b41 100644
+--- a/src/drivers/driver_nl80211_capa.c
++++ b/src/drivers/driver_nl80211_capa.c
+@@ -1068,6 +1068,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+ 				case MTK_NL80211_VENDOR_SUBCMD_WIRELESS_CTRL:
+ 					drv->mtk_wireless_vendor_cmd_avail = 1;
+ 					break;
++				case MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL :
++					drv->mtk_bss_color_vendor_cmd_avail = 1;
++					break;
+ 				}
+ 			}
+ 
+-- 
+2.39.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches/mtk-0020-hostapd-mtk-Mark-DFS-channel-as-available-for-CSA.patch b/recipes-wifi/wpa-supplicant/files/patches/mtk-0020-hostapd-mtk-Mark-DFS-channel-as-available-for-CSA.patch
new file mode 100644
index 0000000..1fe5c88
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches/mtk-0020-hostapd-mtk-Mark-DFS-channel-as-available-for-CSA.patch
@@ -0,0 +1,60 @@
+From 3e9500a42a41e8cd7c2d7bc20aba96e1e17161fb Mon Sep 17 00:00:00 2001
+From: "himanshu.goyal" <himanshu.goyal@mediatek.com>
+Date: Fri, 3 Mar 2023 12:45:42 +0800
+Subject: [PATCH] hostapd: mtk: Mark DFS channel as available for CSA.
+
+---
+ hostapd/ctrl_iface.c   | 10 ++++++++++
+ hostapd/hostapd_cli.c  |  2 +-
+ src/ap/ctrl_iface_ap.c |  1 +
+ 3 files changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index c33b7a4..9ba6992 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -2704,6 +2704,16 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
+ 		settings.freq_params.he_enabled = iface->conf->ieee80211ax;
+ 	}
+ 
++	if (settings.freq_params.radar_background) {
++		hostapd_dfs_sta_update_state(iface,
++			settings.freq_params.freq,
++			settings.freq_params.ht_enabled,
++			settings.freq_params.sec_channel_offset,
++			bandwidth, settings.freq_params.center_freq1,
++			settings.freq_params.center_freq2,
++			HOSTAPD_CHAN_DFS_AVAILABLE);
++	}
++
+ 	if (settings.freq_params.center_freq1)
+ 		dfs_range += hostapd_is_dfs_overlap(
+ 			iface, bandwidth, settings.freq_params.center_freq1);
+diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
+index 0da18e2..6231e51 100644
+--- a/hostapd/hostapd_cli.c
++++ b/hostapd/hostapd_cli.c
+@@ -1693,7 +1693,7 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
+ 	  "<addr> = send QoS Map Configure frame" },
+ 	{ "chan_switch", hostapd_cli_cmd_chan_switch, NULL,
+ 	  "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n"
+-	  "  [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n"
++	  "  [center_freq2=] [bandwidth=] [blocktx] [ht|vht] [skip_cac]\n"
+ 	  "  = initiate channel switch announcement" },
+ 	{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL,
+ 	  "<addr> <url>\n"
+diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
+index 18bae5c..2fae590 100644
+--- a/src/ap/ctrl_iface_ap.c
++++ b/src/ap/ctrl_iface_ap.c
+@@ -938,6 +938,7 @@ int hostapd_parse_csa_settings(const char *pos,
+ 	settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
+ 	settings->freq_params.he_enabled = !!os_strstr(pos, " he");
+ 	settings->freq_params.eht_enabled = !!os_strstr(pos, " eht");
++	settings->freq_params.radar_background = !!os_strstr(pos, " skip_cac");
+ 	settings->block_tx = !!os_strstr(pos, " blocktx");
+ #undef SET_CSA_SETTING
+ 
+-- 
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches/mtk-0020-hostapd-mtk-add-11v_mbss-and-ema-support.patch b/recipes-wifi/wpa-supplicant/files/patches/mtk-0020-hostapd-mtk-add-11v_mbss-and-ema-support.patch
new file mode 100644
index 0000000..8d59a0f
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches/mtk-0020-hostapd-mtk-add-11v_mbss-and-ema-support.patch
@@ -0,0 +1,1175 @@
+From 8cbdb9a59e3bbe8804f909b13ce6df6e2777c3da Mon Sep 17 00:00:00 2001
+From: mtk20656 <chank.chen@mediatek.com>
+Date: Thu, 2 Mar 2023 10:51:43 +0800
+Subject: [PATCH] hostapd: mtk: add 11v_mbss and ema support for hostapd
+
+Signed-off-by: mtk20656 <chank.chen@mediatek.com>
+---
+ hostapd/config_file.c             |   9 +
+ hostapd/hostapd.conf              |  58 +++++++
+ hostapd/main.c                    |   3 +
+ src/ap/ap_config.c                |  12 ++
+ src/ap/ap_config.h                |   6 +
+ src/ap/beacon.c                   | 124 ++++++++++++--
+ src/ap/hostapd.c                  |  72 +++++++-
+ src/ap/hostapd.h                  |   7 +
+ src/ap/ieee802_11.c               | 276 +++++++++++++++++++++++++++++-
+ src/ap/ieee802_11.h               |   7 +-
+ src/ap/ieee802_11_shared.c        |  11 ++
+ src/common/ieee802_11_common.c    |   4 +
+ src/common/ieee802_11_common.h    |   3 +
+ src/common/ieee802_11_defs.h      |   5 +
+ src/drivers/driver.h              |  42 +++++
+ src/drivers/driver_nl80211.c      |  52 ++++++
+ src/drivers/driver_nl80211_capa.c |  27 +++
+ 17 files changed, 698 insertions(+), 20 deletions(-)
+
+diff --git a/hostapd/config_file.c b/hostapd/config_file.c
+index 649618b..3f26191 100644
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -3663,6 +3663,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
+ 			return 1;
+ 		}
+ 		bss->unsol_bcast_probe_resp_interval = val;
++	} else if (os_strcmp(buf, "mbssid") == 0) {
++		int mbssid = atoi(pos);
++		if (mbssid < 0 || mbssid > ENHANCED_MBSSID_ENABLED) {
++			wpa_printf(MSG_ERROR,
++				   "Line %d: invalid mbssid (%d): '%s'.",
++				   line, mbssid, pos);
++			return 1;
++		}
++		conf->mbssid = mbssid;
+ 	} else if (os_strcmp(buf, "mu_onoff") == 0) {
+ 		int val = atoi(pos);
+ 		if (val < 0 || val > 15) {
+diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
+index e3a5eb3..f926029 100644
+--- a/hostapd/hostapd.conf
++++ b/hostapd/hostapd.conf
+@@ -3123,3 +3123,61 @@ own_ip_addr=127.0.0.1
+ #bss=wlan0_1
+ #bssid=00:13:10:95:fe:0b
+ # ...
++#
++# Multiple BSSID Advertisement in 802.11ax
++# IEEE Std 802.11ax-2021 added a feature where instead of multiple interfaces
++# on a common radio transmitting individual beacons, those can form a set with
++# a common beacon is transmitted for all. The interface which is brought up
++# first is called as the transmitting profile of the MBSSID set which transmits
++# the beacons. The remaining interfaces are called as the non-transmitting
++# profiles and these are advertised inside the multiple BSSID element in the
++# beacons and probe response frames.
++# The transmitting interface is visible to all clients in the vicinity, however
++# the clients which do not support parsing of the multiple BSSID element will
++# not be able to connect to the non-transmitting interfaces.
++#
++# Enhanced Multiple BSSID Advertisements (EMA)
++# When enabled, the non-transmitting interfaces are split into multiple
++# beacons. The number of beacons required to cover all the non-transmitting
++# profiles is called as the profile periodicity.
++#
++# Refer to IEEE Std 802.11-2020 for details regarding the procedure and
++# required MAC address assignment.
++#
++# Following configuration is per radio.
++# 0 = Disabled (Default)
++# 1 = Multiple BSSID advertisements enabled.
++# 2 = Enhanced multiple BSSID advertisements enabled.
++#mbssid=0
++#
++# The transmitting interface should be added with 'interface' option while
++# the non-transmitting interfaces should be added using 'bss' option.
++# Security configuration should be added separately per interface, if required.
++#
++# Example:
++#mbssid=2
++#interface=wlan2
++#ctrl_interface=/var/run/hostapd
++#wpa_passphrase=0123456789
++#ieee80211w=2
++#sae_pwe=1
++#auth_algs=1
++#wpa=2
++#wpa_pairwise=CCMP
++#ssid=<SSID-0>
++#bridge=br-lan
++#wpa_key_mgmt=SAE
++#bssid=00:03:7f:12:84:84
++#
++#bss=wlan2-1
++#ctrl_interface=/var/run/hostapd
++#wpa_passphrase=0123456789
++#ieee80211w=2
++#sae_pwe=1
++#auth_algs=1
++#wpa=2
++#wpa_pairwise=CCMP
++#ssid=<SSID-1>
++#bridge=br-lan
++#wpa_key_mgmt=SAE
++#bssid=00:03:7f:12:84:85
+diff --git a/hostapd/main.c b/hostapd/main.c
+index 70a4b32..1b6474a 100644
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -253,6 +253,9 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
+ 				wpa_printf(MSG_ERROR, "set_wowlan failed");
+ 		}
+ 		os_free(triggs);
++
++		iface->mbssid_max_interfaces = capa.mbssid_max_interfaces;
++		iface->ema_max_periodicity = capa.ema_max_periodicity;
+ 	}
+ 
+ 	return 0;
+diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
+index 4e46a62..7d9d5cb 100644
+--- a/src/ap/ap_config.c
++++ b/src/ap/ap_config.c
+@@ -1462,6 +1462,12 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
+ 	}
+ #endif /* CONFIG_IEEE80211BE */
+ 
++	if (full_config && bss->ignore_broadcast_ssid && conf->mbssid) {
++		wpa_printf(MSG_ERROR,
++			   "Hidden SSID is not suppored when MBSSID is enabled");
++		return -1;
++	}
++
+ 	return 0;
+ }
+ 
+@@ -1545,6 +1551,12 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
+ 	}
+ #endif /* CONFIG_IEEE80211BE */
+ 
++	if (full_config && conf->mbssid && !conf->ieee80211ax) {
++		wpa_printf(MSG_ERROR,
++			   "Cannot enable multiple BSSID support without ieee80211ax");
++		return -1;
++	}
++
+ 	for (i = 0; i < conf->num_bss; i++) {
+ 		if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
+ 			return -1;
+diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
+index 7aeb176..51476b8 100644
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
+@@ -923,6 +923,8 @@ struct hostapd_bss_config {
+ 	u8 ext_capa[EXT_CAPA_MAX_LEN];
+ 
+ 	u8 rnr;
++
++	bool xrates_supported;
+ };
+ 
+ /**
+@@ -1163,6 +1165,10 @@ struct hostapd_config {
+ 	u8 ibf_enable;
+ 	u8 dfs_detect_mode;
+ 	u8 amsdu;
++
++#define MBSSID_ENABLED          1
++#define ENHANCED_MBSSID_ENABLED 2
++	u8 mbssid;
+ };
+ 
+ enum three_wire_mode {
+diff --git a/src/ap/beacon.c b/src/ap/beacon.c
+index f3ea5c2..51db23a 100644
+--- a/src/ap/beacon.c
++++ b/src/ap/beacon.c
+@@ -462,15 +462,77 @@ static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
+ }
+ 
+ 
++static int ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd,
++					     struct wpa_driver_ap_params *params,
++					     u8 **eid)
++{
++	struct hostapd_iface *iface = hapd->iface;
++	struct hostapd_data *tx_bss;
++	size_t len;
++	u8 elem_count = 0, *elem = NULL, **elem_offset = NULL, *end;
++	u8 *tailpos = *eid;
++
++	if (!iface->mbssid_max_interfaces ||
++	    iface->num_bss > iface->mbssid_max_interfaces ||
++	    (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED &&
++	     !iface->ema_max_periodicity))
++		goto fail;
++
++	tx_bss = hostapd_mbssid_get_tx_bss(hapd);
++	len = hostapd_eid_mbssid_len(tx_bss, WLAN_FC_STYPE_BEACON, &elem_count,
++				     NULL, 0);
++	if (!len || (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED &&
++		     elem_count > iface->ema_max_periodicity))
++		goto fail;
++
++	elem = os_zalloc(len);
++	if (!elem)
++		goto fail;
++
++	elem_offset = os_zalloc(elem_count * sizeof(u8 *));
++	if (!elem_offset)
++		goto fail;
++
++	end = hostapd_eid_mbssid(tx_bss, elem, elem + len, WLAN_FC_STYPE_BEACON,
++				 elem_count, elem_offset, NULL, 0);
++
++	params->mbssid_tx_iface = tx_bss->conf->iface;
++	params->mbssid_index = hostapd_mbssid_get_bss_index(hapd);
++	params->mbssid_elem = elem;
++	params->mbssid_elem_len = end - elem;
++	params->mbssid_elem_count = elem_count;
++	params->mbssid_elem_offset = elem_offset;
++	if (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED) {
++		params->ema = true;
++		*tailpos++ = WLAN_EID_EXTENSION;
++		*tailpos++ = 3;
++		*tailpos++ = WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION;
++		*tailpos++ = iface->num_bss;
++		*tailpos++ = params->mbssid_elem_count;
++		*eid = tailpos;
++	}
++
++	return 0;
++
++fail:
++	os_free(elem);
++	wpa_printf(MSG_ERROR, "MBSSID: Configuration failed");
++	return -1;
++}
++
++
+ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
+ 				   const struct ieee80211_mgmt *req,
+ 				   int is_p2p, size_t *resp_len,
+-				   bool bcast_probe_resp)
++				   bool bcast_probe_resp, const u8 *known_bss,
++				   u8 known_bss_len)
+ {
+ 	struct ieee80211_mgmt *resp;
+-	u8 *pos, *epos, *csa_pos;
++	u8 *pos, *epos, *csa_pos, *ext_cap_pos;
+ 	size_t buflen;
+ 
++	hapd = hostapd_mbssid_get_tx_bss(hapd);
++
+ #define MAX_PROBERESP_LEN 768
+ 	buflen = MAX_PROBERESP_LEN;
+ #ifdef CONFIG_WPS
+@@ -517,6 +579,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
+ 	}
+ #endif /* CONFIG_IEEE80211BE */
+ 
++	buflen += hostapd_eid_mbssid_len(hapd, WLAN_FC_STYPE_PROBE_RESP, NULL,
++					 known_bss, known_bss_len);
+ 	buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP);
+ 	buflen += hostapd_mbo_ie_len(hapd);
+ 	buflen += hostapd_eid_owe_trans_len(hapd);
+@@ -588,8 +652,16 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
+ 	pos = hostapd_eid_supported_op_classes(hapd, pos);
+ 	pos = hostapd_eid_ht_capabilities(hapd, pos);
+ 	pos = hostapd_eid_ht_operation(hapd, pos);
++	pos = hostapd_eid_mbssid(hapd, pos, epos, WLAN_FC_STYPE_PROBE_RESP, 0,
++				 NULL, known_bss, known_bss_len);
+ 
++	ext_cap_pos = pos;
+ 	pos = hostapd_eid_ext_capab(hapd, pos);
++	if (hapd->iconf->mbssid >= MBSSID_ENABLED && !known_bss_len)
++		ext_cap_pos[12] |= 0x01; /* Probe responses always include all
++					  * non-tx profiles except when a list
++					  * of known BSSes is included in the
++					  * probe request. */
+ 
+ 	pos = hostapd_eid_time_adv(hapd, pos);
+ 	pos = hostapd_eid_time_zone(hapd, pos);
+@@ -1153,16 +1225,23 @@ void handle_probe_req(struct hostapd_data *hapd,
+ 	}
+ #endif /* CONFIG_TESTING_OPTIONS */
+ 
++	/* Do not send probe response from a non-transmitting multiple BSSID
++	 * profile unless the probe request is directed at that paticular BSS */
++	if (hapd != hostapd_mbssid_get_tx_bss(hapd) && res != EXACT_SSID_MATCH)
++		return;
++
+ 	wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR
+ 		     " signal=%d", MAC2STR(mgmt->sa), ssi_signal);
+ 
+ 	if (is_6ghz_op_class(hapd->iconf->op_class) &&
+ 	    is_broadcast_ether_addr(mgmt->da))
+ 		resp = hostapd_gen_probe_resp(hapd, NULL, elems.p2p != NULL,
+-					      &resp_len, true);
++					      &resp_len, false, elems.mbssid_known_bss,
++					      elems.mbssid_known_bss_len);
+ 	else
+ 		resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
+-					      &resp_len, false);
++					      &resp_len, false, elems.mbssid_known_bss,
++					      elems.mbssid_known_bss_len);
+ 	if (resp == NULL)
+ 		return;
+ 
+@@ -1184,7 +1263,8 @@ void handle_probe_req(struct hostapd_data *hapd,
+ 				hapd->cs_c_off_ecsa_proberesp;
+ 	}
+ 
+-	ret = hostapd_drv_send_mlme(hapd, resp, resp_len, noack,
++	ret = hostapd_drv_send_mlme(hostapd_mbssid_get_tx_bss(hapd), resp,
++				    resp_len, noack,
+ 				    csa_offs_len ? csa_offs : NULL,
+ 				    csa_offs_len, 0);
+ 
+@@ -1231,7 +1311,7 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
+ 			   "this");
+ 
+ 	/* Generate a Probe Response template for the non-P2P case */
+-	return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, false);
++	return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, false, NULL, 0);
+ }
+ 
+ #endif /* NEED_AP_MLME */
+@@ -1250,7 +1330,7 @@ static u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
+ 
+ 	return hostapd_gen_probe_resp(hapd, NULL, 0,
+ 				      &params->unsol_bcast_probe_resp_tmpl_len,
+-				      true);
++				      true, NULL, 0);
+ }
+ #endif /* CONFIG_IEEE80211AX */
+ 
+@@ -1533,8 +1613,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
+ 	size_t resp_len = 0;
+ #ifdef NEED_AP_MLME
+ 	u16 capab_info;
+-	u8 *pos, *tailpos, *tailend, *csa_pos;
++	u8 *pos, *tailpos, *tailend, *csa_pos, *ext_cap_pos;
++#endif /* NEED_AP_MLME */
+ 
++	os_memset(params, 0, sizeof(*params));
++
++#ifdef NEED_AP_MLME
+ #define BEACON_HEAD_BUF_SIZE 256
+ #define BEACON_TAIL_BUF_SIZE 512
+ 	head = os_zalloc(BEACON_HEAD_BUF_SIZE);
+@@ -1586,6 +1670,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
+ 	}
+ #endif /* CONFIG_IEEE80211BE */
+ 
++	if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
++	    hapd == hostapd_mbssid_get_tx_bss(hapd))
++		tail_len += 5; /* Multiple BSSID Configuration element */
+ 	tail_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_BEACON);
+ 	tail_len += hostapd_mbo_ie_len(hapd);
+ 	tail_len += hostapd_eid_owe_trans_len(hapd);
+@@ -1671,9 +1758,23 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
+ 	tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
+ 	tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
+ 	tailpos = hostapd_eid_ht_operation(hapd, tailpos);
+-
++	ext_cap_pos = tailpos;
+ 	tailpos = hostapd_eid_ext_capab(hapd, tailpos);
+ 
++	if (hapd->iconf->mbssid && hapd->iconf->num_bss > 1) {
++		if (ieee802_11_build_ap_params_mbssid(hapd, params, &tailpos)) {
++			os_free(head);
++			os_free(tail);
++			wpa_printf(MSG_ERROR, "Failed to set beacon data");
++			return -1;
++		} else if (hapd->iconf->mbssid == MBSSID_ENABLED ||
++			   (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
++			   params->mbssid_elem_count == 1)) {
++			/* Set the extended capability bit for "complete list
++			 * of non-tx profiles" */
++			ext_cap_pos[12] |= 0x01;
++		}
++	}
+ 	/*
+ 	 * TODO: Time Advertisement element should only be included in some
+ 	 * DTIM Beacon frames.
+@@ -1794,7 +1895,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
+ 	resp = hostapd_probe_resp_offloads(hapd, &resp_len);
+ #endif /* NEED_AP_MLME */
+ 
+-	os_memset(params, 0, sizeof(*params));
+ 	params->head = (u8 *) head;
+ 	params->head_len = head_len;
+ 	params->tail = tail;
+@@ -1897,6 +1997,10 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
+ 	params->head = NULL;
+ 	os_free(params->proberesp);
+ 	params->proberesp = NULL;
++	os_free(params->mbssid_elem);
++	params->mbssid_elem = NULL;
++	os_free(params->mbssid_elem_offset);
++	params->mbssid_elem_offset = NULL;
+ #ifdef CONFIG_FILS
+ 	os_free(params->fd_frame_tmpl);
+ 	params->fd_frame_tmpl = NULL;
+diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
+index 42e8ed7..82cc155 100644
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -91,6 +91,29 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
+ }
+ 
+ 
++struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd)
++{
++	if (hapd->iconf->mbssid)
++		return hapd->iface->bss[0];
++
++	return hapd;
++}
++
++
++int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd)
++{
++	if (hapd->iconf->mbssid) {
++		size_t i;
++
++		for (i = 1; i < hapd->iface->num_bss; i++)
++			if (hapd->iface->bss[i] == hapd)
++				return i;
++	}
++
++	return 0;
++}
++
++
+ void hostapd_reconfig_encryption(struct hostapd_data *hapd)
+ {
+ 	if (hapd->wpa_auth)
+@@ -1179,19 +1202,37 @@ static int db_table_create_radius_attributes(sqlite3 *db)
+ 
+ #endif /* CONFIG_NO_RADIUS */
+ 
++static int hostapd_start_beacon(struct hostapd_data *hapd)
++{
++	struct hostapd_bss_config *conf = hapd->conf;
++
++	if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
++		return -1;
++
++	if (hapd->driver && hapd->driver->set_operstate)
++		hapd->driver->set_operstate(hapd->drv_priv, 1);
++
++	return 0;
++}
+ 
+ /**
+  * hostapd_setup_bss - Per-BSS setup (initialization)
+  * @hapd: Pointer to BSS data
+  * @first: Whether this BSS is the first BSS of an interface; -1 = not first,
+  *	but interface may exist
++ * @start_beacon: Whether beacons should be configured and transmission started
++ *	at this time. This is used when MBSSID IE is enabled where the
++ *	information regarding all BSSes should be retrieved before configuring
++ *	the beacons. The calling functions are responsible to configure the
++ *	beacon explicitly if this is set to 'false'.
+  *
+  * This function is used to initialize all per-BSS data structures and
+  * resources. This gets called in a loop for each BSS when an interface is
+  * initialized. Most of the modules that are initialized here will be
+  * deinitialized in hostapd_cleanup().
+  */
+-static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
++static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
++			     bool start_beacon)
+ {
+ 	struct hostapd_bss_config *conf = hapd->conf;
+ 	u8 ssid[SSID_MAX_LEN + 1];
+@@ -1464,9 +1505,6 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
+ 		return -1;
+ 	}
+ 
+-	if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
+-		return -1;
+-
+ 	if (flush_old_stations && !conf->start_disabled &&
+ 	    conf->broadcast_deauth) {
+ 		u8 addr[ETH_ALEN];
+@@ -1485,8 +1523,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
+ 	if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
+ 		return -1;
+ 
+-	if (hapd->driver && hapd->driver->set_operstate)
+-		hapd->driver->set_operstate(hapd->drv_priv, 1);
++	if (start_beacon)
++		return hostapd_start_beacon(hapd);
+ 
+ 	hostapd_ubus_add_bss(hapd);
+ 
+@@ -2214,7 +2252,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
+ 		hapd = iface->bss[j];
+ 		if (j)
+ 			os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
+-		if (hostapd_setup_bss(hapd, j == 0)) {
++		if (hostapd_setup_bss(hapd, j == 0, !iface->conf->mbssid)) {
+ 			for (;;) {
+ 				hapd = iface->bss[j];
+ 				hostapd_bss_deinit_no_free(hapd);
+@@ -2228,6 +2266,24 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
+ 		if (is_zero_ether_addr(hapd->conf->bssid))
+ 			prev_addr = hapd->own_addr;
+ 	}
++
++	if (hapd->iconf->mbssid) {
++		for (j = 0; j < iface->num_bss; j++) {
++			hapd = iface->bss[j];
++			if (hostapd_start_beacon(hapd)) {
++				for (;;) {
++					hapd = iface->bss[j];
++					hostapd_bss_deinit_no_free(hapd);
++					hostapd_free_hapd_data(hapd);
++					if (j == 0)
++						break;
++					j--;
++				}
++				goto fail;
++			}
++		}
++	}
++
+ 	hapd = iface->bss[0];
+ 
+ 	hostapd_tx_queue_params(iface);
+@@ -3130,7 +3186,7 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
+ 
+ 			if (start_ctrl_iface_bss(hapd) < 0 ||
+ 			    (hapd_iface->state == HAPD_IFACE_ENABLED &&
+-			     hostapd_setup_bss(hapd, -1))) {
++			     hostapd_setup_bss(hapd, -1, true))) {
+ 				hostapd_cleanup(hapd);
+ 				hapd_iface->bss[hapd_iface->num_bss - 1] = NULL;
+ 				hapd_iface->conf->num_bss--;
+diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
+index 56d96a5..093c28a 100644
+--- a/src/ap/hostapd.h
++++ b/src/ap/hostapd.h
+@@ -660,6 +660,11 @@ struct hostapd_iface {
+ 	/* Previous WMM element information */
+ 	struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
+ 
++	/* Maximum number of interfaces supported for MBSSID advertisements */
++	u8 mbssid_max_interfaces;
++	/* Maximum profile periodicity for enhanced MBSSID advertisements */
++	u8 ema_max_periodicity;
++
+ 	int (*enable_iface_cb)(struct hostapd_iface *iface);
+ 	int (*disable_iface_cb)(struct hostapd_iface *iface);
+ };
+@@ -762,5 +767,7 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
+ #endif /* CONFIG_FST */
+ 
+ int hostapd_set_acl(struct hostapd_data *hapd);
++struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd);
++int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd);
+ 
+ #endif /* HOSTAPD_H */
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index 098793e..30bfa30 100644
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -165,6 +165,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
+ 	int i, num, count;
+ 	int h2e_required;
+ 
++	hapd->conf->xrates_supported = 0;
+ 	if (hapd->iface->current_rates == NULL)
+ 		return eid;
+ 
+@@ -214,6 +215,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
+ 			*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+ 	}
+ 
++	hapd->conf->xrates_supported = 1;
+ 	return pos;
+ }
+ 
+@@ -3979,6 +3981,23 @@ static void handle_auth(struct hostapd_data *hapd,
+ }
+ 
+ 
++static u8 hostapd_max_bssid_indicator(struct hostapd_data *hapd)
++{
++	size_t num_bss_nontx;
++	u8 max_bssid_ind = 0;
++
++	if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1)
++		return 0;
++
++	num_bss_nontx = hapd->iface->num_bss - 1;
++	while (num_bss_nontx > 0) {
++		max_bssid_ind++;
++		num_bss_nontx >>= 1;
++	}
++	return max_bssid_ind;
++}
++
++
+ int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+ {
+ 	int i, j = 32, aid;
+@@ -4004,7 +4023,10 @@ int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+ 	}
+ 	if (j == 32)
+ 		return -1;
+-	aid = i * 32 + j + 1;
++	aid = i * 32 + j;
++
++	aid += (1 << hostapd_max_bssid_indicator(hapd));
++
+ 	if (aid > 2007)
+ 		return -1;
+ 
+@@ -7579,4 +7601,256 @@ u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
+ 	return eid;
+ }
+ 
++
++static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd,
++					  u32 frame_type, size_t *bss_index,
++					  const u8 *known_bss,
++					  size_t known_bss_len)
++{
++	struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
++	size_t len = 3, i;
++
++	for (i = *bss_index; i < hapd->iface->num_bss; i++) {
++		struct hostapd_data *bss = hapd->iface->bss[i];
++		const u8 *auth, *rsn = NULL, *rsnx = NULL;
++		size_t nontx_profile_len, auth_len;
++		u8 ie_count = 0;
++
++		if (known_bss && (known_bss_len > (i / 8))) {
++			known_bss = &known_bss[i / 8];
++			if (*known_bss & (u8)(BIT(i % 8)))
++				continue;
++		}
++
++		if (!bss || !bss->conf || !bss->started)
++			continue;
++
++		/*
++		 * Sublement ID: 1 byte
++		 * Length: 1 byte
++		 * Nontransmitted capabilities: 4 bytes
++		 * SSID element: 2 + variable
++		 * Multiple BSSID Index Element: 3 bytes (+2 bytes in beacons)
++		 * Fixed length = 1 + 1 + 4 + 2 + 3 = 11
++		 */
++		nontx_profile_len = 11 + bss->conf->ssid.ssid_len;
++
++		if (frame_type == WLAN_FC_STYPE_BEACON)
++			nontx_profile_len += 2;
++
++		auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
++		if (auth) {
++			rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
++			if (rsn)
++				nontx_profile_len += (2 + rsn[1]);
++
++			rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
++			if (rsnx)
++				nontx_profile_len += (2 + rsnx[1]);
++		}
++		if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
++			ie_count++;
++		if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
++			ie_count++;
++		if (bss->conf->xrates_supported)
++			nontx_profile_len += 8;
++		else if (hapd->conf->xrates_supported)
++			ie_count++;
++		if (ie_count)
++			nontx_profile_len += (4 + ie_count);
++
++		if ((len + nontx_profile_len) > 255)
++			goto mbssid_too_big;
++
++		len += nontx_profile_len;
++	}
++
++mbssid_too_big:
++	*bss_index = i;
++	return len;
++}
++
++
++size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
++			      u8 *elem_count, const u8 *known_bss,
++			      size_t known_bss_len)
++{
++	size_t len = 0, bss_index = 1;
++
++	if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
++	    (frame_type != WLAN_FC_STYPE_BEACON &&
++	     frame_type != WLAN_FC_STYPE_PROBE_RESP))
++		return 0;
++
++	if (frame_type == WLAN_FC_STYPE_BEACON) {
++		if (!elem_count) {
++			wpa_printf(MSG_ERROR,
++				   "MBSSID: Insufficient data for beacons");
++			return 0;
++		}
++		*elem_count = 0;
++	}
++
++	while (bss_index < hapd->iface->num_bss) {
++		len += hostapd_eid_mbssid_elem_len(hapd, frame_type,
++						   &bss_index, known_bss,
++						   known_bss_len);
++
++		if (frame_type == WLAN_FC_STYPE_BEACON)
++			*elem_count += 1;
++	}
++	return len;
++}
++
++
++static u8 * hostapd_eid_mbssid_elem(struct hostapd_data *hapd, u8 *eid, u8 *end,
++				    u32 frame_type, u8 max_bssid_indicator,
++				    size_t *bss_index, u8 elem_count,
++				    const u8 *known_bss, size_t known_bss_len)
++{
++	struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
++	size_t i;
++	u8 *eid_len_offset, *max_bssid_indicator_offset;
++
++	*eid++ = WLAN_EID_MULTIPLE_BSSID;
++	eid_len_offset = eid++;
++	max_bssid_indicator_offset = eid++;
++
++	for (i = *bss_index; i < hapd->iface->num_bss; i++) {
++		struct hostapd_data *bss = hapd->iface->bss[i];
++		struct hostapd_bss_config *conf;
++		u8 *eid_len_pos, *nontx_bss_start = eid;
++		const u8 *auth, *rsn = NULL, *rsnx = NULL;
++		u8 ie_count = 0, non_inherit_ie[3];
++		size_t auth_len = 0;
++		u16 capab_info;
++
++		if (known_bss && (known_bss_len > (i / 8))) {
++			known_bss = &known_bss[i / 8];
++			if (*known_bss & (u8)(BIT(i % 8)))
++				continue;
++		}
++
++		if (!bss || !bss->conf || !bss->started)
++			continue;
++		conf = bss->conf;
++
++		*eid++ = WLAN_EID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE;
++		eid_len_pos = eid++;
++
++		*eid++ = WLAN_EID_NONTRANSMITTED_BSSID_CAPA;
++		*eid++ = sizeof(capab_info);
++		capab_info = host_to_le16(hostapd_own_capab_info(bss));
++		os_memcpy(eid, (const void *)&capab_info, sizeof(capab_info));
++		eid += sizeof(capab_info);
++
++		*eid++ = WLAN_EID_SSID;
++		*eid++ = conf->ssid.ssid_len;
++		os_memcpy(eid, conf->ssid.ssid, conf->ssid.ssid_len);
++		eid += conf->ssid.ssid_len;
++
++		*eid++ = WLAN_EID_MULTIPLE_BSSID_INDEX;
++		if (frame_type == WLAN_FC_STYPE_BEACON) {
++			*eid++ = 3;
++			*eid++ = i;
++			if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
++			    (conf->dtim_period % elem_count))
++				conf->dtim_period = elem_count;
++			*eid++ = conf->dtim_period;
++			*eid++ = 0xFF;
++		} else {
++			*eid++ = 1;
++			*eid++ = i;
++		}
++
++		auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
++		if (auth) {
++			rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
++			if (rsn) {
++				os_memcpy(eid, rsn, 2 + rsn[1]);
++				eid += (2 + rsn[1]);
++			}
++
++			rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
++			if (rsnx) {
++				os_memcpy(eid, rsnx, 2 + rsnx[1]);
++				eid += (2 + rsnx[1]);
++			}
++		}
++		if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN)) {
++			non_inherit_ie[ie_count] = WLAN_EID_RSN;
++			ie_count++;
++		}
++		if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX)) {
++			non_inherit_ie[ie_count] = WLAN_EID_RSNX;
++			ie_count++;
++		}
++		if (hapd->conf->xrates_supported &&
++		    !bss->conf->xrates_supported) {
++			non_inherit_ie[ie_count] = WLAN_EID_EXT_SUPP_RATES;
++			ie_count++;
++		}
++		if (ie_count) {
++			*eid++ = WLAN_EID_EXTENSION;
++			*eid++ = 2 + ie_count;
++			*eid++ = WLAN_EID_EXT_NON_INHERITANCE;
++			*eid++ = ie_count;
++			os_memcpy(eid, non_inherit_ie, ie_count);
++			eid += ie_count;
++		}
++
++		*eid_len_pos = (eid - eid_len_pos) - 1;
++
++		if (((eid - eid_len_offset) - 1) > 255) {
++			eid = nontx_bss_start;
++			goto mbssid_too_big;
++		}
++	}
++
++mbssid_too_big:
++	*bss_index = i;
++	*max_bssid_indicator_offset = max_bssid_indicator;
++	if (*max_bssid_indicator_offset < 1)
++		*max_bssid_indicator_offset = 1;
++	*eid_len_offset = (eid - eid_len_offset) - 1;
++	return eid;
++}
++
++
++u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
++			u32 frame_type, u8 elem_count, u8 **elem_offset,
++			const u8 *known_bss, size_t known_bss_len)
++{
++	size_t bss_index = 1;
++	u8 elem_index = 0;
++
++	if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
++	    (frame_type != WLAN_FC_STYPE_BEACON &&
++	     frame_type != WLAN_FC_STYPE_PROBE_RESP))
++		return eid;
++
++	if (frame_type == WLAN_FC_STYPE_BEACON && !elem_offset) {
++		wpa_printf(MSG_ERROR, "MBSSID: Insufficient data for beacons");
++		return eid;
++	}
++
++	while (bss_index < hapd->iface->num_bss) {
++		if (frame_type == WLAN_FC_STYPE_BEACON) {
++			if (elem_index == elem_count) {
++				wpa_printf(MSG_WARNING,
++					   "MBSSID: More number of elements than provided array");
++				break;
++			}
++
++			elem_offset[elem_index] = eid;
++			elem_index = elem_index + 1;
++		}
++		eid = hostapd_eid_mbssid_elem(hapd, eid, end, frame_type,
++					      hostapd_max_bssid_indicator(hapd),
++					      &bss_index, elem_count,
++					      known_bss, known_bss_len);
++	}
++	return eid;
++}
++
+ #endif /* CONFIG_NATIVE_WINDOWS */
+diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
+index fa1f47b..bb454bb 100644
+--- a/src/ap/ieee802_11.h
++++ b/src/ap/ieee802_11.h
+@@ -214,5 +214,10 @@ u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ 		       enum ieee80211_op_mode opmode,
+ 		       const u8 *he_capab, size_t he_capab_len,
+ 		       const u8 *eht_capab, size_t eht_capab_len);
+-
++size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
++			      u8 *elem_count, const u8 *known_bss,
++			      size_t known_bss_len);
++u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
++			u32 frame_type, u8 elem_count, u8 **elem_offset,
++			const u8 *known_bss, size_t known_bss_len);
+ #endif /* IEEE802_11_H */
+diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
+index 4f85d78..7f5b475 100644
+--- a/src/ap/ieee802_11_shared.c
++++ b/src/ap/ieee802_11_shared.c
+@@ -364,6 +364,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
+ 			*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+ 		if (hapd->conf->bss_transition)
+ 			*pos |= 0x08; /* Bit 19 - BSS Transition */
++		if (hapd->iconf->mbssid)
++			*pos |= 0x40; /* Bit 22 - Multiple BSSID */
+ 		break;
+ 	case 3: /* Bits 24-31 */
+ #ifdef CONFIG_WNM_AP
+@@ -436,6 +438,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
+ 		    (hapd->iface->drv_flags &
+ 		     WPA_DRIVER_FLAGS_BEACON_PROTECTION))
+ 			*pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
++		if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED)
++			*pos |= 0x08; /* Bit 83 - Enhanced multiple BSSID */
+ 		break;
+ 	case 11: /* Bits 88-95 */
+ #ifdef CONFIG_SAE_PK
+@@ -471,6 +475,13 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
+ 			*pos &= ~hapd->conf->ext_capa_mask[i];
+ 			*pos |= hapd->conf->ext_capa[i];
+ 		}
++
++		/* Clear bits 83 and 22 if EMA and MBSSID are not enabled
++		 * otherwise association fails with some clients */
++		if (i == 10 && hapd->iconf->mbssid < ENHANCED_MBSSID_ENABLED)
++			*pos &= ~0x08;
++		if (i == 2 && !hapd->iconf->mbssid)
++			*pos &= ~0x40;
+ 	}
+ 
+ 	while (len > 0 && eid[1 + len] == 0) {
+diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
+index c8ee90c..2fab7c3 100644
+--- a/src/common/ieee802_11_common.c
++++ b/src/common/ieee802_11_common.c
+@@ -315,6 +315,10 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
+ 		elems->eht_operation = pos;
+ 		elems->eht_operation_len = elen;
+ 		break;
++	case WLAN_EID_EXT_KNOWN_BSSID:
++		elems->mbssid_known_bss = pos;
++		elems->mbssid_known_bss_len = elen;
++		break;
+ 	default:
+ 		if (show_errors) {
+ 			wpa_printf(MSG_MSGDUMP,
+diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
+index 94e1d7b..1e4e27d 100644
+--- a/src/common/ieee802_11_common.h
++++ b/src/common/ieee802_11_common.h
+@@ -119,6 +119,7 @@ struct ieee802_11_elems {
+ 	const u8 *pasn_params;
+ 	const u8 *eht_capabilities;
+ 	const u8 *eht_operation;
++	const u8 *mbssid_known_bss;
+ 
+ 	u8 ssid_len;
+ 	u8 supp_rates_len;
+@@ -176,6 +177,8 @@ struct ieee802_11_elems {
+ 	u8 eht_capabilities_len;
+ 	u8 eht_operation_len;
+ 
++	u8 mbssid_known_bss_len;
++
+ 	struct mb_ies_info mb_ies;
+ 	struct frag_ies_info frag_ies;
+ };
+diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
+index 62088bd..0bbbca9 100644
+--- a/src/common/ieee802_11_defs.h
++++ b/src/common/ieee802_11_defs.h
+@@ -481,6 +481,9 @@
+ #define WLAN_EID_EXT_SPATIAL_REUSE 39
+ #define WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT 42
+ #define WLAN_EID_EXT_OCV_OCI 54
++#define WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION 55
++#define WLAN_EID_EXT_NON_INHERITANCE 56
++#define WLAN_EID_EXT_KNOWN_BSSID 57
+ #define WLAN_EID_EXT_SHORT_SSID_LIST 58
+ #define WLAN_EID_EXT_HE_6GHZ_BAND_CAP 59
+ #define WLAN_EID_EXT_EDMG_CAPABILITIES 61
+@@ -497,6 +500,8 @@
+ #define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110
+ #define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114
+ 
++#define WLAN_EID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE 0
++
+ /* Extended Capabilities field */
+ #define WLAN_EXT_CAPAB_20_40_COEX 0
+ #define WLAN_EXT_CAPAB_GLK 1
+diff --git a/src/drivers/driver.h b/src/drivers/driver.h
+index 82daef0..36f465c 100644
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -1633,6 +1633,43 @@ struct wpa_driver_ap_params {
+ 	 * ibf_enable=<val>
+ 	 */
+ 	u8 ibf_enable;
++
++	/**
++	 * mbssid_tx_iface - Transmitting interface of the MBSSID set
++	 */
++	const char *mbssid_tx_iface;
++
++	/**
++	 * mbssid_index - The index of this BSS in the MBSSID set
++	 */
++	unsigned int mbssid_index;
++
++	/**
++	 * mbssid_elem - Buffer containing all MBSSID elements
++	 */
++	u8 *mbssid_elem;
++
++	/**
++	 * mbssid_elem_len - Total length of all MBSSID elements
++	 */
++	size_t mbssid_elem_len;
++
++	/**
++	 * mbssid_elem_count - The number of MBSSID elements
++	 */
++	u8 mbssid_elem_count;
++
++	/**
++	 * mbssid_elem_offset - Offsets to elements in mbssid_elem.
++	 * Kernel will use these offsets to generate multiple BSSID beacons.
++	 */
++	u8 **mbssid_elem_offset;
++
++	/**
++	 * ema - Enhanced MBSSID advertisements support.
++	 */
++	bool ema;
++
+ };
+ 
+ struct wpa_driver_mesh_bss_params {
+@@ -2197,6 +2234,11 @@ struct wpa_driver_capa {
+ 
+ 	/* Maximum number of supported CSA counters */
+ 	u16 max_csa_counters;
++
++	/* Maximum number of interfaces supported for MBSSID advertisements */
++	u8 mbssid_max_interfaces;
++	/* Maximum profile periodicity for enhanced MBSSID advertisements */
++	u8 ema_max_periodicity;
+ };
+ 
+ 
+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
+index 6c65901..3753409 100644
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -4540,6 +4540,55 @@ static int nl80211_unsol_bcast_probe_resp(struct i802_bss *bss,
+ 	nla_nest_end(msg, attr);
+ 	return 0;
+ }
++
++
++static int nl80211_mbssid(struct nl_msg *msg,
++			 struct wpa_driver_ap_params *params)
++{
++	struct nlattr *config, *elems;
++	int ifidx;
++
++	if (!params->mbssid_tx_iface)
++		return 0;
++
++	config = nla_nest_start(msg, NL80211_ATTR_MBSSID_CONFIG);
++	if (!config)
++		return -1;
++
++	nla_put_u8(msg, NL80211_MBSSID_CONFIG_ATTR_INDEX, params->mbssid_index);
++	if (params->mbssid_tx_iface) {
++		ifidx = if_nametoindex(params->mbssid_tx_iface);
++		if (ifidx <= 0)
++			return -1;
++		nla_put_u32(msg,
++			    NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX,
++			    ifidx);
++	}
++
++	if (params->ema)
++		nla_put_flag(msg, NL80211_MBSSID_CONFIG_ATTR_EMA);
++
++	nla_nest_end(msg, config);
++
++	if (params->mbssid_elem_count && params->mbssid_elem_len &&
++	    params->mbssid_elem_offset && *params->mbssid_elem_offset) {
++		u8 i, **offs = params->mbssid_elem_offset;
++
++		elems = nla_nest_start(msg, NL80211_ATTR_MBSSID_ELEMS);
++		if (!elems)
++			return -1;
++
++		for (i = 0; i < params->mbssid_elem_count - 1; i++)
++			nla_put(msg, i + 1, offs[i + 1] - offs[i], offs[i]);
++
++		nla_put(msg, i + 1,
++			*offs + params->mbssid_elem_len - offs[i],
++			offs[i]);
++
++		nla_nest_end(msg, elems);
++	}
++	return 0;
++}
+ #endif /* CONFIG_IEEE80211AX */
+ 
+ 
+@@ -4838,6 +4887,9 @@ static int wpa_driver_nl80211_set_ap(void *priv,
+ 	if (params->unsol_bcast_probe_resp_interval &&
+ 	    nl80211_unsol_bcast_probe_resp(bss, msg, params) < 0)
+ 		goto fail;
++
++	if (nl80211_mbssid(msg, params) < 0)
++		goto fail;
+ #endif /* CONFIG_IEEE80211AX */
+ 
+ #ifdef CONFIG_SAE
+diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
+index 06a52db..d8078bc 100644
+--- a/src/drivers/driver_nl80211_capa.c
++++ b/src/drivers/driver_nl80211_capa.c
+@@ -857,6 +857,30 @@ err:
+ }
+ 
+ 
++static void wiphy_info_mbssid(struct wpa_driver_capa *cap, struct nlattr *attr)
++{
++	struct nlattr *config[NL80211_MBSSID_CONFIG_ATTR_MAX + 1];
++
++	if (nla_parse_nested(config, NL80211_MBSSID_CONFIG_ATTR_MAX, attr,
++			     NULL))
++		return;
++
++	if (!config[NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES])
++		return;
++
++	cap->mbssid_max_interfaces =
++		nla_get_u8(config[NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES]);
++
++	if (config[NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY])
++		cap->ema_max_periodicity =
++		nla_get_u8(config[NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY]);
++
++	wpa_printf(MSG_DEBUG,
++		   "multiple_bssid: max interfaces %u, max profile periodicity %u\n",
++		   cap->mbssid_max_interfaces, cap->ema_max_periodicity);
++}
++
++
+ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+ {
+ 	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+@@ -1106,6 +1130,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+ 	if (tb[NL80211_ATTR_WIPHY_SELF_MANAGED_REG])
+ 		capa->flags |= WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY;
+ 
++	if (tb[NL80211_ATTR_MBSSID_CONFIG])
++		wiphy_info_mbssid(capa, tb[NL80211_ATTR_MBSSID_CONFIG]);
++
+ 	return NL_SKIP;
+ }
+ 
+-- 
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches/patches.inc b/recipes-wifi/wpa-supplicant/files/patches/patches.inc
index 872f470..48bd493 100644
--- a/recipes-wifi/wpa-supplicant/files/patches/patches.inc
+++ b/recipes-wifi/wpa-supplicant/files/patches/patches.inc
@@ -78,7 +78,10 @@
     file://mtk-0014-hostapd-mtk-Add-the-broadcast-destination-address-of.patch \
     file://mtk-0015-hostapd-mtk-Add-vendor-command-attribute-for-RTS-BW-.patch \
     file://mtk-0016-hostapd-mtk-6G-band-does-not-require-DFS.patch \
+    file://mtk-0016-hostapd-mtk-Add-available-color-bitmap.patch \
     file://mtk-0017-hostapd-mtk-Fix-sending-wrong-VHT-operation-IE-in-CS.patch \
     file://mtk-0018-hostapd-mtk-Add-sta-assisted-DFS-state-update-mechan.patch \
     file://mtk-0019-hostapd-mtk-Fix-auto-ht-issue-when-switching-to-DFS-.patch \
+    file://mtk-0020-hostapd-mtk-Mark-DFS-channel-as-available-for-CSA.patch \
+    file://mtk-0020-hostapd-mtk-add-11v_mbss-and-ema-support.patch \
     "