[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,
+ ¶ms->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 \
"