[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/atenl/files/iwpriv.sh b/recipes-wifi/atenl/files/iwpriv.sh
index 3690c2d..de74190 100644
--- a/recipes-wifi/atenl/files/iwpriv.sh
+++ b/recipes-wifi/atenl/files/iwpriv.sh
@@ -269,6 +269,12 @@
echo "he_tb"
elif [ "$tx_mode" = "11" ]; then
echo "he_mu"
+ elif [ "$tx_mode" = "13" ]; then
+ echo "eht_su"
+ elif [ "$tx_mode" = "14" ]; then
+ echo "eht_tb"
+ elif [ "$tx_mode" = "15" ]; then
+ echo "eht_mu"
else
echo "undefined"
fi
@@ -496,7 +502,27 @@
local base_freq=5180
local base_chan=36
else
+ local base_freq=5955
case ${bw} in
+ "12")
+ local bw_str="320"
+ if [ ${ch} == "31" ]; then
+ local control_freq="5955"
+ elif [ ${ch} == "63" ]; then
+ local control_freq="6115"
+ elif [ ${ch} == "95" ]; then
+ local control_freq="6275"
+ elif [ ${ch} == "127" ]; then
+ local control_freq="6435"
+ elif [ ${ch} == "159" ]; then
+ local control_freq="6595"
+ elif [ ${ch} == "191" ]; then
+ local control_freq="6755"
+ fi
+ local center_freq=$(((ch - base_chan) * 5 + base_freq))
+ do_cmd "iw dev mon${phy_idx} set freq ${control_freq} ${bw_str} ${center_freq}"
+ return
+ ;;
"5")
bw_str="160MHz"
if [ ${ch} -lt "33" ]; then
@@ -644,7 +670,6 @@
local bw_str="HT20"
;;
esac
- local base_freq=5955
fi
local control_freq=$(((ch - base_chan) * 5 + base_freq))
@@ -826,15 +851,22 @@
if [ "${cmd}" = "ATETxPacketWithBf" ]; then
do_cmd "mt76-test phy${phy_idx} set state=tx_frames"
elif [ "${cmd}" = "ATEConTxETxBfInitProc" ]; then
+ local wlan_idx="1"
+ if [ ${is_eagle} == "1" ]; then
+ local wlan_idx=$((phy_idx+1))
+ fi
do_cmd "mt76-test phy${phy_idx} set aid=1"
do_cmd "mt76-test phy${phy_idx} set txbf_act=stop_sounding txbf_param=1"
do_cmd "mt76-test phy${phy_idx} set txbf_act=update_ch txbf_param=1"
do_cmd "mt76-test phy${phy_idx} set txbf_act=ebf_prof_update txbf_param=0,0,0"
- do_cmd "mt76-test phy${phy_idx} set txbf_act=apply_tx txbf_param=1,1,0,0,0"
+ do_cmd "mt76-test phy${phy_idx} set txbf_act=apply_tx txbf_param=${wlan_idx},1,0,0,0"
+ if [ ${is_eagle} == "1" ]; then
+ do_cmd "mt76-test phy${phy_idx} set txbf_act=txcmd txbf_param=1,1,1"
+ fi
do_cmd "mt76-test phy${phy_idx} set txbf_act=pfmu_tag_read txbf_param=0,1"
- do_cmd "mt76-test phy${phy_idx} set txbf_act=sta_rec_read txbf_param=1"
- do_cmd "mt76-test phy${phy_idx} set txbf_act=trigger_sounding txbf_param=0,1,0,1,0,0,0"
- do_cmd "mt76-test phy${phy_idx} set txbf_act=trigger_sounding txbf_param=2,1,ff,1,0,0,0"
+ do_cmd "mt76-test phy${phy_idx} set txbf_act=sta_rec_read txbf_param=${wlan_idx}"
+ do_cmd "mt76-test phy${phy_idx} set txbf_act=trigger_sounding txbf_param=0,1,0,${wlan_idx},0,0,0"
+ do_cmd "mt76-test phy${phy_idx} set txbf_act=trigger_sounding txbf_param=2,1,ff,${wlan_idx},0,0,0"
do_cmd "mt76-test phy${phy_idx} set state=rx_frames"
elif [ "${cmd}" = "ATEConTxETxBfGdProc" ]; then
do_cmd "mt76-test phy${phy_idx} set aid=1"
@@ -1104,6 +1136,11 @@
exit
elif [[ ${interface} == "ra"* ]]; then
convert_interface $interface
+elif [[ ${interface} == "phy" ]]; then
+ # handle mwctl phy phy0 e2p ... case
+ interface=$2
+ cmd_type=$3
+ full_cmd=$4
fi
tmp_work_mode=$(get_config "WORKMODE" ${iwpriv_file})
@@ -1122,13 +1159,12 @@
## Therefore this wrapper would translate it to either mt76-test or mt76-vendor based on the attribute of the command
## Translate to mt76-vendor command
"csi"|"amnt"|"ap_rfeatures"|"ap_wireless"|"mu")
- if [ ${is_eagle} == "1" ]; then
+ if [ ${is_eagle} == "1" ]; then
do_cmd "hostapd_cli -i $*"
- skip=1
- else
+ else
do_cmd "mt76-vendor $*"
- skip=1
- fi
+ fi
+ skip=1
;;
"ATE")
do_ate_work ${param}
@@ -1152,9 +1188,14 @@
param_new=${param}
;;
"ATETXGI")
- tx_mode=$(convert_tx_mode $(get_config "ATETXMODE" ${iwpriv_file}))
- convert_gi ${tx_mode} ${param}
- skip=1
+ if [ ${is_eagle} == "0" ]; then
+ tx_mode=$(convert_tx_mode $(get_config "ATETXMODE" ${iwpriv_file}))
+ convert_gi ${tx_mode} ${param}
+ skip=1
+ else
+ cmd_new="tx_rate_sgi"
+ param_new=${param}
+ fi
;;
"ATETXMODE")
cmd_new="tx_rate_mode"
@@ -1167,10 +1208,18 @@
record_config ${cmd} ${param} ${iwpriv_file}
fi
;;
- "ATETXPOW0"|"ATETXPOW1"|"ATETXPOW2"|"ATETXPOW3")
+ "ATETXPOW0"|"ATETXPOW1"|"ATETXPOW2"|"ATETXPOW3"|"ATETXPOW")
cmd_new="tx_power"
+ if [ "${param}" == "127" ]; then
+ # for iTest verification
+ exit
+ fi
param_new="${param},0,0,0"
;;
+ "ATEMUAID")
+ cmd_new="aid"
+ param_new=${param}
+ ;;
"ATETXBW")
record_config ${cmd} ${param} ${iwpriv_file}
skip=1
@@ -1233,6 +1282,8 @@
do_cmd "echo ${param} > ${wlan_idx}"
do_cmd "cat ${wtbl_info}"
+ elif [ "${cmd}" = "ATERXSTAT" ]; then
+ convert_rxstat
else
do_cmd "mt76-test ${interface} dump"
do_cmd "mt76-test ${interface} dump stats"
diff --git a/recipes-wifi/hostapd/files/hostapd-full.config b/recipes-wifi/hostapd/files/hostapd-full.config
index b92f9a2..9076ebc 100644
--- a/recipes-wifi/hostapd/files/hostapd-full.config
+++ b/recipes-wifi/hostapd/files/hostapd-full.config
@@ -142,7 +142,7 @@
# RADIUS authentication server. This provides access to the integrated EAP
# server from external hosts using RADIUS.
-#CONFIG_RADIUS_SERVER=y
+CONFIG_RADIUS_SERVER=y
# Build IPv6 support for RADIUS operations
CONFIG_IPV6=y
diff --git a/recipes-wifi/hostapd/files/openwrt_script/hostapd.sh b/recipes-wifi/hostapd/files/openwrt_script/hostapd.sh
index 8c233a4..28bd210 100644
--- a/recipes-wifi/hostapd/files/openwrt_script/hostapd.sh
+++ b/recipes-wifi/hostapd/files/openwrt_script/hostapd.sh
@@ -265,11 +265,11 @@
config_add_int ieee80211w
config_add_int eapol_version
- config_add_string 'auth_server:host' 'server:host'
+ config_add_array auth_server acct_server
+ config_add_string 'server:host'
config_add_string auth_secret key
config_add_int 'auth_port:port' 'port:port'
- config_add_string acct_server
config_add_string acct_secret
config_add_int acct_port
config_add_int acct_interval
@@ -524,6 +524,20 @@
[ -n "$1" ] && append bss_conf "airtime_sta_weight=$1" "$N"
}
+append_auth_server() {
+ [ -n "$1" ] || return
+ append bss_conf "auth_server_addr=$1" "$N"
+ append bss_conf "auth_server_port=$auth_port" "$N"
+ [ -n "$auth_secret" ] && append bss_conf "auth_server_shared_secret=$auth_secret" "$N"
+}
+
+append_acct_server() {
+ [ -n "$1" ] || return
+ append bss_conf "acct_server_addr=$1" "$N"
+ append bss_conf "acct_server_port=$acct_port" "$N"
+ [ -n "$acct_secret" ] && append bss_conf "acct_server_shared_secret=$acct_secret" "$N"
+}
+
hostapd_set_bss_options() {
local var="$1"
local phy="$2"
@@ -542,7 +556,7 @@
wps_independent wps_device_type wps_device_name wps_manufacturer wps_pin \
macfilter ssid utf8_ssid wmm uapsd hidden short_preamble rsn_preauth \
iapp_interface eapol_version dynamic_vlan ieee80211w nasid \
- acct_server acct_secret acct_port acct_interval \
+ acct_secret acct_port acct_interval \
bss_load_update_period chan_util_avg_period sae_require_mfp sae_pwe \
multi_ap multi_ap_backhaul_ssid multi_ap_backhaul_key skip_inactivity_poll \
ppsk airtime_bss_weight airtime_bss_limit airtime_sta_weight \
@@ -614,15 +628,10 @@
set_default nasid "${macaddr//\:}"
append bss_conf "nas_identifier=$nasid" "$N"
- [ -n "$acct_server" ] && {
- append bss_conf "acct_server_addr=$acct_server" "$N"
- append bss_conf "acct_server_port=$acct_port" "$N"
- [ -n "$acct_secret" ] && \
- append bss_conf "acct_server_shared_secret=$acct_secret" "$N"
- [ -n "$acct_interval" ] && \
- append bss_conf "radius_acct_interim_interval=$acct_interval" "$N"
- json_for_each_item append_radius_acct_req_attr radius_acct_req_attr
- }
+ [ -n "$acct_interval" ] && \
+ append bss_conf "radius_acct_interim_interval=$acct_interval" "$N"
+ json_for_each_item append_acct_server acct_server
+ json_for_each_item append_radius_acct_req_attr radius_acct_req_attr
[ -n "$ocv" ] && append bss_conf "ocv=$ocv" "$N"
@@ -659,11 +668,9 @@
psk|sae|psk-sae)
json_get_vars key wpa_psk_file
if [ "$auth_type" = "psk" ] && [ "$ppsk" -ne 0 ] ; then
- json_get_vars auth_server auth_secret auth_port
+ json_get_vars auth_secret auth_port
set_default auth_port 1812
- append bss_conf "auth_server_addr=$auth_server" "$N"
- append bss_conf "auth_server_port=$auth_port" "$N"
- append bss_conf "auth_server_shared_secret=$auth_secret" "$N"
+ json_for_each_item append_auth_server auth_server
append bss_conf "macaddr_acl=2" "$N"
append bss_conf "wpa_psk_radius=2" "$N"
elif [ ${#key} -eq 64 ]; then
@@ -732,12 +739,7 @@
set_default dae_port 3799
set_default request_cui 0
- [ "$eap_server" -eq 0 ] && {
- append bss_conf "auth_server_addr=$auth_server" "$N"
- append bss_conf "auth_server_port=$auth_port" "$N"
- append bss_conf "auth_server_shared_secret=$auth_secret" "$N"
- }
-
+ [ "$eap_server" -eq 0 ] && json_for_each_item append_auth_server auth_server
[ "$request_cui" -gt 0 ] && append bss_conf "radius_request_cui=$request_cui" "$N"
[ -n "$eap_reauth_period" ] && append bss_conf "eap_reauth_period=$eap_reauth_period" "$N"
@@ -777,9 +779,7 @@
[ -n "$auth_server" ] && {
set_default auth_port 1812
- append bss_conf "auth_server_addr=$auth_server" "$N"
- append bss_conf "auth_server_port=$auth_port" "$N"
- [ -n "$auth_secret" ] && append bss_conf "auth_server_shared_secret=$auth_secret" "$N"
+ json_for_each_item append_auth_server auth_server
[ -n "$ownip" ] && append bss_conf "own_ip_addr=$ownip" "$N"
[ -n "$radius_client_addr" ] && append bss_conf "radius_client_addr=$radius_client_addr" "$N"
append bss_conf "macaddr_acl=2" "$N"
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0010-hostapd-mtk-Add-DFS-detection-mode.patch b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0010-hostapd-mtk-Add-DFS-detection-mode.patch
index 2ceb639..7ec986a 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0010-hostapd-mtk-Add-DFS-detection-mode.patch
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/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/hostapd/files/patches-2.10.3/mtk-0016-hostapd-mtk-Add-available-color-bitmap.patch b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0016-hostapd-mtk-Add-available-color-bitmap.patch
new file mode 100644
index 0000000..9bbbf87
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/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/hostapd/files/patches-2.10.3/mtk-0020-hostapd-mtk-Mark-DFS-channel-as-available-for-CSA.patch b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0020-hostapd-mtk-Mark-DFS-channel-as-available-for-CSA.patch
new file mode 100644
index 0000000..1fe5c88
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/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/hostapd/files/patches-2.10.3/mtk-0020-hostapd-mtk-add-11v_mbss-and-ema-support.patch b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0020-hostapd-mtk-add-11v_mbss-and-ema-support.patch
new file mode 100644
index 0000000..8d59a0f
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/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/hostapd/files/patches-2.10.3/patches.inc b/recipes-wifi/hostapd/files/patches-2.10.3/patches.inc
index 78d5240..5e6bf88 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/patches.inc
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/patches.inc
@@ -78,8 +78,11 @@
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 \
file://mtk-0100-hostapd-mtk-update-eht-operation-elem.patch \
"
diff --git a/recipes-wifi/hostapd/files/patches/mtk-0010-hostapd-mtk-Add-DFS-detection-mode.patch b/recipes-wifi/hostapd/files/patches/mtk-0010-hostapd-mtk-Add-DFS-detection-mode.patch
index 2ceb639..7ec986a 100644
--- a/recipes-wifi/hostapd/files/patches/mtk-0010-hostapd-mtk-Add-DFS-detection-mode.patch
+++ b/recipes-wifi/hostapd/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/hostapd/files/patches/mtk-0016-hostapd-mtk-Add-available-color-bitmap.patch b/recipes-wifi/hostapd/files/patches/mtk-0016-hostapd-mtk-Add-available-color-bitmap.patch
new file mode 100644
index 0000000..9bbbf87
--- /dev/null
+++ b/recipes-wifi/hostapd/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/hostapd/files/patches/mtk-0020-hostapd-mtk-Mark-DFS-channel-as-available-for-CSA.patch b/recipes-wifi/hostapd/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/hostapd/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/hostapd/files/patches/mtk-0020-hostapd-mtk-add-11v_mbss-and-ema-support.patch b/recipes-wifi/hostapd/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/hostapd/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/hostapd/files/patches/patches.inc b/recipes-wifi/hostapd/files/patches/patches.inc
index 872f470..48bd493 100644
--- a/recipes-wifi/hostapd/files/patches/patches.inc
+++ b/recipes-wifi/hostapd/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 \
"
diff --git a/recipes-wifi/hostapd/files/src/src/ap/ubus.c b/recipes-wifi/hostapd/files/src/src/ap/ubus.c
index 5001225..ddd8644 100644
--- a/recipes-wifi/hostapd/files/src/src/ap/ubus.c
+++ b/recipes-wifi/hostapd/files/src/src/ap/ubus.c
@@ -1084,6 +1084,8 @@
}
__hostapd_bss_mgmt_enable(hapd, flags);
+
+ return 0;
}
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/319-wifi-mac80211-mesh-fast-xmit-support.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/319-wifi-mac80211-mesh-fast-xmit-support.patch
index b802960..12e9cf5 100644
--- a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/319-wifi-mac80211-mesh-fast-xmit-support.patch
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/319-wifi-mac80211-mesh-fast-xmit-support.patch
@@ -90,7 +90,7 @@
#include "driver-ops.h"
static int mesh_allocated;
-@@ -698,6 +699,102 @@ ieee80211_mesh_update_bss_params(struct
+@@ -698,6 +699,95 @@ ieee80211_mesh_update_bss_params(struct
__le32_to_cpu(he_oper->he_oper_params);
}
@@ -137,8 +137,7 @@
+ if (!entry)
+ return false;
+
-+ if (skb_headroom(skb) + 2 * ETH_ALEN < entry->hdrlen +
-+ entry->fast_tx.hdr_len)
++ if (skb_headroom(skb) < entry->hdrlen + entry->fast_tx.hdr_len)
+ return false;
+
+ sta = rcu_dereference(entry->mpath->next_hop);
@@ -154,16 +153,9 @@
+ tid_tx->last_tx = jiffies;
+ }
+
-+ /* If the skb is shared we need to obtain our own copy */
-+ if (skb_shared(skb)) {
-+ struct sk_buff *oskb = skb;
-+
-+ skb = skb_clone(skb, GFP_ATOMIC);
-+ if (!skb)
-+ return false;
-+
-+ kfree_skb(oskb);
-+ }
++ skb = skb_share_check(skb, GFP_ATOMIC);
++ if (!skb)
++ return true;
+
+ skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb));
+
@@ -184,6 +176,7 @@
+ if (copy_sa)
+ ether_addr_copy(meshhdr->eaddr2, sa);
+
++ skb_push(skb, 2 * ETH_ALEN);
+ __ieee80211_xmit_fast(sdata, sta, &entry->fast_tx, skb, tid_tx,
+ entry->mpath->dst, sdata->vif.addr);
+
@@ -193,7 +186,7 @@
/**
* ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
* @hdr: 802.11 frame header
-@@ -780,6 +877,8 @@ static void ieee80211_mesh_housekeeping(
+@@ -780,6 +870,8 @@ static void ieee80211_mesh_housekeeping(
changed = mesh_accept_plinks_update(sdata);
ieee80211_mbss_info_change_notify(sdata, changed);
@@ -566,7 +559,7 @@
+ if (!entry)
+ goto unlock_sta;
+
-+ spin_lock_bh(&cache->walk_lock);
++ spin_lock(&cache->walk_lock);
+ prev = rhashtable_lookup_get_insert_fast(&cache->rht,
+ &entry->rhash,
+ fast_tx_rht_params);
@@ -589,7 +582,7 @@
+ hlist_add_head(&entry->walk_list, &cache->walk_head);
+
+unlock_cache:
-+ spin_unlock_bh(&cache->walk_lock);
++ spin_unlock(&cache->walk_lock);
+unlock_sta:
+ spin_unlock_bh(&sta->lock);
+}
@@ -771,28 +764,20 @@
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
-@@ -3645,8 +3652,6 @@ static void __ieee80211_xmit_fast(struct
- struct ieee80211_tx_data tx;
+@@ -3646,7 +3653,6 @@ static void __ieee80211_xmit_fast(struct
ieee80211_tx_result r;
int hw_headroom = sdata->local->hw.extra_tx_headroom;
-- int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
+ int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
- struct ethhdr eth;
skb = skb_share_check(skb, GFP_ATOMIC);
if (unlikely(!skb))
-@@ -3661,16 +3666,15 @@ static void __ieee80211_xmit_fast(struct
- * more room than we already have in 'extra_head'
- */
- if (unlikely(ieee80211_skb_resize(sdata, skb,
-- max_t(int, extra_head + hw_headroom -
-+ max_t(int, fast_tx->hdr_len + hw_headroom -
- skb_headroom(skb), 0),
+@@ -3666,11 +3672,10 @@ static void __ieee80211_xmit_fast(struct
ENCRYPT_NO)))
goto free;
- memcpy(ð, skb->data, ETH_HLEN - 2);
-- hdr = skb_push(skb, extra_head);
-+ hdr = skb_push(skb, fast_tx->hdr_len);
+ hdr = skb_push(skb, extra_head);
memcpy(skb->data, fast_tx->hdr, fast_tx->hdr_len);
- memcpy(skb->data + fast_tx->da_offs, eth.h_dest, ETH_ALEN);
- memcpy(skb->data + fast_tx->sa_offs, eth.h_source, ETH_ALEN);
@@ -801,16 +786,17 @@
info = IEEE80211_SKB_CB(skb);
memset(info, 0, sizeof(*info));
-@@ -3689,7 +3693,7 @@ static void __ieee80211_xmit_fast(struct
+@@ -3689,7 +3694,8 @@ static void __ieee80211_xmit_fast(struct
#endif
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
- tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+ u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
++
*ieee80211_get_qos_ctl(hdr) = tid;
}
-@@ -3732,6 +3736,7 @@ static bool ieee80211_xmit_fast(struct i
+@@ -3732,6 +3738,7 @@ static bool ieee80211_xmit_fast(struct i
struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
struct tid_ampdu_tx *tid_tx = NULL;
struct sk_buff *next;
@@ -818,17 +804,16 @@
u8 tid = IEEE80211_NUM_TIDS;
/* control port protocol needs a lot of special handling */
-@@ -3757,14 +3762,18 @@ static bool ieee80211_xmit_fast(struct i
+@@ -3757,6 +3764,8 @@ static bool ieee80211_xmit_fast(struct i
}
}
+ memcpy(ð, skb->data, ETH_HLEN - 2);
+
/* after this point (skb is modified) we cannot return false */
-+ skb_pull(skb, ETH_HLEN - 2);
skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
if (!skb)
- return true;
+@@ -3764,7 +3773,8 @@ static bool ieee80211_xmit_fast(struct i
skb_list_walk_safe(skb, skb, next) {
skb_mark_not_on_list(skb);
@@ -838,7 +823,7 @@
}
return true;
-@@ -4244,8 +4253,15 @@ void __ieee80211_subif_start_xmit(struct
+@@ -4244,8 +4254,15 @@ void __ieee80211_subif_start_xmit(struct
return;
}
@@ -854,7 +839,7 @@
if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
goto out_free;
-@@ -4255,8 +4271,6 @@ void __ieee80211_subif_start_xmit(struct
+@@ -4255,8 +4272,6 @@ void __ieee80211_subif_start_xmit(struct
skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb));
ieee80211_aggr_check(sdata, sta, skb);
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/320-wifi-mac80211-use-mesh-header-cache-to-speed-up-mesh.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/320-wifi-mac80211-use-mesh-header-cache-to-speed-up-mesh.patch
index 3b0bae6..7ec8f3d 100644
--- a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/320-wifi-mac80211-use-mesh-header-cache-to-speed-up-mesh.patch
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/320-wifi-mac80211-use-mesh-header-cache-to-speed-up-mesh.patch
@@ -64,7 +64,7 @@
+
+ skb->dev = sdata->dev;
+ memcpy(ð, skb->data, ETH_HLEN - 2);
-+ skb_pull(skb, sizeof(eth));
++ skb_pull(skb, 2);
+ __ieee80211_xmit_fast(sdata, sta, &entry->fast_tx, skb, tid_tx,
+ eth.h_dest, eth.h_source);
+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/323-wifi-mac80211-Add-VHT-MU-MIMO-related-flags-in-ieee8.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/323-wifi-mac80211-Add-VHT-MU-MIMO-related-flags-in-ieee8.patch
new file mode 100644
index 0000000..2310593
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/323-wifi-mac80211-Add-VHT-MU-MIMO-related-flags-in-ieee8.patch
@@ -0,0 +1,68 @@
+From: Muna Sinada <quic_msinada@quicinc.com>
+Date: Wed, 5 Oct 2022 14:54:45 -0700
+Subject: [PATCH] wifi: mac80211: Add VHT MU-MIMO related flags in
+ ieee80211_bss_conf
+
+Adding flags for SU Beamformer, SU Beamformee, MU Beamformer and
+MU Beamformee for VHT. This is utilized to pass MU-MIMO
+configurations from user space to driver in AP mode.
+
+Signed-off-by: Muna Sinada <quic_msinada@quicinc.com>
+Link: https://lore.kernel.org/r/1665006886-23874-1-git-send-email-quic_msinada@quicinc.com
+[fixed indentation, removed redundant !!]
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -653,6 +653,14 @@ struct ieee80211_fils_discovery {
+ * write-protected by sdata_lock and local->mtx so holding either is fine
+ * for read access.
+ * @color_change_color: the bss color that will be used after the change.
++ * @vht_su_beamformer: in AP mode, does this BSS support operation as an VHT SU
++ * beamformer
++ * @vht_su_beamformee: in AP mode, does this BSS support operation as an VHT SU
++ * beamformee
++ * @vht_mu_beamformer: in AP mode, does this BSS support operation as an VHT MU
++ * beamformer
++ * @vht_mu_beamformee: in AP mode, does this BSS support operation as an VHT MU
++ * beamformee
+ */
+ struct ieee80211_bss_conf {
+ const u8 *bssid;
+@@ -726,6 +734,11 @@ struct ieee80211_bss_conf {
+
+ bool color_change_active;
+ u8 color_change_color;
++
++ bool vht_su_beamformer;
++ bool vht_su_beamformee;
++ bool vht_mu_beamformer;
++ bool vht_mu_beamformee;
+ };
+
+ /**
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -1251,6 +1251,21 @@ static int ieee80211_start_ap(struct wip
+ prev_beacon_int = link_conf->beacon_int;
+ link_conf->beacon_int = params->beacon_interval;
+
++ if (params->vht_cap) {
++ link_conf->vht_su_beamformer =
++ params->vht_cap->vht_cap_info &
++ cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
++ link_conf->vht_su_beamformee =
++ params->vht_cap->vht_cap_info &
++ cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
++ link_conf->vht_mu_beamformer =
++ params->vht_cap->vht_cap_info &
++ cpu_to_le32(IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
++ link_conf->vht_mu_beamformee =
++ params->vht_cap->vht_cap_info &
++ cpu_to_le32(IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
++ }
++
+ if (params->he_cap && params->he_oper) {
+ link_conf->he_support = true;
+ link_conf->htc_trig_based_pkt_ext =
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/324-wifi-mac80211-Add-HE-MU-MIMO-related-flags-in-ieee80.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/324-wifi-mac80211-Add-HE-MU-MIMO-related-flags-in-ieee80.patch
new file mode 100644
index 0000000..a3c4453
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/324-wifi-mac80211-Add-HE-MU-MIMO-related-flags-in-ieee80.patch
@@ -0,0 +1,68 @@
+From: Muna Sinada <quic_msinada@quicinc.com>
+Date: Wed, 5 Oct 2022 14:54:46 -0700
+Subject: [PATCH] wifi: mac80211: Add HE MU-MIMO related flags in
+ ieee80211_bss_conf
+
+Adding flags for SU Beamformer, SU Beamformee, MU Beamformer and Full
+Bandwidth UL MU-MIMO for HE. This is utilized to pass MU-MIMO
+configurations from user space to driver in AP mode.
+
+Signed-off-by: Muna Sinada <quic_msinada@quicinc.com>
+Link: https://lore.kernel.org/r/1665006886-23874-2-git-send-email-quic_msinada@quicinc.com
+[fixed indentation, removed redundant !!]
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -661,6 +661,15 @@ struct ieee80211_fils_discovery {
+ * beamformer
+ * @vht_mu_beamformee: in AP mode, does this BSS support operation as an VHT MU
+ * beamformee
++ * @he_su_beamformer: in AP-mode, does this BSS support operation as an HE SU
++ * beamformer
++ * @he_su_beamformee: in AP-mode, does this BSS support operation as an HE SU
++ * beamformee
++ * @he_mu_beamformer: in AP-mode, does this BSS support operation as an HE MU
++ * beamformer
++ * @he_full_ul_mumimo: does this BSS support the reception (AP) or transmission
++ * (non-AP STA) of an HE TB PPDU on an RU that spans the entire PPDU
++ * bandwidth
+ */
+ struct ieee80211_bss_conf {
+ const u8 *bssid;
+@@ -739,6 +748,10 @@ struct ieee80211_bss_conf {
+ bool vht_su_beamformee;
+ bool vht_mu_beamformer;
+ bool vht_mu_beamformee;
++ bool he_su_beamformer;
++ bool he_su_beamformee;
++ bool he_mu_beamformer;
++ bool he_full_ul_mumimo;
+ };
+
+ /**
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -1280,6 +1280,21 @@ static int ieee80211_start_ap(struct wip
+ changed |= BSS_CHANGED_HE_BSS_COLOR;
+ }
+
++ if (params->he_cap) {
++ link_conf->he_su_beamformer =
++ params->he_cap->phy_cap_info[3] &
++ IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
++ link_conf->he_su_beamformee =
++ params->he_cap->phy_cap_info[4] &
++ IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE;
++ link_conf->he_mu_beamformer =
++ params->he_cap->phy_cap_info[4] &
++ IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
++ link_conf->he_full_ul_mumimo =
++ params->he_cap->phy_cap_info[2] &
++ IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO;
++ }
++
+ if (sdata->vif.type == NL80211_IFTYPE_AP &&
+ params->mbssid_config.tx_wdev) {
+ err = ieee80211_set_ap_mbssid_options(sdata,
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/325-wifi-mac80211-introduce-ieee80211_refresh_tx_agg_ses.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/325-wifi-mac80211-introduce-ieee80211_refresh_tx_agg_ses.patch
new file mode 100644
index 0000000..f6d3d78
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/325-wifi-mac80211-introduce-ieee80211_refresh_tx_agg_ses.patch
@@ -0,0 +1,60 @@
+From: Ryder Lee <ryder.lee@mediatek.com>
+Date: Sat, 18 Feb 2023 01:50:05 +0800
+Subject: [PATCH] wifi: mac80211: introduce
+ ieee80211_refresh_tx_agg_session_timer()
+
+This allows low level drivers to refresh the tx agg session timer, based on
+querying stats from the firmware usually. Especially for some mt76 devices
+support .net_fill_forward_path would bypass mac80211, which leads to tx BA
+session timeout for certain clients.
+
+Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -5968,6 +5968,18 @@ void ieee80211_queue_delayed_work(struct
+ unsigned long delay);
+
+ /**
++ * ieee80211_refresh_tx_agg_session_timer - Refresh a tx agg session timer.
++ * @sta: the station for which to start a BA session
++ * @tid: the TID to BA on.
++ *
++ * This function allows low level driver to refresh tx agg session timer
++ * to maintain BA session, the session level will still be managed by the
++ * mac80211.
++ */
++void ieee80211_refresh_tx_agg_session_timer(struct ieee80211_sta *sta,
++ u16 tid);
++
++/**
+ * ieee80211_start_tx_ba_session - Start a tx Block Ack session.
+ * @sta: the station for which to start a BA session
+ * @tid: the TID to BA on.
+--- a/net/mac80211/agg-tx.c
++++ b/net/mac80211/agg-tx.c
+@@ -552,6 +552,23 @@ void ieee80211_tx_ba_session_handle_star
+ ieee80211_send_addba_with_timeout(sta, tid_tx);
+ }
+
++void ieee80211_refresh_tx_agg_session_timer(struct ieee80211_sta *pubsta,
++ u16 tid)
++{
++ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
++ struct tid_ampdu_tx *tid_tx;
++
++ if (WARN_ON_ONCE(tid >= IEEE80211_NUM_TIDS))
++ return;
++
++ tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
++ if (!tid_tx)
++ return;
++
++ tid_tx->last_tx = jiffies;
++}
++EXPORT_SYMBOL(ieee80211_refresh_tx_agg_session_timer);
++
+ /*
+ * After accepting the AddBA Response we activated a timer,
+ * resetting it after each frame that we send.
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/326-wifi-mac80211-add-mesh-fast-rx-support.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/326-wifi-mac80211-add-mesh-fast-rx-support.patch
new file mode 100644
index 0000000..b2b94d0
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/326-wifi-mac80211-add-mesh-fast-rx-support.patch
@@ -0,0 +1,77 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 2 Mar 2023 13:52:29 +0100
+Subject: [PATCH] wifi: mac80211: add mesh fast-rx support
+
+This helps bring down rx CPU usage by avoiding calls to the rx handlers in
+the slow path. Supports forwarding and local rx, including A-MSDU.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -4572,6 +4572,12 @@ void ieee80211_check_fast_rx(struct sta_
+ }
+
+ break;
++ case NL80211_IFTYPE_MESH_POINT:
++ fastrx.expected_ds_bits = cpu_to_le16(IEEE80211_FCTL_FROMDS |
++ IEEE80211_FCTL_TODS);
++ fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
++ fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4);
++ break;
+ default:
+ goto clear;
+ }
+@@ -4780,6 +4786,7 @@ static bool ieee80211_invoke_fast_rx(str
+ struct sk_buff *skb = rx->skb;
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
++ static ieee80211_rx_result res;
+ int orig_len = skb->len;
+ int hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ int snap_offs = hdrlen;
+@@ -4841,7 +4848,8 @@ static bool ieee80211_invoke_fast_rx(str
+ snap_offs += IEEE80211_CCMP_HDR_LEN;
+ }
+
+- if (!(status->rx_flags & IEEE80211_RX_AMSDU)) {
++ if (!ieee80211_vif_is_mesh(&rx->sdata->vif) &&
++ !(status->rx_flags & IEEE80211_RX_AMSDU)) {
+ if (!pskb_may_pull(skb, snap_offs + sizeof(*payload)))
+ return false;
+
+@@ -4880,13 +4888,29 @@ static bool ieee80211_invoke_fast_rx(str
+ /* do the header conversion - first grab the addresses */
+ ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs);
+ ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs);
+- skb_postpull_rcsum(skb, skb->data + snap_offs,
+- sizeof(rfc1042_header) + 2);
+- /* remove the SNAP but leave the ethertype */
+- skb_pull(skb, snap_offs + sizeof(rfc1042_header));
++ if (ieee80211_vif_is_mesh(&rx->sdata->vif)) {
++ skb_pull(skb, snap_offs - 2);
++ put_unaligned_be16(skb->len - 2, skb->data);
++ } else {
++ skb_postpull_rcsum(skb, skb->data + snap_offs,
++ sizeof(rfc1042_header) + 2);
++
++ /* remove the SNAP but leave the ethertype */
++ skb_pull(skb, snap_offs + sizeof(rfc1042_header));
++ }
+ /* push the addresses in front */
+ memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs));
+
++ res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
++ switch (res) {
++ case RX_QUEUED:
++ return true;
++ case RX_CONTINUE:
++ break;
++ default:
++ goto drop;
++ }
++
+ ieee80211_rx_8023(rx, fast_rx, orig_len);
+
+ return true;
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0008-mac80211-mtk-remove-timerout-handle-for-ax210-iot-is.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0008-mac80211-mtk-remove-timerout-handle-for-ax210-iot-is.patch
deleted file mode 100644
index bf8111a..0000000
--- a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0008-mac80211-mtk-remove-timerout-handle-for-ax210-iot-is.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 41ef202d35486326d8fc52466ef4ad6f7aa98e34 Mon Sep 17 00:00:00 2001
-From: Evelyn Tsai <evelyn.tsai@mediatek.com>
-Date: Wed, 19 Oct 2022 13:49:21 +0800
-Subject: [PATCH 08/16] mac80211: mtk: remove timerout handle for ax210 iot
- issue
-
-Signed-off-by: Evelyn Tsai <evelyn.tsai@mediatek.com>
----
- net/mac80211/agg-tx.c | 7 +++----
- 1 file changed, 3 insertions(+), 4 deletions(-)
- mode change 100644 => 100755 net/mac80211/agg-tx.c
-
-diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
-old mode 100644
-new mode 100755
-index 07c892a..1f46561
---- a/net/mac80211/agg-tx.c
-+++ b/net/mac80211/agg-tx.c
-@@ -568,10 +568,9 @@ static void sta_tx_agg_session_timer_expired(struct timer_list *t)
- }
-
- timeout = tid_tx->last_tx + TU_TO_JIFFIES(tid_tx->timeout);
-- if (time_is_after_jiffies(timeout)) {
-- mod_timer(&tid_tx->session_timer, timeout);
-- return;
-- }
-+ /* remove timerout handle for ax210 iot issue */
-+ mod_timer(&tid_tx->session_timer, timeout);
-+ return;
-
- ht_dbg(sta->sdata, "tx session timer expired on %pM tid %d\n",
- sta->sta.addr, tid);
---
-2.25.1
-
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0012-mac80211-mtk-check-the-control-channel-before-downgr.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0011-mac80211-mtk-check-the-control-channel-before-downgr.patch
similarity index 92%
rename from recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0012-mac80211-mtk-check-the-control-channel-before-downgr.patch
rename to recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0011-mac80211-mtk-check-the-control-channel-before-downgr.patch
index 23b9ccb..18f434f 100644
--- a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0012-mac80211-mtk-check-the-control-channel-before-downgr.patch
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0011-mac80211-mtk-check-the-control-channel-before-downgr.patch
@@ -1,7 +1,7 @@
-From cc6f40e49bfdee7c824d4b158a060c2dc42ded4c Mon Sep 17 00:00:00 2001
+From 0ed0a8f524a3288603f9eb298dcdeff7ae745e39 Mon Sep 17 00:00:00 2001
From: Evelyn Tsai <evelyn.tsai@mediatek.com>
Date: Fri, 16 Dec 2022 03:31:06 +0800
-Subject: [PATCH 12/16] mac80211: mtk: check the control channel before
+Subject: [PATCH 11/19] mac80211: mtk: check the control channel before
downgrading the bandwidth
---
@@ -50,5 +50,5 @@
*conn_flags |=
ieee80211_chandef_downgrade(&chandef);
--
-2.25.1
+2.18.0
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0011-mac80211-mtk-fix-the-issue-of-AP-and-STA-starting-on.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0011-mac80211-mtk-fix-the-issue-of-AP-and-STA-starting-on.patch
deleted file mode 100644
index c42a00f..0000000
--- a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0011-mac80211-mtk-fix-the-issue-of-AP-and-STA-starting-on.patch
+++ /dev/null
@@ -1,261 +0,0 @@
-From 7dd3aacd15e5678a617001dc329cf942ed7f4298 Mon Sep 17 00:00:00 2001
-From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
-Date: Wed, 5 Oct 2022 19:13:43 +0800
-Subject: [PATCH 11/16] mac80211: mtk: fix the issue of AP and STA starting on
- DFS channel concurrently
-
-Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
----
- include/net/cfg80211.h | 22 ++++++++++++++++++
- include/uapi/linux/nl80211.h | 2 +-
- net/mac80211/cfg.c | 44 ++++++++++++++++++++++++++++++++++++
- net/mac80211/chan.c | 2 +-
- net/wireless/chan.c | 6 ++---
- net/wireless/nl80211.c | 7 ++++++
- net/wireless/rdev-ops.h | 16 +++++++++++++
- net/wireless/trace.h | 15 ++++++++++++
- 8 files changed, 109 insertions(+), 5 deletions(-)
-
-diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
-index f9c2cc3..84e769b 100644
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -888,6 +888,24 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
- chandef1->center_freq2 == chandef2->center_freq2);
- }
-
-+/**
-+ * cfg80211_chan_fully_overlap - check if two channel are fully overlapped
-+ * @chandef1: first channel definition
-+ * @chandef2: second channel definition
-+ *
-+ * Return: %true if the channels are valid and fully overlapped, %false otherwise.
-+ */
-+static inline bool
-+cfg80211_chan_fully_overlap(const struct cfg80211_chan_def *chandef1,
-+ const struct cfg80211_chan_def *chandef2)
-+{
-+ return (chandef1->center_freq1 != 0 &&
-+ chandef1->center_freq1 == chandef2->center_freq1 &&
-+ chandef1->width == chandef2->width &&
-+ chandef1->freq1_offset == chandef2->freq1_offset &&
-+ chandef1->center_freq2 == chandef2->center_freq2);
-+}
-+
- /**
- * cfg80211_chandef_is_edmg - check if chandef represents an EDMG channel
- *
-@@ -4642,6 +4660,8 @@ struct cfg80211_ops {
- int (*del_link_station)(struct wiphy *wiphy, struct net_device *dev,
- struct link_station_del_parameters *params);
- void (*skip_cac)(struct wireless_dev *wdev);
-+ void (*check_cac_skip)(struct wiphy *wiphy,
-+ struct cfg80211_chan_def *chandef);
- };
-
- /*
-@@ -5847,6 +5867,8 @@ struct wireless_dev {
- };
- } links[IEEE80211_MLD_MAX_NUM_LINKS];
- u16 valid_links;
-+
-+ bool start_disabled;
- };
-
- static inline const u8 *wdev_address(struct wireless_dev *wdev)
-diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
-index 1293d30..db9d0a8 100644
---- a/include/uapi/linux/nl80211.h
-+++ b/include/uapi/linux/nl80211.h
-@@ -3283,7 +3283,7 @@ enum nl80211_attrs {
- NL80211_ATTR_WIPHY_ANTENNA_GAIN,
-
- /* add attributes here, update the policy in nl80211.c */
--
-+ NL80211_ATTR_START_DISABLED = 999,
- __NL80211_ATTR_AFTER_LAST,
- NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
- NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
-diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
-index 5718c56..9da02d9 100644
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -4889,6 +4889,49 @@ ieee80211_skip_cac(struct wireless_dev *wdev)
- }
- }
-
-+static void
-+ieee80211_check_cac_skip(struct wiphy *wiphy,
-+ struct cfg80211_chan_def *chandef)
-+{
-+ struct ieee80211_local *local = wiphy_priv(wiphy);
-+ struct ieee80211_sub_if_data *s1;
-+ struct ieee80211_sub_if_data *s2;
-+ struct ieee80211_sub_if_data *sdata_sta;
-+ struct ieee80211_if_managed *ifmgd;
-+ struct ieee80211_channel *chan;
-+ struct wireless_dev *wdev;
-+ unsigned int cac_time_ms;
-+
-+ mutex_lock(&local->mtx);
-+ /* Bypass AP's cac if there is a STA associated to the same DFS channel */
-+ list_for_each_entry(s1, &local->interfaces, list) {
-+ ifmgd = &s1->u.mgd;
-+
-+ if (s1->vif.type == NL80211_IFTYPE_STATION && ifmgd->associated)
-+ sdata_sta = s1;
-+ else
-+ continue;
-+
-+ list_for_each_entry(s2, &local->interfaces, list) {
-+ wdev = &s2->wdev;
-+ chan = wdev->links[0].ap.chandef.chan;
-+ if (chan) {
-+ if (!(chan->flags & IEEE80211_CHAN_RADAR))
-+ continue;
-+
-+ if (wdev->identifier != sdata_sta->wdev.identifier &&
-+ chan->dfs_state == NL80211_DFS_USABLE && wdev->cac_started &&
-+ cfg80211_chan_fully_overlap(&sdata_sta->vif.bss_conf.chandef,
-+ &s2->vif.bss_conf.chandef)) {
-+ ieee80211_skip_cac(wdev);
-+ sdata_info(s2, "Skip CAC on the associated STA's chan\n");
-+ }
-+ }
-+ }
-+ }
-+ mutex_unlock(&local->mtx);
-+}
-+
- const struct cfg80211_ops mac80211_config_ops = {
- .add_virtual_intf = ieee80211_add_iface,
- .del_virtual_intf = ieee80211_del_iface,
-@@ -5001,4 +5044,5 @@ const struct cfg80211_ops mac80211_config_ops = {
- .mod_link_station = ieee80211_mod_link_station,
- .del_link_station = ieee80211_del_link_station,
- .skip_cac = ieee80211_skip_cac,
-+ .check_cac_skip = ieee80211_check_cac_skip,
- };
-diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
-index e72cf07..94496d7 100644
---- a/net/mac80211/chan.c
-+++ b/net/mac80211/chan.c
-@@ -567,7 +567,7 @@ bool ieee80211_is_radar_required(struct ieee80211_local *local)
-
- link = rcu_dereference(sdata->link[link_id]);
-
-- if (link && link->radar_required) {
-+ if (link && link->radar_required && sdata->wdev.cac_started) {
- rcu_read_unlock();
- return true;
- }
-diff --git a/net/wireless/chan.c b/net/wireless/chan.c
-index 29b5c2f..bf21f99 100644
---- a/net/wireless/chan.c
-+++ b/net/wireless/chan.c
-@@ -719,16 +719,16 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_P2P_GO:
- for_each_valid_link(wdev, link) {
-- if (wdev->links[link].ap.beacon_interval)
-+ if (wdev->links[link].ap.beacon_interval || wdev->start_disabled)
- return true;
- }
- break;
- case NL80211_IFTYPE_ADHOC:
-- if (wdev->u.ibss.ssid_len)
-+ if (wdev->u.ibss.ssid_len || wdev->start_disabled)
- return true;
- break;
- case NL80211_IFTYPE_MESH_POINT:
-- if (wdev->u.mesh.id_len)
-+ if (wdev->u.mesh.id_len || wdev->start_disabled)
- return true;
- break;
- case NL80211_IFTYPE_STATION:
-diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
-index 202f802..cc8d4b2 100644
---- a/net/wireless/nl80211.c
-+++ b/net/wireless/nl80211.c
-@@ -789,6 +789,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
- NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
- [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
- [NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG },
-+ [NL80211_ATTR_START_DISABLED] = { .type = NLA_FLAG },
- [NL80211_ATTR_AP_SETTINGS_FLAGS] = { .type = NLA_U32 },
- [NL80211_ATTR_EHT_CAPABILITY] =
- NLA_POLICY_BINARY_RANGE(NL80211_EHT_MIN_CAPABILITY_LEN, NL80211_EHT_MAX_CAPABILITY_LEN),
-@@ -5803,6 +5804,11 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
- if (wdev->links[link_id].ap.beacon_interval)
- return -EALREADY;
-
-+ if (info->attrs[NL80211_ATTR_START_DISABLED]) {
-+ wdev->start_disabled = nla_get_flag(info->attrs[NL80211_ATTR_START_DISABLED]);
-+ return 0;
-+ }
-+
- /* these are required for START_AP */
- if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
- !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
-@@ -9846,6 +9852,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
- wdev->cac_started = true;
- wdev->cac_start_time = jiffies;
- wdev->cac_time_ms = cac_time_ms;
-+ err = rdev_check_cac_skip(rdev, &wdev->links[0].ap.chandef);
- }
- unlock:
- wiphy_unlock(wiphy);
-diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
-index ce83152..ffa504a 100644
---- a/net/wireless/rdev-ops.h
-+++ b/net/wireless/rdev-ops.h
-@@ -1508,4 +1508,20 @@ rdev_skip_cac(struct cfg80211_registered_device *rdev,
- return 0;
- }
-
-+static inline int
-+rdev_check_cac_skip(struct cfg80211_registered_device *rdev,
-+ struct cfg80211_chan_def *chandef)
-+{
-+ struct wiphy *wiphy = &rdev->wiphy;
-+
-+ if (!rdev->ops->check_cac_skip)
-+ return -EOPNOTSUPP;
-+
-+ trace_rdev_check_cac_skip(wiphy, chandef);
-+ rdev->ops->check_cac_skip(wiphy, chandef);
-+ trace_rdev_return_void(wiphy);
-+
-+ return 0;
-+}
-+
- #endif /* __CFG80211_RDEV_OPS */
-diff --git a/net/wireless/trace.h b/net/wireless/trace.h
-index d3a98e8..72c8f0e 100644
---- a/net/wireless/trace.h
-+++ b/net/wireless/trace.h
-@@ -3913,6 +3913,21 @@ TRACE_EVENT(rdev_skip_cac,
- TP_printk(WDEV_PR_FMT, WDEV_PR_ARG)
- );
-
-+TRACE_EVENT(rdev_check_cac_skip,
-+ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
-+
-+ TP_ARGS(wiphy, chandef),
-+
-+ TP_STRUCT__entry(WIPHY_ENTRY
-+ CHAN_DEF_ENTRY),
-+
-+ TP_fast_assign(WIPHY_ASSIGN;
-+ CHAN_DEF_ASSIGN(chandef)),
-+
-+ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
-+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
-+);
-+
- #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
-
- #undef TRACE_INCLUDE_PATH
---
-2.25.1
-
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0013-mac80211-mtk-fix-tx-amsdu-aggregation.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0012-mac80211-mtk-fix-tx-amsdu-aggregation.patch
similarity index 87%
rename from recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0013-mac80211-mtk-fix-tx-amsdu-aggregation.patch
rename to recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0012-mac80211-mtk-fix-tx-amsdu-aggregation.patch
index da3eede..6b5dab9 100644
--- a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0013-mac80211-mtk-fix-tx-amsdu-aggregation.patch
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0012-mac80211-mtk-fix-tx-amsdu-aggregation.patch
@@ -1,7 +1,7 @@
-From e07d5401accc96f8380bf42ec454c9ea42255196 Mon Sep 17 00:00:00 2001
+From bb385f098e5f12c7ec0cc5032ac32a27f6713af6 Mon Sep 17 00:00:00 2001
From: TomLiu <tomml.liu@mediatek.com>
Date: Wed, 14 Dec 2022 00:26:50 -0800
-Subject: [PATCH 13/16] mac80211: mtk: fix tx amsdu aggregation
+Subject: [PATCH 12/19] mac80211: mtk: fix tx amsdu aggregation
---
include/net/mac80211.h | 7 +++++++
@@ -9,10 +9,10 @@
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
-index dc4faea..286810b 100644
+index 5908ba3..ad5f217 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -2864,6 +2864,13 @@ static inline void _ieee80211_hw_set(struct ieee80211_hw *hw,
+@@ -2890,6 +2890,13 @@ static inline void _ieee80211_hw_set(struct ieee80211_hw *hw,
}
#define ieee80211_hw_set(hw, flg) _ieee80211_hw_set(hw, IEEE80211_HW_##flg)
@@ -27,7 +27,7 @@
* struct ieee80211_scan_request - hw scan request
*
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
-index 1f46561..318c71e 100755
+index 65c35e4..6b7ec6e 100755
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -66,7 +66,8 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
@@ -51,5 +51,5 @@
capab |= u16_encode_bits(tid, IEEE80211_ADDBA_PARAM_TID_MASK);
capab |= u16_encode_bits(agg_size, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
--
-2.25.1
+2.18.0
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0014-mac80211-mtk-add-fill-receive-path-ops-to-get-wed-id.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0013-mac80211-mtk-add-fill-receive-path-ops-to-get-wed-id.patch
similarity index 91%
rename from recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0014-mac80211-mtk-add-fill-receive-path-ops-to-get-wed-id.patch
rename to recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0013-mac80211-mtk-add-fill-receive-path-ops-to-get-wed-id.patch
index 277e231..8d2067f 100644
--- a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0014-mac80211-mtk-add-fill-receive-path-ops-to-get-wed-id.patch
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0013-mac80211-mtk-add-fill-receive-path-ops-to-get-wed-id.patch
@@ -1,7 +1,7 @@
-From b36c1fd5e967880b025a8301aadbeb832a364639 Mon Sep 17 00:00:00 2001
+From 2a801c07d58b8c9b9d5e9049856c7ef7b504d841 Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Wed, 18 May 2022 15:10:22 +0800
-Subject: [PATCH 14/16] mac80211: mtk: add fill receive path ops to get wed idx
+Subject: [PATCH 13/19] mac80211: mtk: add fill receive path ops to get wed idx
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
---
@@ -13,10 +13,10 @@
mode change 100644 => 100755 net/mac80211/util.c
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
-index 286810b..f68eb7d 100644
+index ad5f217..d1d7fc3 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -1354,7 +1354,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
+@@ -1380,7 +1380,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
* @RX_FLAG_AMPDU_EOF_BIT_KNOWN: The EOF value is known
* @RX_FLAG_RADIOTAP_HE: HE radiotap data is present
* (&struct ieee80211_radiotap_he, mac80211 will fill in
@@ -25,7 +25,7 @@
* - DATA3_DATA_MCS
* - DATA3_DATA_DCM
* - DATA3_CODING
-@@ -1362,7 +1362,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
+@@ -1388,7 +1388,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
* - DATA5_DATA_BW_RU_ALLOC
* - DATA6_NSTS
* - DATA3_STBC
@@ -34,7 +34,7 @@
* from the RX info data, so leave those zeroed when building this data)
* @RX_FLAG_RADIOTAP_HE_MU: HE MU radiotap data is present
* (&struct ieee80211_radiotap_he_mu)
-@@ -1924,6 +1924,12 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
+@@ -1950,6 +1950,12 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
*/
struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif);
@@ -47,7 +47,7 @@
/**
* lockdep_vif_mutex_held - for lockdep checks on link poiners
* @vif: the interface to check
-@@ -4193,6 +4199,8 @@ struct ieee80211_prep_tx_info {
+@@ -4219,6 +4225,8 @@ struct ieee80211_prep_tx_info {
* Note that a sta can also be inserted or removed with valid links,
* i.e. passed to @sta_add/@sta_state with sta->valid_links not zero.
* In fact, cannot change from having valid_links and not having them.
@@ -56,7 +56,7 @@
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
-@@ -4548,6 +4556,9 @@ struct ieee80211_ops {
+@@ -4574,6 +4582,9 @@ struct ieee80211_ops {
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
u16 old_links, u16 new_links);
@@ -153,5 +153,5 @@
* Nothing should have been stuffed into the workqueue during
* the suspend->resume cycle. Since we can't check each caller
--
-2.25.1
+2.18.0
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0015-mac80211-mtk-register-.ndo_setup_tc-to-support-wifi2.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0014-mac80211-mtk-register-.ndo_setup_tc-to-support-wifi2.patch
similarity index 90%
rename from recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0015-mac80211-mtk-register-.ndo_setup_tc-to-support-wifi2.patch
rename to recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0014-mac80211-mtk-register-.ndo_setup_tc-to-support-wifi2.patch
index 60ab368..c32e2a0 100644
--- a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0015-mac80211-mtk-register-.ndo_setup_tc-to-support-wifi2.patch
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0014-mac80211-mtk-register-.ndo_setup_tc-to-support-wifi2.patch
@@ -1,7 +1,7 @@
-From d0bf320b53011bf418e32991f899683280da184f Mon Sep 17 00:00:00 2001
+From a4cd8f81a63827647e88021cbcfc479f024221cb Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Fri, 23 Dec 2022 18:12:41 +0800
-Subject: [PATCH 15/16] mac80211: mtk: register .ndo_setup_tc to support
+Subject: [PATCH 14/19] mac80211: mtk: register .ndo_setup_tc to support
wifi2wifi offload
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
@@ -11,10 +11,10 @@
2 files changed, 31 insertions(+)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
-index f68eb7d..c453b19 100644
+index d1d7fc3..1de9fad 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -4201,6 +4201,8 @@ struct ieee80211_prep_tx_info {
+@@ -4227,6 +4227,8 @@ struct ieee80211_prep_tx_info {
* In fact, cannot change from having valid_links and not having them.
* @net_fill_receive_path: Called from .ndo_fill_receive_path in order to
* get a path for hardware flow offloading
@@ -23,7 +23,7 @@
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
-@@ -4559,6 +4561,9 @@ struct ieee80211_ops {
+@@ -4585,6 +4587,9 @@ struct ieee80211_ops {
int (*net_fill_receive_path)(struct ieee80211_hw *hw,
struct net_device_path_ctx *ctx,
struct net_device_path *path);
@@ -85,5 +85,5 @@
dev->needs_free_netdev = true;
dev->priv_destructor = ieee80211_if_free;
--
-2.25.1
+2.18.0
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0016-mac80211-mtk-fix-build-error-on-Linux-Kernel-5.4.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0015-mac80211-mtk-fix-build-error-on-Linux-Kernel-5.4.patch
similarity index 90%
rename from recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0016-mac80211-mtk-fix-build-error-on-Linux-Kernel-5.4.patch
rename to recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0015-mac80211-mtk-fix-build-error-on-Linux-Kernel-5.4.patch
index bb53403..3b2b718 100644
--- a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0016-mac80211-mtk-fix-build-error-on-Linux-Kernel-5.4.patch
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0015-mac80211-mtk-fix-build-error-on-Linux-Kernel-5.4.patch
@@ -1,7 +1,7 @@
-From 12d2196bb600818a9fc9081037c509f2624b2d25 Mon Sep 17 00:00:00 2001
+From 83f826c468a145fb205cffe0f5fcc8d69143bb78 Mon Sep 17 00:00:00 2001
From: Evelyn Tsai <evelyn.tsai@mediatek.com>
Date: Tue, 13 Dec 2022 09:04:49 +0800
-Subject: [PATCH 16/16] mac80211: mtk: fix build error on Linux Kernel 5.4
+Subject: [PATCH 15/19] mac80211: mtk: fix build error on Linux Kernel 5.4
---
include/linux/ieee80211.h | 8 +++-----
@@ -66,10 +66,10 @@
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
-index cc8d4b2..8928a26 100644
+index 202f802..1035f74 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
-@@ -16448,9 +16448,11 @@ static const struct genl_ops nl80211_ops[] = {
+@@ -16441,9 +16441,11 @@ static const struct genl_ops nl80211_ops[] = {
/* can be retrieved by unprivileged users */
.internal_flags = IFLAGS(NL80211_FLAG_NEED_WIPHY),
},
@@ -81,7 +81,7 @@
{
.cmd = NL80211_CMD_SET_WIPHY,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-@@ -17287,8 +17289,10 @@ static struct genl_family nl80211_fam __genl_ro_after_init = {
+@@ -17280,8 +17282,10 @@ static struct genl_family nl80211_fam __genl_ro_after_init = {
.module = THIS_MODULE,
.ops = nl80211_ops,
.n_ops = ARRAY_SIZE(nl80211_ops),
@@ -93,5 +93,5 @@
.resv_start_op = NL80211_CMD_REMOVE_LINK_STA + 1,
#endif
--
-2.25.1
+2.18.0
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/subsys.inc b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/subsys.inc
index db2b20a..a2d8984 100644
--- a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/subsys.inc
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/subsys.inc
@@ -27,6 +27,10 @@
file://320-wifi-mac80211-use-mesh-header-cache-to-speed-up-mesh.patch \
file://321-mac80211-fix-mesh-forwarding.patch \
file://322-wifi-mac80211-fix-mesh-path-discovery-based-on-unica.patch \
+ file://323-wifi-mac80211-Add-VHT-MU-MIMO-related-flags-in-ieee8.patch \
+ file://324-wifi-mac80211-Add-HE-MU-MIMO-related-flags-in-ieee80.patch \
+ file://325-wifi-mac80211-introduce-ieee80211_refresh_tx_agg_ses.patch \
+ file://326-wifi-mac80211-add-mesh-fast-rx-support.patch \
file://400-allow-ibss-mixed.patch \
file://500-mac80211_configure_antenna_gain.patch \
file://782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch \
@@ -37,15 +41,13 @@
file://mtk-0005-mac80211-mtk-it-s-invalid-case-when-frag_threshold-i.patch \
file://mtk-0006-mac80211-mtk-airtime_flags-depends-on-NL80211_EXT_FE.patch \
file://mtk-0007-mac80211-mtk-add-support-for-runtime-set-inband-disc.patch \
- file://mtk-0008-mac80211-mtk-remove-timerout-handle-for-ax210-iot-is.patch \
file://mtk-0009-cfg80211-mtk-implement-DFS-status-show-cac-and-nop-s.patch \
file://mtk-0010-mac80211-mtk-Set-TWT-Information-Frame-Disabled-bit-.patch \
- file://mtk-0011-mac80211-mtk-fix-the-issue-of-AP-and-STA-starting-on.patch \
- file://mtk-0012-mac80211-mtk-check-the-control-channel-before-downgr.patch \
- file://mtk-0013-mac80211-mtk-fix-tx-amsdu-aggregation.patch \
- file://mtk-0014-mac80211-mtk-add-fill-receive-path-ops-to-get-wed-id.patch \
- file://mtk-0015-mac80211-mtk-register-.ndo_setup_tc-to-support-wifi2.patch \
- file://mtk-0016-mac80211-mtk-fix-build-error-on-Linux-Kernel-5.4.patch \
+ file://mtk-0011-mac80211-mtk-check-the-control-channel-before-downgr.patch \
+ file://mtk-0012-mac80211-mtk-fix-tx-amsdu-aggregation.patch \
+ file://mtk-0013-mac80211-mtk-add-fill-receive-path-ops-to-get-wed-id.patch \
+ file://mtk-0014-mac80211-mtk-register-.ndo_setup_tc-to-support-wifi2.patch \
+ file://mtk-0015-mac80211-mtk-fix-build-error-on-Linux-Kernel-5.4.patch \
file://mtk-0100-mac80211-mtk-add-EHT-BA1024-support.patch \
file://mtk-0101-mac80211-mtk-add-rate-duration-for-EHT-rate.patch \
"
diff --git a/recipes-wifi/linux-mac80211/files/patches/subsys/347-wifi-mac80211-introduce-ieee80211_refresh_tx_agg_ses.patch b/recipes-wifi/linux-mac80211/files/patches/subsys/347-wifi-mac80211-introduce-ieee80211_refresh_tx_agg_ses.patch
new file mode 100644
index 0000000..acd6c12
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches/subsys/347-wifi-mac80211-introduce-ieee80211_refresh_tx_agg_ses.patch
@@ -0,0 +1,60 @@
+From: Ryder Lee <ryder.lee@mediatek.com>
+Date: Sat, 18 Feb 2023 01:50:05 +0800
+Subject: [PATCH] wifi: mac80211: introduce
+ ieee80211_refresh_tx_agg_session_timer()
+
+This allows low level drivers to refresh the tx agg session timer, based on
+querying stats from the firmware usually. Especially for some mt76 devices
+support .net_fill_forward_path would bypass mac80211, which leads to tx BA
+session timeout for certain clients.
+
+Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -5970,6 +5970,18 @@ void ieee80211_queue_delayed_work(struct
+ unsigned long delay);
+
+ /**
++ * ieee80211_refresh_tx_agg_session_timer - Refresh a tx agg session timer.
++ * @sta: the station for which to start a BA session
++ * @tid: the TID to BA on.
++ *
++ * This function allows low level driver to refresh tx agg session timer
++ * to maintain BA session, the session level will still be managed by the
++ * mac80211.
++ */
++void ieee80211_refresh_tx_agg_session_timer(struct ieee80211_sta *sta,
++ u16 tid);
++
++/**
+ * ieee80211_start_tx_ba_session - Start a tx Block Ack session.
+ * @sta: the station for which to start a BA session
+ * @tid: the TID to BA on.
+--- a/net/mac80211/agg-tx.c
++++ b/net/mac80211/agg-tx.c
+@@ -552,6 +552,23 @@ void ieee80211_tx_ba_session_handle_star
+ ieee80211_send_addba_with_timeout(sta, tid_tx);
+ }
+
++void ieee80211_refresh_tx_agg_session_timer(struct ieee80211_sta *pubsta,
++ u16 tid)
++{
++ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
++ struct tid_ampdu_tx *tid_tx;
++
++ if (WARN_ON_ONCE(tid >= IEEE80211_NUM_TIDS))
++ return;
++
++ tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
++ if (!tid_tx)
++ return;
++
++ tid_tx->last_tx = jiffies;
++}
++EXPORT_SYMBOL(ieee80211_refresh_tx_agg_session_timer);
++
+ /*
+ * After accepting the AddBA Response we activated a timer,
+ * resetting it after each frame that we send.
diff --git a/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0009-mac80211-mtk-remove-timerout-handle-for-ax210-iot-is.patch b/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0009-mac80211-mtk-remove-timerout-handle-for-ax210-iot-is.patch
deleted file mode 100644
index 50f2684..0000000
--- a/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0009-mac80211-mtk-remove-timerout-handle-for-ax210-iot-is.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 733277b58ef0b13581c4c22231003f1910d60a5b Mon Sep 17 00:00:00 2001
-From: Evelyn Tsai <evelyn.tsai@mediatek.com>
-Date: Wed, 19 Oct 2022 13:49:21 +0800
-Subject: [PATCH 908/915] mac80211: mtk: remove timerout handle for ax210 iot
- issue
-
-Signed-off-by: Evelyn Tsai <evelyn.tsai@mediatek.com>
----
- net/mac80211/agg-tx.c | 7 +++----
- 1 file changed, 3 insertions(+), 4 deletions(-)
- mode change 100644 => 100755 net/mac80211/agg-tx.c
-
-diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
-old mode 100644
-new mode 100755
-index 1deb3d8..c30f02d
---- a/net/mac80211/agg-tx.c
-+++ b/net/mac80211/agg-tx.c
-@@ -568,10 +568,9 @@ static void sta_tx_agg_session_timer_expired(struct timer_list *t)
- }
-
- timeout = tid_tx->last_tx + TU_TO_JIFFIES(tid_tx->timeout);
-- if (time_is_after_jiffies(timeout)) {
-- mod_timer(&tid_tx->session_timer, timeout);
-- return;
-- }
-+ /* remove timerout handle for ax210 iot issue */
-+ mod_timer(&tid_tx->session_timer, timeout);
-+ return;
-
- ht_dbg(sta->sdata, "tx session timer expired on %pM tid %d\n",
- sta->sta.addr, tid);
---
-2.36.1
-
diff --git a/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0014--mac80211-mtk-track-obss-color-bitmap.patch b/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0014--mac80211-mtk-track-obss-color-bitmap.patch
new file mode 100644
index 0000000..18d8aab
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0014--mac80211-mtk-track-obss-color-bitmap.patch
@@ -0,0 +1,102 @@
+From 40ceb2dcc486ddefb5e4cb69e4cd86906242872c Mon Sep 17 00:00:00 2001
+From: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
+Date: Tue, 15 Nov 2022 06:35:48 +0800
+Subject: [PATCH] mac80211: mtk: track obss color bitmap
+
+Track OBSS BSS color when receive their beacon.
+
+Adding 2 tracepoint for debug, usage:
+echo 1 > /sys/kernel/debug/tracing/events/mac80211/bss_color_bitmap/enable
+echo 1 > /sys/kernel/debug/tracing/events/mac80211/bss_color_collision/enable
+---
+ include/net/cfg80211.h | 1 +
+ net/mac80211/rx.c | 14 ++++++++++++--
+ net/mac80211/trace.h | 35 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 48 insertions(+), 2 deletions(-)
+
+diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
+index c4c0926..e5175c2 100644
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -307,6 +307,7 @@ struct cfg80211_he_bss_color {
+ u8 color;
+ bool enabled;
+ bool partial;
++ u64 used_color_bitmap;
+ };
+
+ /**
+diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
+index eb16838..4a6491c 100644
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -3219,9 +3219,18 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx)
+
+ color = le32_get_bits(he_oper->he_oper_params,
+ IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
+- if (color == bss_conf->he_bss_color.color)
++
++ bss_conf->he_bss_color.used_color_bitmap |= BIT_ULL(color);
++
++ trace_bss_color_bitmap(color,
++ bss_conf->he_bss_color.used_color_bitmap);
++
++ if (color == bss_conf->he_bss_color.color) {
++ trace_bss_color_collision(color);
++
+ ieeee80211_obss_color_collision_notify(&rx->sdata->vif,
+- BIT_ULL(color));
++ bss_conf->he_bss_color.used_color_bitmap);
++ }
+ }
+ }
+
+diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
+index d91498f..013f5e4 100644
+--- a/net/mac80211/trace.h
++++ b/net/mac80211/trace.h
+@@ -2899,6 +2899,41 @@ DEFINE_EVENT(sta_event, drv_net_fill_forward_path,
+ TP_ARGS(local, sdata, sta)
+ );
+
++TRACE_EVENT(bss_color_bitmap,
++ TP_PROTO(u8 color,
++ u64 color_bitmap),
++
++ TP_ARGS(color, color_bitmap),
++
++ TP_STRUCT__entry(
++ __field(u8, color)
++ __field(u64, color_bitmap)
++ ),
++
++ TP_fast_assign(
++ __entry->color = color;
++ __entry->color_bitmap = color_bitmap;
++ ),
++
++ TP_printk(
++ "color=%u color_bitmap=0x%llx", __entry->color, __entry->color_bitmap
++ )
++);
++
++TRACE_EVENT(bss_color_collision,
++ TP_PROTO(u8 color),
++
++ TP_ARGS(color),
++
++ TP_STRUCT__entry(__field(u8, color)),
++
++ TP_fast_assign(
++ __entry->color = color;
++ ),
++
++ TP_printk("collision detected on color %u", __entry->color)
++);
++
+ #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
+
+ #undef TRACE_INCLUDE_PATH
+--
+2.36.1
+
diff --git a/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0015-mac80211-mtk-aging-color-bitmap.patch b/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0015-mac80211-mtk-aging-color-bitmap.patch
new file mode 100644
index 0000000..4ed9142
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0015-mac80211-mtk-aging-color-bitmap.patch
@@ -0,0 +1,126 @@
+From f6cd955e1c042a00691fa80d231495024cfcf7a5 Mon Sep 17 00:00:00 2001
+From: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
+Date: Tue, 15 Nov 2022 11:03:22 +0800
+Subject: [PATCH] mac80211: mtk: ageout color bitmap
+
+Adding a periodic work which runs once per second to check BSS color.
+OBSS BSS Color will be ageout if not seen for 10 seconds.
+---
+ include/net/cfg80211.h | 1 +
+ net/mac80211/cfg.c | 25 +++++++++++++++++++++++++
+ net/mac80211/ieee80211_i.h | 4 ++++
+ net/mac80211/iface.c | 5 +++++
+ net/mac80211/rx.c | 1 +
+ 5 files changed, 36 insertions(+)
+
+diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
+index e5175c2..3e826f0 100644
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -308,6 +308,7 @@ struct cfg80211_he_bss_color {
+ bool enabled;
+ bool partial;
+ u64 used_color_bitmap;
++ u64 color_last_seen[64];
+ };
+
+ /**
+diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
+index a7b6284..f084912 100644
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -4425,6 +4425,31 @@ unlock:
+ sdata_unlock(sdata);
+ }
+
++void ieee80211_color_aging_work(struct work_struct *work)
++{
++ struct ieee80211_sub_if_data *sdata =
++ container_of(work, struct ieee80211_sub_if_data,
++ color_aging_work.work);
++ struct cfg80211_he_bss_color *he_bss_color = &sdata->vif.bss_conf.he_bss_color;
++ int i = 0;
++
++ sdata_lock(sdata);
++
++ for (i = 0; i < IEEE80211_BSS_COLOR_MAX; i++) {
++ /* ageout if not seen for a period */
++ if ((he_bss_color->used_color_bitmap & BIT_ULL(i)) &&
++ time_before(he_bss_color->color_last_seen[i],
++ jiffies - IEEE80211_BSS_COLOR_AGEOUT_TIME * HZ)) {
++ he_bss_color->used_color_bitmap &= ~BIT_ULL(i);
++ }
++ }
++
++ ieee80211_queue_delayed_work(&sdata->local->hw,
++ &sdata->color_aging_work, HZ);
++
++ sdata_unlock(sdata);
++}
++
+ void ieee80211_color_change_finish(struct ieee80211_vif *vif)
+ {
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
+index 6edabd8..415f202 100644
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1033,6 +1033,8 @@ struct ieee80211_sub_if_data {
+ } debugfs;
+ #endif
+
++ struct delayed_work color_aging_work;
++
+ /* must be last, dynamically sized area in this! */
+ struct ieee80211_vif vif;
+ };
+@@ -1811,8 +1813,11 @@ void ieee80211_csa_finalize_work(struct work_struct *work);
+ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_csa_settings *params);
+
++#define IEEE80211_BSS_COLOR_AGEOUT_TIME 10
++#define IEEE80211_BSS_COLOR_MAX 64
+ /* color change handling */
+ void ieee80211_color_change_finalize_work(struct work_struct *work);
++void ieee80211_color_aging_work(struct work_struct *work);
+
+ /* interface handling */
+ #define MAC80211_SUPPORTED_FEATURES_TX (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \
+diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
+index 43f6cb0..7f26828 100644
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -466,6 +466,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
+ cancel_work_sync(&sdata->color_change_finalize_work);
+
+ cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
++ if (sdata->vif.type == NL80211_IFTYPE_AP)
++ cancel_delayed_work_sync(&sdata->color_aging_work);
+
+ if (sdata->wdev.cac_started) {
+ chandef = sdata->vif.bss_conf.chandef;
+@@ -1804,6 +1806,9 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
+ skb_queue_head_init(&sdata->u.ap.ps.bc_buf);
+ INIT_LIST_HEAD(&sdata->u.ap.vlans);
+ sdata->vif.bss_conf.bssid = sdata->vif.addr;
++ INIT_DELAYED_WORK(&sdata->color_aging_work, ieee80211_color_aging_work);
++ ieee80211_queue_delayed_work(&sdata->local->hw,
++ &sdata->color_aging_work, 0);
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ type = NL80211_IFTYPE_STATION;
+diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
+index 789a41b..4a6491c 100644
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -3221,6 +3221,7 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx)
+ IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
+
+ bss_conf->he_bss_color.used_color_bitmap |= BIT_ULL(color);
++ bss_conf->he_bss_color.color_last_seen[color] = jiffies;
+
+ trace_bss_color_bitmap(color,
+ bss_conf->he_bss_color.used_color_bitmap);
+--
+2.39.0
+
diff --git a/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0015-nl80211-mtk-Mark-DFS-channel-as-available-for-CSA.patch b/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0015-nl80211-mtk-Mark-DFS-channel-as-available-for-CSA.patch
new file mode 100644
index 0000000..eff574e
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0015-nl80211-mtk-Mark-DFS-channel-as-available-for-CSA.patch
@@ -0,0 +1,28 @@
+From 20d6ed31c0e6c15cfbc120bea6a8729121560371 Mon Sep 17 00:00:00 2001
+From: "himanshu.goyal" <himanshu.goyal@mediatek.com>
+Date: Tue, 21 Feb 2023 15:24:09 +0800
+Subject: [PATCH] nl80211: mtk: Mark DFS channel as available for CSA.
+
+---
+ net/wireless/nl80211.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index 8dc928d..a02aacb 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -3193,6 +3193,11 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
+ return -EINVAL;
+ }
+
++ /* Use RADAR_BACKGROUND attribute here for skipping CAC */
++ if (info->attrs[NL80211_ATTR_RADAR_BACKGROUND]) {
++ cfg80211_set_dfs_state(&rdev->wiphy, chandef, NL80211_DFS_AVAILABLE);
++ }
++
+ if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
+ IEEE80211_CHAN_DISABLED)) {
+ NL_SET_ERR_MSG(extack, "(extension) channel is disabled");
+--
+2.18.0
+
diff --git a/recipes-wifi/linux-mac80211/files/patches/subsys/subsys.inc b/recipes-wifi/linux-mac80211/files/patches/subsys/subsys.inc
index ae088f6..dcebb38 100644
--- a/recipes-wifi/linux-mac80211/files/patches/subsys/subsys.inc
+++ b/recipes-wifi/linux-mac80211/files/patches/subsys/subsys.inc
@@ -42,6 +42,7 @@
file://344-v6.1-wifi-cfg80211-fix-ieee80211_data_to_8023_exthdr-hand.patch \
file://345-v6.1-wifi-mac80211-do-not-drop-packets-smaller-than-the-L.patch \
file://346-v6.0-wifi-mac80211-fix-mesh-airtime-link-metric-estimatin.patch \
+ file://347-wifi-mac80211-introduce-ieee80211_refresh_tx_agg_ses.patch \
file://363-v5.19-bss-color-collision.patch \
file://364-mac80211-add-support-for-restricting-netdev-features.patch \
file://400-allow-ibss-mixed.patch \
@@ -57,12 +58,14 @@
file://mtk-0006-mac80211-mtk-add-support-for-runtime-set-inband-disc.patch \
file://mtk-0007-mac80211-mtk-add-s1g-category-to-_ieee80211_is_robus.patch \
file://mtk-0008-mac80211-mtk-make-4addr-null-frames-using-min_rate-f.patch \
- file://mtk-0009-mac80211-mtk-remove-timerout-handle-for-ax210-iot-is.patch \
file://mtk-0010-cfg80211-mtk-implement-DFS-status-show-cac-and-nop-s.patch \
file://mtk-0011-mac80211-mtk-Set-TWT-Information-Frame-Disabled-bit-.patch \
file://mtk-0012-mac80211-mtk-check-the-control-channel-before-downgr.patch \
file://mtk-0013-mac80211-mtk-fix-tx-amsdu-aggregation.patch \
+ file://mtk-0014--mac80211-mtk-track-obss-color-bitmap.patch \
file://mtk-0014-mac80211-mtk-add-sta-assisted-DFS-state-update-mecha.patch \
+ file://mtk-0015-mac80211-mtk-aging-color-bitmap.patch \
+ file://mtk-0015-nl80211-mtk-Mark-DFS-channel-as-available-for-CSA.patch \
file://mtk-9900-mac80211-mtk-mask-kernel-version-limitation-and-fil.patch \
file://mtk-9901-mac80211-mtk-add-fill-receive-path-ops-to-get-wed-i.patch \
file://mtk-9902-mac80211-mtk-register-.ndo_setup_tc-to-support-wifi2.patch \
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0000-sync-to-master.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0000-sync-to-master.patch
deleted file mode 100644
index 44a01ec..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0000-sync-to-master.patch
+++ /dev/null
@@ -1,249 +0,0 @@
-diff --git a/eeprom.c b/eeprom.c
-index 0a88048b..ea54b7af 100644
---- a/eeprom.c
-+++ b/eeprom.c
-@@ -138,6 +138,7 @@ mt76_find_power_limits_node(struct mt76_dev *dev)
- {
- struct device_node *np = dev->dev->of_node;
- const char *const region_names[] = {
-+ [NL80211_DFS_UNSET] = "ww",
- [NL80211_DFS_ETSI] = "etsi",
- [NL80211_DFS_FCC] = "fcc",
- [NL80211_DFS_JP] = "jp",
-diff --git a/mt76_connac_mac.c b/mt76_connac_mac.c
-index 614df85e..aed4ee95 100644
---- a/mt76_connac_mac.c
-+++ b/mt76_connac_mac.c
-@@ -823,7 +823,6 @@ void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev,
- HE_BITS(DATA2_TXOP_KNOWN),
- };
- u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1;
-- u32 txbf_mask = is_mt7996(dev) ? BIT(11) : BIT(10);
- struct ieee80211_radiotap_he *he;
-
- status->flag |= RX_FLAG_RADIOTAP_HE;
-@@ -837,7 +836,7 @@ void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev,
- he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) |
- le16_encode_bits(ltf_size,
- IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
-- if (le32_to_cpu(rxv[0]) & txbf_mask)
-+ if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
- he->data5 |= HE_BITS(DATA5_TXBF);
- he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) |
- HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]);
-diff --git a/mt76x0/usb_mcu.c b/mt76x0/usb_mcu.c
-index 45502fd4..6dc1f51f 100644
---- a/mt76x0/usb_mcu.c
-+++ b/mt76x0/usb_mcu.c
-@@ -148,6 +148,7 @@ static int mt76x0u_load_firmware(struct mt76x02_dev *dev)
- mt76_wr(dev, MT_USB_DMA_CFG, val);
-
- ret = mt76x0u_upload_firmware(dev, hdr);
-+ mt76x02_set_ethtool_fwver(dev, hdr);
- release_firmware(fw);
-
- mt76_wr(dev, MT_FCE_PSE_CTRL, 1);
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 674cea1a..c9a9f0e3 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -12,6 +12,10 @@
-
- #define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2)
-
-+#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f)
-+#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\
-+ IEEE80211_RADIOTAP_HE_##f)
-+
- static const struct mt7996_dfs_radar_spec etsi_radar_specs = {
- .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
- .radar_pattern = {
-@@ -251,6 +255,178 @@ void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
- mt76_clear(dev, addr, BIT(5));
- }
-
-+static void
-+mt7996_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
-+ struct ieee80211_radiotap_he *he,
-+ __le32 *rxv)
-+{
-+ u32 ru_h, ru_l;
-+ u8 ru, offs = 0;
-+
-+ ru_l = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC_L);
-+ ru_h = le32_get_bits(rxv[1], MT_PRXV_HE_RU_ALLOC_H);
-+ ru = (u8)(ru_l | ru_h << 4);
-+
-+ status->bw = RATE_INFO_BW_HE_RU;
-+
-+ switch (ru) {
-+ case 0 ... 36:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
-+ offs = ru;
-+ break;
-+ case 37 ... 52:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
-+ offs = ru - 37;
-+ break;
-+ case 53 ... 60:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
-+ offs = ru - 53;
-+ break;
-+ case 61 ... 64:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
-+ offs = ru - 61;
-+ break;
-+ case 65 ... 66:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
-+ offs = ru - 65;
-+ break;
-+ case 67:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
-+ break;
-+ case 68:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
-+ break;
-+ }
-+
-+ he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
-+ he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
-+ le16_encode_bits(offs,
-+ IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
-+}
-+
-+static void
-+mt7996_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32 *rxv)
-+{
-+ struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
-+ static const struct ieee80211_radiotap_he_mu mu_known = {
-+ .flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
-+ HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
-+ HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
-+ HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
-+ .flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
-+ };
-+ struct ieee80211_radiotap_he_mu *he_mu = NULL;
-+
-+ status->flag |= RX_FLAG_RADIOTAP_HE_MU;
-+
-+ he_mu = skb_push(skb, sizeof(mu_known));
-+ memcpy(he_mu, &mu_known, sizeof(mu_known));
-+
-+#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)
-+
-+ he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
-+ if (status->he_dcm)
-+ he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm);
-+
-+ he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
-+ MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
-+ le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER));
-+
-+ he_mu->ru_ch1[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU0);
-+
-+ if (status->bw >= RATE_INFO_BW_40) {
-+ he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
-+ he_mu->ru_ch2[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU1);
-+ }
-+
-+ if (status->bw >= RATE_INFO_BW_80) {
-+ he_mu->ru_ch1[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU2);
-+ he_mu->ru_ch2[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU3);
-+ }
-+}
-+
-+static void
-+mt7996_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u8 mode)
-+{
-+ struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
-+ static const struct ieee80211_radiotap_he known = {
-+ .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
-+ HE_BITS(DATA1_DATA_DCM_KNOWN) |
-+ HE_BITS(DATA1_STBC_KNOWN) |
-+ HE_BITS(DATA1_CODING_KNOWN) |
-+ HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
-+ HE_BITS(DATA1_DOPPLER_KNOWN) |
-+ HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
-+ HE_BITS(DATA1_BSS_COLOR_KNOWN),
-+ .data2 = HE_BITS(DATA2_GI_KNOWN) |
-+ HE_BITS(DATA2_TXBF_KNOWN) |
-+ HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
-+ HE_BITS(DATA2_TXOP_KNOWN),
-+ };
-+ struct ieee80211_radiotap_he *he = NULL;
-+ u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1;
-+
-+ status->flag |= RX_FLAG_RADIOTAP_HE;
-+
-+ he = skb_push(skb, sizeof(known));
-+ memcpy(he, &known, sizeof(known));
-+
-+ he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) |
-+ HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]);
-+ he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]);
-+ he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) |
-+ le16_encode_bits(ltf_size,
-+ IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
-+ if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
-+ he->data5 |= HE_BITS(DATA5_TXBF);
-+ he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) |
-+ HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]);
-+
-+ switch (mode) {
-+ case MT_PHY_TYPE_HE_SU:
-+ he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
-+ HE_BITS(DATA1_UL_DL_KNOWN) |
-+ HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
-+ HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
-+
-+ he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) |
-+ HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
-+ break;
-+ case MT_PHY_TYPE_HE_EXT_SU:
-+ he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
-+ HE_BITS(DATA1_UL_DL_KNOWN) |
-+ HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
-+
-+ he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
-+ break;
-+ case MT_PHY_TYPE_HE_MU:
-+ he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
-+ HE_BITS(DATA1_UL_DL_KNOWN);
-+
-+ he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
-+ he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]);
-+
-+ mt7996_mac_decode_he_radiotap_ru(status, he, rxv);
-+ mt7996_mac_decode_he_mu_radiotap(skb, rxv);
-+ break;
-+ case MT_PHY_TYPE_HE_TB:
-+ he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
-+ HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
-+ HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
-+ HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
-+
-+ he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) |
-+ HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) |
-+ HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) |
-+ HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]);
-+
-+ mt7996_mac_decode_he_radiotap_ru(status, he, rxv);
-+ break;
-+ default:
-+ break;
-+ }
-+}
-+
- /* The HW does not translate the mac header to 802.3 for mesh point */
- static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
- {
-@@ -686,8 +862,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
- }
-
- if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
-- mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv,
-- mode);
-+ mt7996_mac_decode_he_radiotap(skb, rxv, mode);
-
- if (!status->wcid || !ieee80211_is_data_qos(fc))
- return 0;
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0001-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_tx_compl.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0001-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_tx_compl.patch
deleted file mode 100644
index 1022535..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0001-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_tx_compl.patch
+++ /dev/null
@@ -1,96 +0,0 @@
-From 6767bcfec5f48f14fdf63c9699c63e6bc741ad74 Mon Sep 17 00:00:00 2001
-From: Shayne Chen <shayne.chen@mediatek.com>
-Date: Fri, 3 Feb 2023 11:00:59 +0800
-Subject: [PATCH 1/7] Revert "wifi: mt76: mt7996: rely on
- mt76_connac_tx_complete_skb"
-
-This reverts commit 8688756305c643b8a296c16d0626732aaae1d02a.
----
- mt7996/mac.c | 21 +++++++++++++++++++++
- mt7996/mac.h | 13 +++++++++++++
- mt7996/mmio.c | 2 +-
- mt7996/mt7996.h | 1 +
- 4 files changed, 36 insertions(+), 1 deletion(-)
-
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index c9a9f0e3..0d718598 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -1565,6 +1565,27 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
- }
- }
-
-+void mt7996_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
-+{
-+ if (!e->txwi) {
-+ dev_kfree_skb_any(e->skb);
-+ return;
-+ }
-+
-+ /* error path */
-+ if (e->skb == DMA_DUMMY_DATA) {
-+ struct mt76_connac_txp_common *txp;
-+ struct mt76_txwi_cache *t;
-+
-+ txp = mt7996_txwi_to_txp(mdev, e->txwi);
-+ t = mt76_token_put(mdev, le16_to_cpu(txp->fw.token));
-+ e->skb = t ? t->skb : NULL;
-+ }
-+
-+ if (e->skb)
-+ mt76_tx_complete_skb(mdev, e->wcid, e->skb);
-+}
-+
- void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy)
- {
- struct mt7996_dev *dev = phy->dev;
-diff --git a/mt7996/mac.h b/mt7996/mac.h
-index 27184cba..10e08d66 100644
---- a/mt7996/mac.h
-+++ b/mt7996/mac.h
-@@ -371,4 +371,17 @@ struct mt7996_dfs_radar_spec {
- struct mt7996_dfs_pattern radar_pattern[16];
- };
-
-+static inline struct mt76_connac_txp_common *
-+mt7996_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t)
-+{
-+ u8 *txwi;
-+
-+ if (!t)
-+ return NULL;
-+
-+ txwi = mt76_get_txwi_ptr(dev, t);
-+
-+ return (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
-+}
-+
- #endif
-diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-index 902370a2..2237f50a 100644
---- a/mt7996/mmio.c
-+++ b/mt7996/mmio.c
-@@ -326,7 +326,7 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
- SURVEY_INFO_TIME_BSS_RX,
- .token_size = MT7996_TOKEN_SIZE,
- .tx_prepare_skb = mt7996_tx_prepare_skb,
-- .tx_complete_skb = mt76_connac_tx_complete_skb,
-+ .tx_complete_skb = mt7996_tx_complete_skb,
- .rx_skb = mt7996_queue_rx_skb,
- .rx_check = mt7996_rx_check,
- .rx_poll_complete = mt7996_rx_poll_complete,
-diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 018dfd2b..13f22432 100644
---- a/mt7996/mt7996.h
-+++ b/mt7996/mt7996.h
-@@ -508,6 +508,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- enum mt76_txq_id qid, struct mt76_wcid *wcid,
- struct ieee80211_sta *sta,
- struct mt76_tx_info *tx_info);
-+void mt7996_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
- void mt7996_tx_token_put(struct mt7996_dev *dev);
- void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
- struct sk_buff *skb, u32 *info);
---
-2.25.1
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0001-wifi-mt76-mt7996-add-eht-rx-rate-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0001-wifi-mt76-mt7996-add-eht-rx-rate-support.patch
new file mode 100644
index 0000000..66ab9ce
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0001-wifi-mt76-mt7996-add-eht-rx-rate-support.patch
@@ -0,0 +1,92 @@
+From 995b09b6a62700568b36cc2e4ae6b6063456942b Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Fri, 10 Feb 2023 17:39:23 +0800
+Subject: [PATCH 01/19] wifi: mt76: mt7996: add eht rx rate support
+
+Add support to report eht rx rate.
+
+Change-Id: Iee067d891bd634a918c942c2ba90ae72cd40c538
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mac80211.c | 11 ++++++++---
+ mt76.h | 18 ++++++++++++++----
+ mt7996/mac.c | 9 +++++----
+ 3 files changed, 27 insertions(+), 11 deletions(-)
+
+diff --git a/mac80211.c b/mac80211.c
+index 87902f4b..e53166fc 100644
+--- a/mac80211.c
++++ b/mac80211.c
+@@ -1067,9 +1067,14 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
+ status->enc_flags = mstat.enc_flags;
+ status->encoding = mstat.encoding;
+ status->bw = mstat.bw;
+- status->he_ru = mstat.he_ru;
+- status->he_gi = mstat.he_gi;
+- status->he_dcm = mstat.he_dcm;
++ if (status->encoding == RX_ENC_EHT) {
++ status->eht.ru = mstat.eht.ru;
++ status->eht.gi = mstat.eht.gi;
++ } else {
++ status->he_ru = mstat.he_ru;
++ status->he_gi = mstat.he_gi;
++ status->he_dcm = mstat.he_dcm;
++ }
+ status->rate_idx = mstat.rate_idx;
+ status->nss = mstat.nss;
+ status->band = mstat.band;
+diff --git a/mt76.h b/mt76.h
+index 183b0fc5..c3d1313e 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -621,12 +621,22 @@ struct mt76_rx_status {
+ u16 freq;
+ u32 flag;
+ u8 enc_flags;
+- u8 encoding:2, bw:3, he_ru:3;
+- u8 he_gi:2, he_dcm:1;
++ u8 encoding:3, bw:4;
++ union {
++ struct {
++ u8 he_ru:3;
++ u8 he_gi:2;
++ u8 he_dcm:1;
++ };
++ struct {
++ u8 ru:4;
++ u8 gi:2;
++ } eht;
++ };
++
+ u8 amsdu:1, first_amsdu:1, last_amsdu:1;
+ u8 rate_idx;
+- u8 nss;
+- u8 band;
++ u8 nss:5, band:3;
+ s8 signal;
+ u8 chains;
+ s8 chain_signal[IEEE80211_MAX_CHAINS];
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 3c3506c7..d811b4e0 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -572,11 +572,12 @@ mt7996_mac_fill_rx_rate(struct mt7996_dev *dev,
+ case MT_PHY_TYPE_EHT_SU:
+ case MT_PHY_TYPE_EHT_TRIG:
+ case MT_PHY_TYPE_EHT_MU:
+- /* TODO: currently report rx rate with HE rate */
+ status->nss = nss;
+- status->encoding = RX_ENC_HE;
+- bw = min_t(int, bw, IEEE80211_STA_RX_BW_160);
+- i = min_t(int, i & 0xf, 11);
++ status->encoding = RX_ENC_EHT;
++ i &= GENMASK(3, 0);
++
++ if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
++ status->eht.gi = gi;
+ break;
+ default:
+ return -EINVAL;
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0002-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_skb_.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0002-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_skb_.patch
deleted file mode 100644
index fb6581a..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0002-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_skb_.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 9c2313ddded0179ae1a9e6112e2762a1a3e958d7 Mon Sep 17 00:00:00 2001
-From: Shayne Chen <shayne.chen@mediatek.com>
-Date: Fri, 3 Feb 2023 11:01:11 +0800
-Subject: [PATCH 2/7] Revert "wifi: mt76: mt7996: rely on
- mt76_connac_txp_skb_unmap"
-
-This reverts commit bdb7dc38a6d150b5aa4b09b82a8954c6bb49ba4a.
----
- mt7996/mac.c | 14 +++++++++++++-
- 1 file changed, 13 insertions(+), 1 deletion(-)
-
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 0d718598..df97d7cf 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -1187,6 +1187,18 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
- ieee80211_start_tx_ba_session(sta, tid, 0);
- }
-
-+static void
-+mt7996_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
-+{
-+ struct mt76_connac_txp_common *txp;
-+ int i;
-+
-+ txp = mt7996_txwi_to_txp(dev, t);
-+ for (i = 0; i < txp->fw.nbuf; i++)
-+ dma_unmap_single(dev->dev, le32_to_cpu(txp->fw.buf[i]),
-+ le16_to_cpu(txp->fw.len[i]), DMA_TO_DEVICE);
-+}
-+
- static void
- mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
- struct ieee80211_sta *sta, struct list_head *free_list)
-@@ -1196,7 +1208,7 @@ mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
- __le32 *txwi;
- u16 wcid_idx;
-
-- mt76_connac_txp_skb_unmap(mdev, t);
-+ mt7996_txp_skb_unmap(mdev, t);
- if (!t->skb)
- goto out;
-
---
-2.25.1
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0002-wifi-mt76-mt7996-let-non-bufferable-MMPDUs-use-corre.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0002-wifi-mt76-mt7996-let-non-bufferable-MMPDUs-use-corre.patch
new file mode 100644
index 0000000..872ef03
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0002-wifi-mt76-mt7996-let-non-bufferable-MMPDUs-use-corre.patch
@@ -0,0 +1,92 @@
+From 5b858f7f944144d99fb0ca1ef26d6b8c6719890c Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Thu, 16 Feb 2023 10:52:22 +0800
+Subject: [PATCH 02/19] wifi: mt76: mt7996: let non-bufferable MMPDUs use
+ correct hw queue
+
+non-bufferable MMPDUs are expected to use ALTX hw queue, but current
+condition in mt7996_mac_write_txwi() won't let their tx descriptor
+be filled with correct q_idx. Fix this by passing qid parameter into
+the funciton.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: I18bd1a5ea698912c7aa8f4d4317d4a428d4ac440
+---
+ mt7996/mac.c | 9 +++++----
+ mt7996/mcu.c | 4 ++--
+ mt7996/mt7996.h | 3 ++-
+ 3 files changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index d811b4e0..198eb711 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -982,7 +982,8 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
+ }
+
+ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+- struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
++ struct sk_buff *skb, struct mt76_wcid *wcid,
++ enum mt76_txq_id qid, int pid,
+ struct ieee80211_key_conf *key, u32 changed)
+ {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+@@ -1014,7 +1015,7 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+ } else if (beacon) {
+ p_fmt = MT_TX_TYPE_FW;
+ q_idx = MT_LMAC_BCN0;
+- } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) {
++ } else if (qid >= MT_TXQ_PSD) {
+ p_fmt = MT_TX_TYPE_CT;
+ q_idx = MT_LMAC_ALTX0;
+ } else {
+@@ -1123,8 +1124,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ memset(txwi_ptr, 0, MT_TXD_SIZE);
+ /* Transmit non qos data by 802.11 header and need to fill txd by host*/
+ if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
+- mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid,
+- key, 0);
++ mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, qid,
++ pid, key, 0);
+
+ txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
+ for (i = 0; i < nbuf; i++) {
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 8ad51cbf..dbe10576 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -1906,7 +1906,7 @@ mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ }
+
+ buf = (u8 *)bcn + sizeof(*bcn) - MAX_BEACON_SIZE;
+- mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL,
++ mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, 0, NULL,
+ BSS_CHANGED_BEACON);
+ memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
+ }
+@@ -2115,7 +2115,7 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
+
+ buf = (u8 *)tlv + sizeof(*discov) - MAX_INBAND_FRAME_SIZE;
+
+- mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL,
++ mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, 0, NULL,
+ changed);
+
+ memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 018dfd2b..d20aa5f2 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -487,7 +487,8 @@ void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band);
+ void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
+ struct ieee80211_vif *vif, bool enable);
+ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+- struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
++ struct sk_buff *skb, struct mt76_wcid *wcid,
++ enum mt76_txq_id qid, int pid,
+ struct ieee80211_key_conf *key, u32 changed);
+ void mt7996_mac_set_timing(struct mt7996_phy *phy);
+ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0003-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_comm.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0003-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_comm.patch
deleted file mode 100644
index 43ea6c9..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0003-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_comm.patch
+++ /dev/null
@@ -1,163 +0,0 @@
-From 8ba17e7cdbb5e921edd03102476cd8fb4f4e1b31 Mon Sep 17 00:00:00 2001
-From: Shayne Chen <shayne.chen@mediatek.com>
-Date: Fri, 3 Feb 2023 11:12:46 +0800
-Subject: [PATCH 3/7] Revert "wifi: mt76: mt7996: rely on
- mt76_connac_txp_common structure"
-
-This reverts commit 321edbb414dcc03d349bddd08916b7cc531802e8.
----
- mt7996/mac.c | 38 +++++++++++++++++++-------------------
- mt7996/mac.h | 15 +++++++++++++--
- mt7996/mmio.c | 2 +-
- 3 files changed, 33 insertions(+), 22 deletions(-)
-
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index df97d7cf..e5b5fed6 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -1088,8 +1088,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
- struct ieee80211_key_conf *key = info->control.hw_key;
- struct ieee80211_vif *vif = info->control.vif;
-- struct mt76_connac_txp_common *txp;
- struct mt76_txwi_cache *t;
-+ struct mt7996_txp *txp;
- int id, i, pid, nbuf = tx_info->nbuf - 1;
- bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
- u8 *txwi = (u8 *)txwi_ptr;
-@@ -1123,35 +1123,35 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid,
- key, 0);
-
-- txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
-+ txp = (struct mt7996_txp *)(txwi + MT_TXD_SIZE);
- for (i = 0; i < nbuf; i++) {
-- txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
-- txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
-+ txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
-+ txp->len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
- }
-- txp->fw.nbuf = nbuf;
-+ txp->nbuf = nbuf;
-
-- txp->fw.flags = cpu_to_le16(MT_CT_INFO_FROM_HOST);
-+ txp->flags = cpu_to_le16(MT_CT_INFO_FROM_HOST);
-
- if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
-- txp->fw.flags |= cpu_to_le16(MT_CT_INFO_APPLY_TXD);
-+ txp->flags |= cpu_to_le16(MT_CT_INFO_APPLY_TXD);
-
- if (!key)
-- txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
-+ txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
-
- if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control))
-- txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
-+ txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
-
- if (vif) {
- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
-
-- txp->fw.bss_idx = mvif->mt76.idx;
-+ txp->bss_idx = mvif->mt76.idx;
- }
-
-- txp->fw.token = cpu_to_le16(id);
-+ txp->token = cpu_to_le16(id);
- if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags))
-- txp->fw.rept_wds_wcid = cpu_to_le16(wcid->idx);
-+ txp->rept_wds_wcid = cpu_to_le16(wcid->idx);
- else
-- txp->fw.rept_wds_wcid = cpu_to_le16(0xfff);
-+ txp->rept_wds_wcid = cpu_to_le16(0xfff);
- tx_info->skb = DMA_DUMMY_DATA;
-
- /* pass partial skb header to fw */
-@@ -1190,13 +1190,13 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
- static void
- mt7996_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
- {
-- struct mt76_connac_txp_common *txp;
-+ struct mt7996_txp *txp;
- int i;
-
- txp = mt7996_txwi_to_txp(dev, t);
-- for (i = 0; i < txp->fw.nbuf; i++)
-- dma_unmap_single(dev->dev, le32_to_cpu(txp->fw.buf[i]),
-- le16_to_cpu(txp->fw.len[i]), DMA_TO_DEVICE);
-+ for (i = 0; i < txp->nbuf; i++)
-+ dma_unmap_single(dev->dev, le32_to_cpu(txp->buf[i]),
-+ le16_to_cpu(txp->len[i]), DMA_TO_DEVICE);
- }
-
- static void
-@@ -1586,11 +1586,11 @@ void mt7996_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
-
- /* error path */
- if (e->skb == DMA_DUMMY_DATA) {
-- struct mt76_connac_txp_common *txp;
- struct mt76_txwi_cache *t;
-+ struct mt7996_txp *txp;
-
- txp = mt7996_txwi_to_txp(mdev, e->txwi);
-- t = mt76_token_put(mdev, le16_to_cpu(txp->fw.token));
-+ t = mt76_token_put(mdev, le16_to_cpu(txp->token));
- e->skb = t ? t->skb : NULL;
- }
-
-diff --git a/mt7996/mac.h b/mt7996/mac.h
-index 10e08d66..9f688520 100644
---- a/mt7996/mac.h
-+++ b/mt7996/mac.h
-@@ -268,6 +268,17 @@ enum tx_mgnt_type {
- /* VHT/HE only use bits 0-3 */
- #define MT_TX_RATE_IDX GENMASK(5, 0)
-
-+struct mt7996_txp {
-+ __le16 flags;
-+ __le16 token;
-+ u8 bss_idx;
-+ __le16 rept_wds_wcid;
-+ u8 nbuf;
-+#define MT_TXP_MAX_BUF_NUM 6
-+ __le32 buf[MT_TXP_MAX_BUF_NUM];
-+ __le16 len[MT_TXP_MAX_BUF_NUM];
-+} __packed __aligned(4);
-+
- #define MT_TXFREE0_PKT_TYPE GENMASK(31, 27)
- #define MT_TXFREE0_MSDU_CNT GENMASK(25, 16)
- #define MT_TXFREE0_RX_BYTE GENMASK(15, 0)
-@@ -371,7 +382,7 @@ struct mt7996_dfs_radar_spec {
- struct mt7996_dfs_pattern radar_pattern[16];
- };
-
--static inline struct mt76_connac_txp_common *
-+static inline struct mt7996_txp *
- mt7996_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t)
- {
- u8 *txwi;
-@@ -381,7 +392,7 @@ mt7996_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t)
-
- txwi = mt76_get_txwi_ptr(dev, t);
-
-- return (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
-+ return (struct mt7996_txp *)(txwi + MT_TXD_SIZE);
- }
-
- #endif
-diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-index 2237f50a..d8a2c1a7 100644
---- a/mt7996/mmio.c
-+++ b/mt7996/mmio.c
-@@ -318,7 +318,7 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
- {
- static const struct mt76_driver_ops drv_ops = {
- /* txwi_size = txd size + txp size */
-- .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp),
-+ .txwi_size = MT_TXD_SIZE + sizeof(struct mt7996_txp),
- .drv_flags = MT_DRV_TXWI_NO_FREE |
- MT_DRV_HW_MGMT_TXQ,
- .survey_flags = SURVEY_INFO_TIME_TX |
---
-2.25.1
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0003-wifi-mt76-mt7996-reduce-repeated-bss_info-and-sta_re.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0003-wifi-mt76-mt7996-reduce-repeated-bss_info-and-sta_re.patch
new file mode 100644
index 0000000..c91eb62
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0003-wifi-mt76-mt7996-reduce-repeated-bss_info-and-sta_re.patch
@@ -0,0 +1,67 @@
+From 09ef1c1248c8b38c5f2c6e624397e64e8938349f Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Thu, 16 Feb 2023 00:39:01 +0800
+Subject: [PATCH 03/19] wifi: mt76: mt7996: reduce repeated bss_info and
+ sta_rec commands
+
+Refine the flow of setting bss_info and sta_rec commands to prevent from
+sending duplicated commands, especially for station mode.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: Iffd2c81f9ec98284793e75f4b7d39e9618977024
+---
+ mt7996/main.c | 21 ++++++---------------
+ 1 file changed, 6 insertions(+), 15 deletions(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 3e4da035..e80ee19e 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -241,8 +241,8 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ int idx = msta->wcid.idx;
+
+- mt7996_mcu_add_bss_info(phy, vif, false);
+ mt7996_mcu_add_sta(dev, vif, NULL, false);
++ mt7996_mcu_add_bss_info(phy, vif, false);
+
+ if (vif == phy->monitor_vif)
+ phy->monitor_vif = NULL;
+@@ -510,17 +510,13 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
+ /* station mode uses BSSID to map the wlan entry to a peer,
+ * and then peer references bss_info_rfch to set bandwidth cap.
+ */
+- if (changed & BSS_CHANGED_BSSID &&
+- vif->type == NL80211_IFTYPE_STATION) {
+- bool join = !is_zero_ether_addr(info->bssid);
+-
+- mt7996_mcu_add_bss_info(phy, vif, join);
+- mt7996_mcu_add_sta(dev, vif, NULL, join);
++ if ((changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) ||
++ (changed & BSS_CHANGED_ASSOC && vif->cfg.assoc) ||
++ (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon)) {
++ mt7996_mcu_add_bss_info(phy, vif, true);
++ mt7996_mcu_add_sta(dev, vif, NULL, true);
+ }
+
+- if (changed & BSS_CHANGED_ASSOC)
+- mt7996_mcu_add_bss_info(phy, vif, vif->cfg.assoc);
+-
+ if (changed & BSS_CHANGED_ERP_CTS_PROT)
+ mt7996_mac_enable_rtscts(dev, vif, info->use_cts_prot);
+
+@@ -533,11 +529,6 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
+ }
+ }
+
+- if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) {
+- mt7996_mcu_add_bss_info(phy, vif, true);
+- mt7996_mcu_add_sta(dev, vif, NULL, true);
+- }
+-
+ /* ensure that enable txcmd_mode after bss_info */
+ if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED))
+ mt7996_mcu_set_tx(dev, vif);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-move-radio-enable-command-to-mt7996.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-move-radio-enable-command-to-mt7996.patch
new file mode 100644
index 0000000..cc366e3
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-move-radio-enable-command-to-mt7996.patch
@@ -0,0 +1,61 @@
+From c86f2243472f00fd2011cc44b89a87f7f6e2066a Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Wed, 15 Feb 2023 18:38:04 +0800
+Subject: [PATCH 04/19] wifi: mt76: mt7996: move radio enable command to
+ mt7996_start()
+
+The radio enable and disable commands are used for per-phy radio, so
+move them into mt7996_start() and mt7996_stop(), respectively.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: I610b170f5198e085eb86dbd371ee0745ac6ff50f
+---
+ mt7996/main.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index e80ee19e..a4fd9e24 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -46,6 +46,10 @@ static int mt7996_start(struct ieee80211_hw *hw)
+ if (ret)
+ goto out;
+
++ ret = mt7996_mcu_set_radio_en(phy, true);
++ if (ret)
++ goto out;
++
+ ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH);
+ if (ret)
+ goto out;
+@@ -77,6 +81,8 @@ static void mt7996_stop(struct ieee80211_hw *hw)
+
+ mutex_lock(&dev->mt76.mutex);
+
++ mt7996_mcu_set_radio_en(phy, false);
++
+ clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+
+ ieee80211_iterate_interfaces(dev->mt76.hw,
+@@ -189,10 +195,6 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+ if (ret)
+ goto out;
+
+- ret = mt7996_mcu_set_radio_en(phy, true);
+- if (ret)
+- goto out;
+-
+ dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx);
+ phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx);
+
+@@ -248,7 +250,6 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ phy->monitor_vif = NULL;
+
+ mt7996_mcu_add_dev_info(phy, vif, false);
+- mt7996_mcu_set_radio_en(phy, false);
+
+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0005-wifi-mt76-connac-set-correct-muar_idx-for-connac3-ch.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0005-wifi-mt76-connac-set-correct-muar_idx-for-connac3-ch.patch
new file mode 100644
index 0000000..07dffec
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0005-wifi-mt76-connac-set-correct-muar_idx-for-connac3-ch.patch
@@ -0,0 +1,49 @@
+From 5d4c7f88b2066f4a8ec1769cf6c067d0e88abfa3 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Thu, 16 Feb 2023 13:53:14 +0800
+Subject: [PATCH 05/19] wifi: mt76: connac: set correct muar_idx for connac3
+ chipset
+
+Set the muar_idx to 0xe for the hw bcast/mcast station entry of connac3
+chipset.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: I7054c3b3c64ec447cc280ea810f4958afdfa9e02
+---
+ mt76_connac.h | 5 +++++
+ mt76_connac_mcu.c | 3 +++
+ 2 files changed, 8 insertions(+)
+
+diff --git a/mt76_connac.h b/mt76_connac.h
+index b339c50b..c8b91e86 100644
+--- a/mt76_connac.h
++++ b/mt76_connac.h
+@@ -216,6 +216,11 @@ static inline bool is_connac_v1(struct mt76_dev *dev)
+ return is_mt7615(dev) || is_mt7663(dev) || is_mt7622(dev);
+ }
+
++static inline bool is_connac_v3(struct mt76_dev *dev)
++{
++ return is_mt7996(dev);
++}
++
+ static inline bool is_mt76_fw_txp(struct mt76_dev *dev)
+ {
+ switch (mt76_chip(dev)) {
+diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
+index efb9bfaa..4e4f6b35 100644
+--- a/mt76_connac_mcu.c
++++ b/mt76_connac_mcu.c
+@@ -281,6 +281,9 @@ __mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif *mvif,
+ };
+ struct sk_buff *skb;
+
++ if (is_connac_v3(dev) && !wcid->sta)
++ hdr.muar_idx = 0xe;
++
+ mt76_connac_mcu_get_wlan_idx(dev, wcid, &hdr.wlan_idx_lo,
+ &hdr.wlan_idx_hi);
+ skb = mt76_mcu_msg_alloc(dev, NULL, len);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0005-wifi-mt76-mt7996-set-txd-v1.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0005-wifi-mt76-mt7996-set-txd-v1.patch
deleted file mode 100644
index 8fddb93..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0005-wifi-mt76-mt7996-set-txd-v1.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From d8bef73f22f88bf857698f4018db3aed6a2fca2d Mon Sep 17 00:00:00 2001
-From: Peter Chiu <chui-hao.chiu@mediatek.com>
-Date: Tue, 29 Nov 2022 09:13:32 +0800
-Subject: [PATCH 5/7] wifi: mt76: mt7996: set txd v1
-
----
- mt7996/mac.c | 3 +++
- mt7996/mac.h | 3 ++-
- 2 files changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index e5b5fed6..51337dde 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -1092,6 +1092,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- struct mt7996_txp *txp;
- int id, i, pid, nbuf = tx_info->nbuf - 1;
- bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
-+ __le32 *txd = (__le32 *)txwi_ptr;
- u8 *txwi = (u8 *)txwi_ptr;
-
- if (unlikely(tx_info->skb->len <= ETH_HLEN))
-@@ -1123,6 +1124,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid,
- key, 0);
-
-+ txd[0] |= le32_encode_bits(1, MT_TXD0_VER);
-+
- txp = (struct mt7996_txp *)(txwi + MT_TXD_SIZE);
- for (i = 0; i < nbuf; i++) {
- txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
-diff --git a/mt7996/mac.h b/mt7996/mac.h
-index 9f688520..470b701a 100644
---- a/mt7996/mac.h
-+++ b/mt7996/mac.h
-@@ -186,7 +186,8 @@ enum tx_mgnt_type {
-
- #define MT_TXD0_Q_IDX GENMASK(31, 25)
- #define MT_TXD0_PKT_FMT GENMASK(24, 23)
--#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16)
-+#define MT_TXD0_VER GENMASK(22, 19)
-+#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(18, 16)
- #define MT_TXD0_TX_BYTES GENMASK(15, 0)
-
- #define MT_TXD1_FIXED_RATE BIT(31)
---
-2.25.1
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-fix-pointer-calculation-in-ie-count.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-fix-pointer-calculation-in-ie-count.patch
new file mode 100644
index 0000000..65596f4
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-fix-pointer-calculation-in-ie-count.patch
@@ -0,0 +1,34 @@
+From 00d76d4dc3cdb719b5fc234d9cf3bbef39f448ce Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Mon, 13 Feb 2023 14:48:10 +0800
+Subject: [PATCH 06/19] wifi: mt76: mt7996: fix pointer calculation in ie
+ countdown event
+
+Fix the tail and data pointers. The rxd->len in mt7996_mcu_rxd does not
+include the length of general rxd. It only includes the length of
+firmware event rxd. Use the skb->length to get the correct length.
+
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: I832194559e63e6b49b7ee00dc9c606b6106d8669
+---
+ mt7996/mcu.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index dbe10576..2e25572a 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -422,7 +422,8 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
+ if (hdr->band && dev->mt76.phys[hdr->band])
+ mphy = dev->mt76.phys[hdr->band];
+
+- tail = skb->data + le16_to_cpu(rxd->len);
++ tail = skb->data + skb->len;
++ data += sizeof(struct header);
+ while (data + sizeof(struct tlv) < tail && le16_to_cpu(tlv->len)) {
+ switch (le16_to_cpu(tlv->tag)) {
+ case UNI_EVENT_IE_COUNTDOWN_CSA:
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0007-wifi-mt76-mt7996-remove-mt7996_mcu_set_pm.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0007-wifi-mt76-mt7996-remove-mt7996_mcu_set_pm.patch
new file mode 100644
index 0000000..7988196
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0007-wifi-mt76-mt7996-remove-mt7996_mcu_set_pm.patch
@@ -0,0 +1,96 @@
+From c2dafe57df1726acb80e30987bc8d678b86af14a Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Tue, 14 Feb 2023 18:35:43 +0800
+Subject: [PATCH 07/19] wifi: mt76: mt7996: remove mt7996_mcu_set_pm()
+
+Currently using BSS_INFO_PS command will sometimes cause packet drop in
+hw rx queue.
+Temporarily remove this function until finding the cause.
+
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: I863fc1edb18e4d7b5dac20140dd0904875e1323c
+---
+ mt7996/main.c | 8 --------
+ mt7996/mcu.c | 26 --------------------------
+ mt7996/mt7996.h | 1 -
+ 3 files changed, 35 deletions(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index a4fd9e24..44d23e1d 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -56,10 +56,6 @@ static int mt7996_start(struct ieee80211_hw *hw)
+
+ set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+
+- ieee80211_iterate_interfaces(dev->mt76.hw,
+- IEEE80211_IFACE_ITER_RESUME_ALL,
+- mt7996_mcu_set_pm, dev->mt76.hw);
+-
+ ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
+ MT7996_WATCHDOG_TIME);
+
+@@ -85,10 +81,6 @@ static void mt7996_stop(struct ieee80211_hw *hw)
+
+ clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+
+- ieee80211_iterate_interfaces(dev->mt76.hw,
+- IEEE80211_IFACE_ITER_RESUME_ALL,
+- mt7996_mcu_set_pm, dev->mt76.hw);
+-
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 2e25572a..f6947438 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -3577,32 +3577,6 @@ int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev,
+ &req, sizeof(req), true);
+ }
+
+-void mt7996_mcu_set_pm(void *priv, u8 *mac, struct ieee80211_vif *vif)
+-{
+-#define EXIT_PM_STATE 0
+-#define ENTER_PM_STATE 1
+- struct ieee80211_hw *hw = priv;
+- struct mt7996_dev *dev = mt7996_hw_dev(hw);
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct bss_power_save *ps;
+- struct sk_buff *skb;
+- struct tlv *tlv;
+- bool running = test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+-
+- skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
+- MT7996_BSS_UPDATE_MAX_SIZE);
+- if (IS_ERR(skb))
+- return;
+-
+- tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_PS, sizeof(*ps));
+- ps = (struct bss_power_save *)tlv;
+- ps->profile = running ? EXIT_PM_STATE : ENTER_PM_STATE;
+-
+- mt76_mcu_skb_send_msg(&dev->mt76, skb,
+- MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
+-}
+-
+ int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val)
+ {
+ struct {
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index d20aa5f2..f9d8fbfd 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -432,7 +432,6 @@ int mt7996_mcu_set_pulse_th(struct mt7996_dev *dev,
+ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
+ const struct mt7996_dfs_pattern *pattern);
+ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
+-void mt7996_mcu_set_pm(void *priv, u8 *mac, struct ieee80211_vif *vif);
+ int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
+ int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
+ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-add-muru-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0008-wifi-mt76-mt7996-add-muru-support.patch
similarity index 91%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-add-muru-support.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0008-wifi-mt76-mt7996-add-muru-support.patch
index dab5182..20d7f48 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-add-muru-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0008-wifi-mt76-mt7996-add-muru-support.patch
@@ -1,7 +1,7 @@
-From 7c8b8c77489ef907f2122c5d0edb7ff5e0fed177 Mon Sep 17 00:00:00 2001
+From b587a9f1615585f8db0fa98cc46791a3253ddac7 Mon Sep 17 00:00:00 2001
From: MeiChia Chiu <MeiChia.Chiu@mediatek.com>
Date: Mon, 28 Nov 2022 14:36:09 +0800
-Subject: [PATCH 4/7] wifi: mt76: mt7996: add muru support
+Subject: [PATCH 08/19] wifi: mt76: mt7996: add muru support
Add sta_rec_muru() and related phy cap for MU and RU support.
@@ -15,7 +15,7 @@
3 files changed, 73 insertions(+), 2 deletions(-)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index a5e6ee4d..39667840 100644
+index 40a99e0c..6f30a0fb 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -518,7 +518,8 @@ struct sta_rec_muru {
@@ -29,10 +29,10 @@
struct {
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index dbe30832..394dd15c 100644
+index f6947438..b6bd36c2 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -1049,6 +1049,63 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+@@ -1050,6 +1050,63 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
}
}
@@ -96,7 +96,7 @@
static inline bool
mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool bfee)
-@@ -1721,7 +1778,8 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+@@ -1722,7 +1779,8 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
mt7996_mcu_sta_he_6g_tlv(skb, sta);
/* starec eht */
mt7996_mcu_sta_eht_tlv(skb, sta);
@@ -106,7 +106,7 @@
/* starec bfee */
mt7996_mcu_sta_bfee_tlv(dev, skb, vif, sta);
/* starec hdr trans */
-@@ -2004,6 +2062,15 @@ mt7996_mcu_beacon_check_caps(struct mt7996_phy *phy, struct ieee80211_vif *vif,
+@@ -2005,6 +2063,15 @@ mt7996_mcu_beacon_check_caps(struct mt7996_phy *phy, struct ieee80211_vif *vif,
vc->eht_su_ebfee =
EHT_PHY(CAP0_SU_BEAMFORMEE, eht->phy_cap_info[0]) &&
EHT_PHY(CAP0_SU_BEAMFORMEE, pe->phy_cap_info[0]);
@@ -123,7 +123,7 @@
}
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 13f22432..64a804a4 100644
+index f9d8fbfd..997a0bf0 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -125,6 +125,9 @@ struct mt7996_vif_cap {
@@ -137,5 +137,5 @@
struct mt7996_vif {
--
-2.25.1
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0009-wifi-mt76-mt7996-set-txd-v1.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0009-wifi-mt76-mt7996-set-txd-v1.patch
new file mode 100644
index 0000000..cc7548a
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0009-wifi-mt76-mt7996-set-txd-v1.patch
@@ -0,0 +1,48 @@
+From 9a1a54c7df9babadd8f6ae066deb2b5e49715cb0 Mon Sep 17 00:00:00 2001
+From: Bo Jiao <Bo.Jiao@mediatek.com>
+Date: Mon, 6 Feb 2023 10:40:33 +0800
+Subject: [PATCH 09/19] wifi: mt76: mt7996: set txd v1
+
+---
+ mt7996/mac.c | 3 +++
+ mt7996/mac.h | 3 ++-
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 198eb711..40ef5e4b 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -1096,6 +1096,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ struct mt76_txwi_cache *t;
+ int id, i, pid, nbuf = tx_info->nbuf - 1;
+ bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
++ __le32 *txd = (__le32 *)txwi_ptr;
+ u8 *txwi = (u8 *)txwi_ptr;
+
+ if (unlikely(tx_info->skb->len <= ETH_HLEN))
+@@ -1127,6 +1128,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, qid,
+ pid, key, 0);
+
++ txd[0] |= le32_encode_bits(1, MT_TXD0_VER);
++
+ txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
+ for (i = 0; i < nbuf; i++) {
+ txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
+diff --git a/mt7996/mac.h b/mt7996/mac.h
+index 2cc218f7..4914d3e5 100644
+--- a/mt7996/mac.h
++++ b/mt7996/mac.h
+@@ -183,7 +183,8 @@ enum tx_mgnt_type {
+
+ #define MT_TXD0_Q_IDX GENMASK(31, 25)
+ #define MT_TXD0_PKT_FMT GENMASK(24, 23)
+-#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16)
++#define MT_TXD0_VER GENMASK(22, 19)
++#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(18, 16)
+ #define MT_TXD0_TX_BYTES GENMASK(15, 0)
+
+ #define MT_TXD1_FIXED_RATE BIT(31)
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0010-wifi-mt76-mt7996-add-thermal-protection-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0010-wifi-mt76-mt7996-add-thermal-protection-support.patch
new file mode 100644
index 0000000..319eb1f
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0010-wifi-mt76-mt7996-add-thermal-protection-support.patch
@@ -0,0 +1,437 @@
+From 1744b5397ad4240ce41bf88bfff2eef34d76d587 Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Thu, 2 Feb 2023 21:20:31 +0800
+Subject: [PATCH 10/19] wifi: mt76: mt7996: add thermal protection support
+
+This commit includes the following changes:
+1. implement MTK thermal protection driver API
+2. support Linux cooling device control
+
+Change-Id: I8fecc28f5b17ee50ae4644d1dd17d188dd694731
+---
+ mt76_connac_mcu.h | 1 +
+ mt7996/init.c | 105 +++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/main.c | 8 ++++
+ mt7996/mcu.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mcu.h | 44 +++++++++++++++++++
+ mt7996/mt7996.h | 15 +++++++
+ 6 files changed, 279 insertions(+)
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index 6f30a0fb..fa10d823 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -1009,6 +1009,7 @@ enum {
+ MCU_UNI_EVENT_FW_LOG_2_HOST = 0x04,
+ MCU_UNI_EVENT_IE_COUNTDOWN = 0x09,
+ MCU_UNI_EVENT_RDD_REPORT = 0x11,
++ MCU_UNI_EVENT_THERMAL = 0x35,
+ };
+
+ #define MCU_UNI_CMD_EVENT BIT(1)
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 946da93e..5a22cd81 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -41,6 +41,98 @@ static const struct ieee80211_iface_combination if_comb[] = {
+ }
+ };
+
++static int
++mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
++ unsigned long *state)
++{
++ *state = MT7996_CDEV_THROTTLE_MAX;
++
++ return 0;
++}
++
++static int
++mt7996_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
++ unsigned long *state)
++{
++ struct mt7996_phy *phy = cdev->devdata;
++
++ *state = phy->cdev_state;
++
++ return 0;
++}
++
++static int
++mt7996_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
++ unsigned long state)
++{
++ struct mt7996_phy *phy = cdev->devdata;
++ u8 throttling = MT7996_THERMAL_THROTTLE_MAX - state;
++ int ret;
++
++ if (state > MT7996_CDEV_THROTTLE_MAX) {
++ dev_err(phy->dev->mt76.dev,
++ "please specify a valid throttling state\n");
++ return -EINVAL;
++ }
++
++ if (state == phy->cdev_state)
++ return 0;
++
++ /*
++ * cooling_device convention: 0 = no cooling, more = more cooling
++ * mcu convention: 1 = max cooling, more = less cooling
++ */
++ ret = mt7996_mcu_set_thermal_throttling(phy, throttling);
++ if (ret)
++ return ret;
++
++ phy->cdev_state = state;
++
++ return 0;
++}
++
++static const struct thermal_cooling_device_ops mt7996_thermal_ops = {
++ .get_max_state = mt7996_thermal_get_max_throttle_state,
++ .get_cur_state = mt7996_thermal_get_cur_throttle_state,
++ .set_cur_state = mt7996_thermal_set_cur_throttle_state,
++};
++
++static void mt7996_unregister_thermal(struct mt7996_phy *phy)
++{
++ struct wiphy *wiphy = phy->mt76->hw->wiphy;
++
++ if (!phy->cdev)
++ return;
++
++ sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
++ thermal_cooling_device_unregister(phy->cdev);
++}
++
++static int mt7996_thermal_init(struct mt7996_phy *phy)
++{
++ struct wiphy *wiphy = phy->mt76->hw->wiphy;
++ struct thermal_cooling_device *cdev;
++ const char *name;
++
++ name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s",
++ wiphy_name(wiphy));
++
++ cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops);
++ if (!IS_ERR(cdev)) {
++ if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj,
++ "cooling_device") < 0)
++ thermal_cooling_device_unregister(cdev);
++ else
++ phy->cdev = cdev;
++ }
++
++ /* initialize critical/maximum high temperature */
++ phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP;
++ phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP;
++
++ return 0;
++}
++
+ static void mt7996_led_set_config(struct led_classdev *led_cdev,
+ u8 delay_on, u8 delay_off)
+ {
+@@ -367,6 +459,10 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+ if (ret)
+ goto error;
+
++ ret = mt7996_thermal_init(phy);
++ if (ret)
++ goto error;
++
+ ret = mt7996_init_debugfs(phy);
+ if (ret)
+ goto error;
+@@ -387,6 +483,8 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
+ if (!phy)
+ return;
+
++ mt7996_unregister_thermal(phy);
++
+ mphy = phy->dev->mt76.phys[band];
+ mt76_unregister_phy(mphy);
+ ieee80211_free_hw(mphy->hw);
+@@ -876,6 +974,10 @@ int mt7996_register_device(struct mt7996_dev *dev)
+ if (ret)
+ return ret;
+
++ ret = mt7996_thermal_init(&dev->phy);
++ if (ret)
++ return ret;
++
+ ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
+
+ ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1);
+@@ -893,6 +995,9 @@ void mt7996_unregister_device(struct mt7996_dev *dev)
+ {
+ mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2);
+ mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1);
++
++ mt7996_unregister_thermal(&dev->phy);
++
+ mt76_unregister_device(&dev->mt76);
+ mt7996_mcu_exit(dev);
+ mt7996_tx_token_put(dev);
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 44d23e1d..d8d578c0 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -54,6 +54,14 @@ static int mt7996_start(struct ieee80211_hw *hw)
+ if (ret)
+ goto out;
+
++ ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX);
++ if (ret)
++ goto out;
++
++ ret = mt7996_mcu_set_thermal_protect(phy);
++ if (ret)
++ goto out;
++
+ set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+
+ ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index b6bd36c2..3820a63e 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -443,6 +443,34 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
+ }
+ }
+
++static void
++mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb)
++{
++#define THERMAL_NOTIFY_TAG 0x4
++#define THERMAL_NOTIFY 0x2
++ struct mt76_phy *mphy = &dev->mt76.phy;
++ struct mt7996_mcu_thermal_notify *n;
++ struct mt7996_phy *phy;
++
++ n = (struct mt7996_mcu_thermal_notify *)skb->data;
++
++ if (n->tag != THERMAL_NOTIFY_TAG)
++ return;
++
++ if (n->event_id != THERMAL_NOTIFY)
++ return;
++
++ if (n->band_idx > MT_BAND2)
++ return;
++
++ mphy = dev->mt76.phys[n->band_idx];
++ if (!mphy)
++ return;
++
++ phy = (struct mt7996_phy *)mphy->priv;
++ phy->throttle_state = n->duty_percent;
++}
++
+ static void
+ mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb)
+ {
+@@ -487,6 +515,9 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
+ case MCU_UNI_EVENT_RDD_REPORT:
+ mt7996_mcu_rx_radar_detected(dev, skb);
+ break;
++ case MCU_UNI_EVENT_THERMAL:
++ mt7996_mcu_rx_thermal_notify(dev, skb);
++ break;
+ default:
+ break;
+ }
+@@ -3277,6 +3308,81 @@ out:
+ return 0;
+ }
+
++
++int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state)
++{
++ struct {
++ u8 _rsv[4];
++
++ __le16 tag;
++ __le16 len;
++
++ struct mt7996_mcu_thermal_ctrl ctrl;
++ } __packed req = {
++ .tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG),
++ .len = cpu_to_le16(sizeof(req) - 4),
++ .ctrl = {
++ .band_idx = phy->mt76->band_idx,
++ },
++ };
++ int level, ret;
++
++ /* set duty cycle and level */
++ for (level = 0; level < 4; level++) {
++ req.ctrl.duty.duty_level = level;
++ req.ctrl.duty.duty_cycle = state;
++ state /= 2;
++
++ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++ &req, sizeof(req), false);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
++int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy)
++{
++#define SUSTAIN_PERIOD 10
++ struct {
++ u8 _rsv[4];
++
++ __le16 tag;
++ __le16 len;
++
++ struct mt7996_mcu_thermal_ctrl ctrl;
++ struct mt7996_mcu_thermal_enable enable;
++ } __packed req = {
++ .len = cpu_to_le16(sizeof(req) - 4 - sizeof(req.enable)),
++ .ctrl = {
++ .band_idx = phy->mt76->band_idx,
++ .type.protect_type = 1,
++ .type.trigger_type = 1,
++ },
++ };
++ int ret;
++
++ req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DISABLE);
++
++ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++ &req, sizeof(req) - sizeof(req.enable), false);
++ if (ret)
++ return ret;
++
++ /* set high-temperature trigger threshold */
++ req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_ENABLE);
++ /* add a safety margin ~10 */
++ req.enable.restore_temp = cpu_to_le32(phy->throttle_temp[0] - 10);
++ req.enable.trigger_temp = cpu_to_le32(phy->throttle_temp[1]);
++ req.enable.sustain_time = cpu_to_le16(SUSTAIN_PERIOD);
++
++ req.len = cpu_to_le16(sizeof(req) - 4);
++
++ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++ &req, sizeof(req), false);
++}
++
+ int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band)
+ {
+ struct {
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index dd0c5ac5..7fefc28f 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -30,6 +30,28 @@ struct mt7996_mcu_uni_event {
+ __le32 status; /* 0: success, others: fail */
+ } __packed;
+
++struct mt7996_mcu_thermal_ctrl {
++ u8 ctrl_id;
++ u8 band_idx;
++ union {
++ struct {
++ u8 protect_type; /* 1: duty admit, 2: radio off */
++ u8 trigger_type; /* 0: low, 1: high */
++ } __packed type;
++ struct {
++ u8 duty_level; /* level 0~3 */
++ u8 duty_cycle;
++ } __packed duty;
++ };
++} __packed;
++
++struct mt7996_mcu_thermal_enable {
++ __le32 trigger_temp;
++ __le32 restore_temp;
++ __le16 sustain_time;
++ u8 rsv[2];
++} __packed;
++
+ struct mt7996_mcu_csa_notify {
+ struct mt7996_mcu_rxd rxd;
+
+@@ -153,6 +175,22 @@ struct mt7996_mcu_mib {
+ __le64 data;
+ } __packed;
+
++struct mt7996_mcu_thermal_notify {
++ struct mt7996_mcu_rxd rxd;
++
++ u8 __rsv1[4];
++
++ __le16 tag;
++ __le16 len;
++
++ u8 event_id;
++ u8 band_idx;
++ u8 level_idx;
++ u8 duty_percent;
++ __le32 restore_temp;
++ u8 __rsv2[4];
++} __packed;
++
+ enum mt7996_chan_mib_offs {
+ UNI_MIB_OBSS_AIRTIME = 26,
+ UNI_MIB_NON_WIFI_TIME = 27,
+@@ -642,6 +680,12 @@ enum{
+ UNI_CMD_SR_SET_SIGA = 0xd0,
+ };
+
++enum {
++ UNI_CMD_THERMAL_PROTECT_ENABLE = 0x6,
++ UNI_CMD_THERMAL_PROTECT_DISABLE,
++ UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
++};
++
+ enum {
+ UNI_CMD_ACCESS_REG_BASIC = 0x0,
+ UNI_CMD_ACCESS_RF_REG_BASIC,
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 997a0bf0..25b20fa6 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -43,6 +43,13 @@
+ #define MT7996_MAX_STA_TWT_AGRT 8
+ #define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3)
+
++#define MT7996_THERMAL_THROTTLE_MAX 100
++#define MT7996_CDEV_THROTTLE_MAX 99
++#define MT7996_CRIT_TEMP_IDX 0
++#define MT7996_MAX_TEMP_IDX 1
++#define MT7996_CRIT_TEMP 110
++#define MT7996_MAX_TEMP 120
++
+ struct mt7996_vif;
+ struct mt7996_sta;
+ struct mt7996_dfs_pulse;
+@@ -211,6 +218,11 @@ struct mt7996_phy {
+
+ struct ieee80211_vif *monitor_vif;
+
++ struct thermal_cooling_device *cdev;
++ u8 cdev_state;
++ u8 throttle_state;
++ u32 throttle_temp[2]; /* 0: critical high, 1: maximum */
++
+ u32 rxfilter;
+ u64 omac_mask;
+
+@@ -437,6 +449,9 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
+ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
+ int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
+ int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
++int mt7996_mcu_get_temperature(struct mt7996_phy *phy);
++int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state);
++int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy);
+ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
+ u8 rx_sel, u8 val);
+ int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0011-wifi-mt76-mt7996-add-thermal-sensor-device-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0011-wifi-mt76-mt7996-add-thermal-sensor-device-support.patch
new file mode 100644
index 0000000..3de5b90
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0011-wifi-mt76-mt7996-add-thermal-sensor-device-support.patch
@@ -0,0 +1,184 @@
+From afdb511f0febad0e0cc5572461ab04794cf86852 Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Thu, 2 Feb 2023 20:53:42 +0800
+Subject: [PATCH 11/19] wifi: mt76: mt7996: add thermal sensor device support
+
+---
+ mt7996/init.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mcu.c | 41 ++++++++++++++++++++++++
+ 2 files changed, 128 insertions(+)
+
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 5a22cd81..631ada15 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -4,6 +4,8 @@
+ */
+
+ #include <linux/etherdevice.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
+ #include <linux/thermal.h>
+ #include "mt7996.h"
+ #include "mac.h"
+@@ -41,6 +43,81 @@ static const struct ieee80211_iface_combination if_comb[] = {
+ }
+ };
+
++static ssize_t mt7996_thermal_temp_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct mt7996_phy *phy = dev_get_drvdata(dev);
++ int i = to_sensor_dev_attr(attr)->index;
++ int temperature;
++
++ switch (i) {
++ case 0:
++ temperature = mt7996_mcu_get_temperature(phy);
++ if (temperature < 0)
++ return temperature;
++ /* display in millidegree celcius */
++ return sprintf(buf, "%u\n", temperature * 1000);
++ case 1:
++ case 2:
++ return sprintf(buf, "%u\n",
++ phy->throttle_temp[i - 1] * 1000);
++ case 3:
++ return sprintf(buf, "%hhu\n", phy->throttle_state);
++ default:
++ return -EINVAL;
++ }
++}
++
++static ssize_t mt7996_thermal_temp_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct mt7996_phy *phy = dev_get_drvdata(dev);
++ int ret, i = to_sensor_dev_attr(attr)->index;
++ long val;
++
++ ret = kstrtol(buf, 10, &val);
++ if (ret < 0)
++ return ret;
++
++ mutex_lock(&phy->dev->mt76.mutex);
++ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 40, 130);
++
++ if ((i - 1 == MT7996_CRIT_TEMP_IDX &&
++ val > phy->throttle_temp[MT7996_MAX_TEMP_IDX]) ||
++ (i - 1 == MT7996_MAX_TEMP_IDX &&
++ val < phy->throttle_temp[MT7996_CRIT_TEMP_IDX])) {
++ dev_err(phy->dev->mt76.dev,
++ "temp1_max shall be greater than temp1_crit.");
++ mutex_unlock(&phy->dev->mt76.mutex);
++ return -EINVAL;
++ }
++
++ phy->throttle_temp[i - 1] = val;
++ mutex_unlock(&phy->dev->mt76.mutex);
++
++ ret = mt7996_mcu_set_thermal_protect(phy);
++ if (ret)
++ return ret;
++
++ return count;
++}
++
++static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7996_thermal_temp, 0);
++static SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7996_thermal_temp, 1);
++static SENSOR_DEVICE_ATTR_RW(temp1_max, mt7996_thermal_temp, 2);
++static SENSOR_DEVICE_ATTR_RO(throttle1, mt7996_thermal_temp, 3);
++
++static struct attribute *mt7996_hwmon_attrs[] = {
++ &sensor_dev_attr_temp1_input.dev_attr.attr,
++ &sensor_dev_attr_temp1_crit.dev_attr.attr,
++ &sensor_dev_attr_temp1_max.dev_attr.attr,
++ &sensor_dev_attr_throttle1.dev_attr.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(mt7996_hwmon);
++
+ static int
+ mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+@@ -112,6 +189,7 @@ static int mt7996_thermal_init(struct mt7996_phy *phy)
+ {
+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
+ struct thermal_cooling_device *cdev;
++ struct device *hwmon;
+ const char *name;
+
+ name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s",
+@@ -130,6 +208,15 @@ static int mt7996_thermal_init(struct mt7996_phy *phy)
+ phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP;
+ phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP;
+
++ if (!IS_REACHABLE(CONFIG_HWMON))
++ return 0;
++
++ hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
++ mt7996_hwmon_groups);
++
++ if (IS_ERR(hwmon))
++ return PTR_ERR(hwmon);
++
+ return 0;
+ }
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 3820a63e..b3326586 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -3308,6 +3308,47 @@ out:
+ return 0;
+ }
+
++int mt7996_mcu_get_temperature(struct mt7996_phy *phy)
++{
++#define TEMPERATURE_QUERY 0
++#define GET_TEMPERATURE 0
++ struct {
++ u8 _rsv[4];
++
++ __le16 tag;
++ __le16 len;
++
++ u8 rsv1;
++ u8 action;
++ u8 band_idx;
++ u8 rsv2;
++ } req = {
++ .tag = cpu_to_le16(TEMPERATURE_QUERY),
++ .len = cpu_to_le16(sizeof(req) - 4),
++ .action = GET_TEMPERATURE,
++ .band_idx = phy->mt76->band_idx,
++ };
++ struct mt7996_mcu_thermal {
++ u8 _rsv[4];
++
++ __le16 tag;
++ __le16 len;
++
++ __le32 rsv;
++ __le32 temperature;
++ } __packed *res;
++ struct sk_buff *skb;
++ int ret;
++
++ ret = mt76_mcu_send_and_get_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++ &req, sizeof(req), true, &skb);
++ if (ret)
++ return ret;
++
++ res = (void *)skb->data;
++
++ return le32_to_cpu(res->temperature);
++}
+
+ int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state)
+ {
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0012-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch
similarity index 78%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0012-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch
index 70867df..728b4e0 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0012-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch
@@ -1,7 +1,7 @@
-From 6298046de15b190139552d74aeb668e8cb873b1d Mon Sep 17 00:00:00 2001
+From f78111386b1ac57a459687b9d58e1804a80d4970 Mon Sep 17 00:00:00 2001
From: Bo Jiao <Bo.Jiao@mediatek.com>
-Date: Thu, 15 Dec 2022 18:22:37 +0800
-Subject: [PATCH 6/7] wifi: mt76: mt7996: add 802.11s mesh amsdu/de-amsdu
+Date: Mon, 6 Feb 2023 11:34:51 +0800
+Subject: [PATCH 12/19] wifi: mt76: mt7996: add 802.11s mesh amsdu/de-amsdu
support
Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
@@ -12,16 +12,12 @@
mt7996/mcu.h | 2 +-
mt7996/mmio.c | 3 ++-
5 files changed, 27 insertions(+), 4 deletions(-)
- mode change 100644 => 100755 mt7996/mac.c
- mode change 100644 => 100755 mt7996/mmio.c
diff --git a/mt7996/mac.c b/mt7996/mac.c
-old mode 100644
-new mode 100755
-index 51337dde..d17b5478
+index 40ef5e4b..8dc3a621 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
-@@ -630,6 +630,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -633,6 +633,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
u32 rxd4 = le32_to_cpu(rxd[4]);
u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
u32 csum_status = *(u32 *)skb->cb;
@@ -29,7 +25,7 @@
bool unicast, insert_ccmp_hdr = false;
u8 remove_pad, amsdu_info, band_idx;
u8 mode = 0, qos_ctl = 0;
-@@ -822,6 +823,9 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -825,6 +826,9 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
skb_pull(skb, hdr_gap);
if (!hdr_trans && status->amsdu) {
@@ -39,7 +35,7 @@
pad_start = ieee80211_get_hdrlen_from_skb(skb);
} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {
/* When header translation failure is indicated,
-@@ -854,8 +858,17 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -857,8 +861,17 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
hdr = mt76_skb_get_hdr(skb);
fc = hdr->frame_control;
if (ieee80211_is_data_qos(fc)) {
@@ -59,7 +55,7 @@
} else {
status->flag |= RX_FLAG_8023;
diff --git a/mt7996/mac.h b/mt7996/mac.h
-index 470b701a..fd0e5d1c 100644
+index 4914d3e5..e48cc68b 100644
--- a/mt7996/mac.h
+++ b/mt7996/mac.h
@@ -12,6 +12,8 @@
@@ -72,10 +68,10 @@
#define MT_RXD0_NORMAL_IP_SUM BIT(23)
#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 394dd15c..1e47b0ae 100644
+index b3326586..0dbe2e01 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -1022,7 +1022,8 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+@@ -1054,7 +1054,8 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
struct tlv *tlv;
if (vif->type != NL80211_IFTYPE_STATION &&
@@ -85,7 +81,7 @@
return;
if (!sta->deflink.agg.max_amsdu_len)
-@@ -1528,6 +1529,12 @@ mt7996_mcu_sta_hdr_trans_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+@@ -1560,6 +1561,12 @@ mt7996_mcu_sta_hdr_trans_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
hdr_trans->to_ds = true;
hdr_trans->from_ds = true;
}
@@ -99,10 +95,10 @@
static enum mcu_mmps_mode
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index dd0c5ac5..009f5f06 100644
+index 7fefc28f..ad66a1f8 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
-@@ -396,7 +396,7 @@ struct sta_rec_hdr_trans {
+@@ -434,7 +434,7 @@ struct sta_rec_hdr_trans {
u8 from_ds;
u8 to_ds;
u8 dis_rx_hdr_tran;
@@ -112,14 +108,12 @@
struct hdr_trans_en {
diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-old mode 100644
-new mode 100755
-index d8a2c1a7..08164b1a
+index 902370a2..6610cc45 100644
--- a/mt7996/mmio.c
+++ b/mt7996/mmio.c
@@ -320,7 +320,8 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
/* txwi_size = txd size + txp size */
- .txwi_size = MT_TXD_SIZE + sizeof(struct mt7996_txp),
+ .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp),
.drv_flags = MT_DRV_TXWI_NO_FREE |
- MT_DRV_HW_MGMT_TXQ,
+ MT_DRV_HW_MGMT_TXQ |
@@ -128,5 +122,5 @@
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_BSS_RX,
--
-2.25.1
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0013-wifi-mt76-mt7996-add-L0.5-system-error-recovery-supp.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0013-wifi-mt76-mt7996-add-L0.5-system-error-recovery-supp.patch
new file mode 100644
index 0000000..93ec12d
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0013-wifi-mt76-mt7996-add-L0.5-system-error-recovery-supp.patch
@@ -0,0 +1,948 @@
+From 6b8dfe2580a782be754be7bcd44da6ad79dc4231 Mon Sep 17 00:00:00 2001
+From: Bo Jiao <Bo.Jiao@mediatek.com>
+Date: Mon, 13 Feb 2023 18:00:25 +0800
+Subject: [PATCH 13/19] wifi: mt76: mt7996: add L0.5 system error recovery
+ support
+
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+---
+ mt7996/debugfs.c | 155 +++++++++++++++++++++++---
+ mt7996/dma.c | 65 +++++++++++
+ mt7996/init.c | 9 +-
+ mt7996/mac.c | 285 +++++++++++++++++++++++++++++++++++++++--------
+ mt7996/main.c | 18 ++-
+ mt7996/mcu.c | 22 ++--
+ mt7996/mcu.h | 28 +++--
+ mt7996/mmio.c | 7 +-
+ mt7996/mt7996.h | 17 ++-
+ mt7996/regs.h | 36 +++++-
+ 10 files changed, 542 insertions(+), 100 deletions(-)
+
+diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
+index 9c5e9ac1..f2c46a50 100644
+--- a/mt7996/debugfs.c
++++ b/mt7996/debugfs.c
+@@ -48,12 +48,12 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7996_implicit_txbf_get,
+
+ /* test knob of system error recovery */
+ static ssize_t
+-mt7996_fw_ser_set(struct file *file, const char __user *user_buf,
+- size_t count, loff_t *ppos)
++mt7996_sys_recovery_set(struct file *file, const char __user *user_buf,
++ size_t count, loff_t *ppos)
+ {
+ struct mt7996_phy *phy = file->private_data;
+ struct mt7996_dev *dev = phy->dev;
+- u8 band_idx = phy->mt76->band_idx;
++ bool band = phy->mt76->band_idx;
+ char buf[16];
+ int ret = 0;
+ u16 val;
+@@ -73,17 +73,49 @@ mt7996_fw_ser_set(struct file *file, const char __user *user_buf,
+ return -EINVAL;
+
+ switch (val) {
+- case SER_SET_RECOVER_L1:
+- case SER_SET_RECOVER_L2:
+- case SER_SET_RECOVER_L3_RX_ABORT:
+- case SER_SET_RECOVER_L3_TX_ABORT:
+- case SER_SET_RECOVER_L3_TX_DISABLE:
+- case SER_SET_RECOVER_L3_BF:
+- ret = mt7996_mcu_set_ser(dev, SER_ENABLE, BIT(val), band_idx);
++ /*
++ * 0: grab firmware current SER state.
++ * 1: trigger & enable system error L1 recovery.
++ * 2: trigger & enable system error L2 recovery.
++ * 3: trigger & enable system error L3 rx abort.
++ * 4: trigger & enable system error L3 tx abort.
++ * 5: trigger & enable system error L3 tx disable.
++ * 6: trigger & enable system error L3 bf recovery.
++ * 7: trigger & enable system error L4 MDP recovery.
++ * 8: trigger & enable system error full recovery.
++ * 9: trigger firmware crash.
++ */
++ case UNI_CMD_SER_QUERY:
++ ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_QUERY, 0, band);
++ break;
++ case UNI_CMD_SER_SET_RECOVER_L1:
++ case UNI_CMD_SER_SET_RECOVER_L2:
++ case UNI_CMD_SER_SET_RECOVER_L3_RX_ABORT:
++ case UNI_CMD_SER_SET_RECOVER_L3_TX_ABORT:
++ case UNI_CMD_SER_SET_RECOVER_L3_TX_DISABLE:
++ case UNI_CMD_SER_SET_RECOVER_L3_BF:
++ case UNI_CMD_SER_SET_RECOVER_L4_MDP:
++ ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_SET, BIT(val), band);
++ if (ret)
++ return ret;
++
++ ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_TRIGGER, val, band);
++ break;
++
++ /* enable full chip reset */
++ case UNI_CMD_SER_SET_RECOVER_FULL:
++ mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
+ if (ret)
+ return ret;
+
+- ret = mt7996_mcu_set_ser(dev, SER_RECOVER, val, band_idx);
++ dev->recovery.state |= MT_MCU_CMD_WDT_MASK;
++ mt7996_reset(dev);
++ break;
++
++ /* WARNING: trigger firmware crash */
++ case UNI_CMD_SER_SET_SYSTEM_ASSERT:
++ mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR, BIT(18));
++ mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_SOFT_ADDR, BIT(18));
+ break;
+ default:
+ break;
+@@ -92,9 +124,101 @@ mt7996_fw_ser_set(struct file *file, const char __user *user_buf,
+ return ret ? ret : count;
+ }
+
+-static const struct file_operations mt7996_fw_ser_ops = {
+- .write = mt7996_fw_ser_set,
+- /* TODO: ser read */
++static ssize_t
++mt7996_sys_recovery_get(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct mt7996_phy *phy = file->private_data;
++ struct mt7996_dev *dev = phy->dev;
++ char *buff;
++ int desc = 0;
++ ssize_t ret;
++ static const size_t bufsz = 1024;
++
++ buff = kmalloc(bufsz, GFP_KERNEL);
++ if (!buff)
++ return -ENOMEM;
++
++ /* HELP */
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "Please echo the correct value ...\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "0: grab firmware transient SER state\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "1: trigger system error L1 recovery\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "2: trigger system error L2 recovery\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "3: trigger system error L3 rx abort\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "4: trigger system error L3 tx abort\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "5: trigger system error L3 tx disable\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "6: trigger system error L3 bf recovery\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "7: trigger system error L4 MDP recovery\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "8: trigger system error full recovery\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "9: trigger firmware crash\n");
++
++ /* SER statistics */
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "\nlet's dump firmware SER statistics...\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_STATUS = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_SER_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_PLE_ERR = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_PLE_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_PLE_ERR_1 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_PLE1_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_PLE_ERR_AMSDU = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_PLE_AMSDU_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_PSE_ERR = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_PSE_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_PSE_ERR_1 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_PSE1_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_LMAC_WISR6_B0 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN0_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_LMAC_WISR6_B1 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN1_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_LMAC_WISR6_B2 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN2_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_LMAC_WISR7_B0 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN0_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_LMAC_WISR7_B1 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_LMAC_WISR7_B2 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN2_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_WFDMA_ERR = 0x%08x\n",
++ mt76_rr(dev, WF_SWDEF_WFDMA_STATUS_ADDR));
++
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "\nSYS_RESET_COUNT: WM %d, WA %d\n",
++ dev->recovery.wm_reset_count,
++ dev->recovery.wa_reset_count);
++
++ ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
++ kfree(buff);
++ return ret;
++}
++
++static const struct file_operations mt7996_sys_recovery_ops = {
++ .write = mt7996_sys_recovery_set,
++ .read = mt7996_sys_recovery_get,
+ .open = simple_open,
+ .llseek = default_llseek,
+ };
+@@ -674,6 +798,8 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
+ debugfs_create_file("xmit-queues", 0400, dir, phy,
+ &mt7996_xmit_queues_fops);
+ debugfs_create_file("tx_stats", 0400, dir, phy, &mt7996_tx_stats_fops);
++ debugfs_create_file("sys_recovery", 0600, dir, phy,
++ &mt7996_sys_recovery_ops);
+ debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm);
+ debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa);
+ debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin);
+@@ -684,7 +810,6 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
+ &fops_implicit_txbf);
+ debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir,
+ mt7996_twt_stats);
+- debugfs_create_file("fw_ser", 0600, dir, phy, &mt7996_fw_ser_ops);
+ debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
+
+ if (phy->mt76->cap.has_5ghz) {
+diff --git a/mt7996/dma.c b/mt7996/dma.c
+index c09fe427..18ea758c 100644
+--- a/mt7996/dma.c
++++ b/mt7996/dma.c
+@@ -352,6 +352,71 @@ int mt7996_dma_init(struct mt7996_dev *dev)
+ return 0;
+ }
+
++void mt7996_dma_reset(struct mt7996_dev *dev, bool force)
++{
++ struct mt76_phy *phy2 = dev->mt76.phys[MT_BAND1];
++ struct mt76_phy *phy3 = dev->mt76.phys[MT_BAND2];
++ u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
++ int i;
++
++ mt76_clear(dev, MT_WFDMA0_GLO_CFG,
++ MT_WFDMA0_GLO_CFG_TX_DMA_EN |
++ MT_WFDMA0_GLO_CFG_RX_DMA_EN);
++
++ if (dev->hif2)
++ mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
++ MT_WFDMA0_GLO_CFG_TX_DMA_EN |
++ MT_WFDMA0_GLO_CFG_RX_DMA_EN);
++
++ usleep_range(1000, 2000);
++
++ for (i = 0; i < __MT_TXQ_MAX; i++) {
++ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
++ if (phy2)
++ mt76_queue_tx_cleanup(dev, phy2->q_tx[i], true);
++ if (phy3)
++ mt76_queue_tx_cleanup(dev, phy3->q_tx[i], true);
++ }
++
++ for (i = 0; i < __MT_MCUQ_MAX; i++)
++ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
++
++ mt76_for_each_q_rx(&dev->mt76, i)
++ //mt76_queue_rx_reset(dev, i);
++ mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]);
++
++ mt76_tx_status_check(&dev->mt76, true);
++
++ /* reset wfsys */
++ if (force)
++ mt7996_wfsys_reset(dev);
++
++ mt7996_dma_disable(dev, force);
++
++ /* reset hw queues */
++ for (i = 0; i < __MT_TXQ_MAX; i++) {
++ mt76_queue_reset(dev, dev->mphy.q_tx[i]);
++ if (phy2)
++ mt76_queue_reset(dev, phy2->q_tx[i]);
++ if (phy3)
++ mt76_queue_reset(dev, phy3->q_tx[i]);
++ }
++
++ for (i = 0; i < __MT_MCUQ_MAX; i++)
++ mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
++
++ mt76_for_each_q_rx(&dev->mt76, i) {
++ mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
++ }
++
++ mt76_tx_status_check(&dev->mt76, true);
++
++ mt76_for_each_q_rx(&dev->mt76, i)
++ mt76_queue_rx_reset(dev, i);
++
++ mt7996_dma_enable(dev);
++}
++
+ void mt7996_dma_cleanup(struct mt7996_dev *dev)
+ {
+ mt7996_dma_disable(dev, true);
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 631ada15..ced38ac8 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -278,8 +278,7 @@ static void mt7996_led_set_brightness(struct led_classdev *led_cdev,
+ mt7996_led_set_config(led_cdev, 0xff, 0);
+ }
+
+-static void
+-mt7996_init_txpower(struct mt7996_dev *dev,
++void mt7996_init_txpower(struct mt7996_dev *dev,
+ struct ieee80211_supported_band *sband)
+ {
+ int i, nss = hweight8(dev->mphy.antenna_mask);
+@@ -429,7 +428,7 @@ mt7996_mac_init_band(struct mt7996_dev *dev, u8 band)
+ mt76_rmw(dev, MT_WTBLOFF_RSCR(band), mask, set);
+ }
+
+-static void mt7996_mac_init(struct mt7996_dev *dev)
++void mt7996_mac_init(struct mt7996_dev *dev)
+ {
+ #define HIF_TXD_V2_1 4
+ int i;
+@@ -463,7 +462,7 @@ static void mt7996_mac_init(struct mt7996_dev *dev)
+ mt7996_mac_init_band(dev, i);
+ }
+
+-static int mt7996_txbf_init(struct mt7996_dev *dev)
++int mt7996_txbf_init(struct mt7996_dev *dev)
+ {
+ int ret;
+
+@@ -1075,6 +1074,8 @@ int mt7996_register_device(struct mt7996_dev *dev)
+ if (ret)
+ return ret;
+
++ dev->recovery.hw_init_done = true;
++
+ return mt7996_init_debugfs(&dev->phy);
+ }
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 8dc3a621..4c0c8f1e 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -1724,7 +1724,7 @@ mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state)
+ bool ret;
+
+ ret = wait_event_timeout(dev->reset_wait,
+- (READ_ONCE(dev->reset_state) & state),
++ (READ_ONCE(dev->recovery.state) & state),
+ MT7996_RESET_TIMEOUT);
+
+ WARN(!ret, "Timeout waiting for MCU reset state %x\n", state);
+@@ -1773,68 +1773,208 @@ mt7996_update_beacons(struct mt7996_dev *dev)
+ mt7996_update_vif_beacon, phy3->hw);
+ }
+
+-static void
+-mt7996_dma_reset(struct mt7996_dev *dev)
++void mt7996_tx_token_put(struct mt7996_dev *dev)
+ {
+- struct mt76_phy *phy2 = dev->mt76.phys[MT_BAND1];
+- struct mt76_phy *phy3 = dev->mt76.phys[MT_BAND2];
+- u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
+- int i;
++ struct mt76_txwi_cache *txwi;
++ int id;
+
+- mt76_clear(dev, MT_WFDMA0_GLO_CFG,
+- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+- MT_WFDMA0_GLO_CFG_RX_DMA_EN);
++ spin_lock_bh(&dev->mt76.token_lock);
++ idr_for_each_entry(&dev->mt76.token, txwi, id) {
++ mt7996_txwi_free(dev, txwi, NULL, NULL);
++ dev->mt76.token_count--;
++ }
++ spin_unlock_bh(&dev->mt76.token_lock);
++ idr_destroy(&dev->mt76.token);
++}
+
+- if (dev->hif2)
+- mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
+- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+- MT_WFDMA0_GLO_CFG_RX_DMA_EN);
+
+- usleep_range(1000, 2000);
++static int
++mt7996_mac_restart(struct mt7996_dev *dev)
++{
++ struct mt7996_phy *phy2, *phy3;
++ struct mt76_dev *mdev = &dev->mt76;
++ int i, ret;
+
+- for (i = 0; i < __MT_TXQ_MAX; i++) {
+- mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
+- if (phy2)
+- mt76_queue_tx_cleanup(dev, phy2->q_tx[i], true);
+- if (phy3)
+- mt76_queue_tx_cleanup(dev, phy3->q_tx[i], true);
++ phy2 = mt7996_phy2(dev);
++ phy3 = mt7996_phy3(dev);
++
++ if (dev->hif2) {
++ mt76_wr(dev, MT_INT1_MASK_CSR, 0x0);
++ mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
+ }
+
+- for (i = 0; i < __MT_MCUQ_MAX; i++)
+- mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
++ if (dev_is_pci(mdev->dev)) {
++ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
++ if (dev->hif2)
++ mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0);
++ }
+
+- mt76_for_each_q_rx(&dev->mt76, i)
+- mt76_queue_rx_reset(dev, i);
++ set_bit(MT76_RESET, &dev->mphy.state);
++ set_bit(MT76_MCU_RESET, &dev->mphy.state);
++ wake_up(&dev->mt76.mcu.wait);
++ if (phy2) {
++ set_bit(MT76_RESET, &phy2->mt76->state);
++ set_bit(MT76_MCU_RESET, &phy2->mt76->state);
++ }
++ if (phy3) {
++ set_bit(MT76_RESET, &phy3->mt76->state);
++ set_bit(MT76_MCU_RESET, &phy3->mt76->state);
++ }
+
+- mt76_tx_status_check(&dev->mt76, true);
++ /* lock/unlock all queues to ensure that no tx is pending */
++ mt76_txq_schedule_all(&dev->mphy);
++ if (phy2)
++ mt76_txq_schedule_all(phy2->mt76);
++ if (phy3)
++ mt76_txq_schedule_all(phy3->mt76);
++
++ /* disable all tx/rx napi */
++ mt76_worker_disable(&dev->mt76.tx_worker);
++ mt76_for_each_q_rx(mdev, i) {
++ if (mdev->q_rx[i].ndesc)
++ napi_disable(&dev->mt76.napi[i]);
++ }
++ napi_disable(&dev->mt76.tx_napi);
+
+- /* re-init prefetch settings after reset */
+- mt7996_dma_prefetch(dev);
++ /* token reinit */
++ mt7996_tx_token_put(dev);
++ idr_init(&dev->mt76.token);
+
+- mt76_set(dev, MT_WFDMA0_GLO_CFG,
+- MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
++ mt7996_dma_reset(dev, true);
+
+- if (dev->hif2)
+- mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
+- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+- MT_WFDMA0_GLO_CFG_RX_DMA_EN);
++ local_bh_disable();
++ mt76_for_each_q_rx(mdev, i) {
++ if (mdev->q_rx[i].ndesc) {
++ napi_enable(&dev->mt76.napi[i]);
++ napi_schedule(&dev->mt76.napi[i]);
++ }
++ }
++ local_bh_enable();
++ clear_bit(MT76_MCU_RESET, &dev->mphy.state);
++ clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
++
++ mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
++ mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
++ if (dev->hif2) {
++ mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask);
++ mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
++ }
++ if (dev_is_pci(mdev->dev)) {
++ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
++ if (dev->hif2)
++ mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
++ }
++
++ /* load firmware */
++ ret = mt7996_mcu_init_firmware(dev);
++ if (ret)
++ goto out;
++
++ /* set the necessary init items */
++ ret = mt7996_mcu_set_eeprom(dev);
++ if (ret)
++ goto out;
++
++ mt7996_mac_init(dev);
++ mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband);
++ mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband);
++ mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband);
++ ret = mt7996_txbf_init(dev);
++
++ if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
++ ret = mt7996_run(dev->mphy.hw);
++ if (ret)
++ goto out;
++ }
++
++ if (phy2 && test_bit(MT76_STATE_RUNNING, &phy2->mt76->state)) {
++ ret = mt7996_run(phy2->mt76->hw);
++ if (ret)
++ goto out;
++ }
++
++ if (phy3 && test_bit(MT76_STATE_RUNNING, &phy3->mt76->state)) {
++ ret = mt7996_run(phy3->mt76->hw);
++ if (ret)
++ goto out;
++ }
++
++out:
++ /* reset done */
++ clear_bit(MT76_RESET, &dev->mphy.state);
++ if (phy2)
++ clear_bit(MT76_RESET, &phy2->mt76->state);
++ if (phy3)
++ clear_bit(MT76_RESET, &phy3->mt76->state);
++
++ local_bh_disable();
++ napi_enable(&dev->mt76.tx_napi);
++ napi_schedule(&dev->mt76.tx_napi);
++ local_bh_enable();
++
++ mt76_worker_enable(&dev->mt76.tx_worker);
++ return ret;
+ }
+
+-void mt7996_tx_token_put(struct mt7996_dev *dev)
++static void
++mt7996_mac_full_reset(struct mt7996_dev *dev)
+ {
+- struct mt76_txwi_cache *txwi;
+- int id;
++ struct mt7996_phy *phy2, *phy3;
++ int i;
+
+- spin_lock_bh(&dev->mt76.token_lock);
+- idr_for_each_entry(&dev->mt76.token, txwi, id) {
+- mt7996_txwi_free(dev, txwi, NULL, NULL);
+- dev->mt76.token_count--;
++ phy2 = mt7996_phy2(dev);
++ phy3 = mt7996_phy3(dev);
++ dev->recovery.hw_full_reset = true;
++
++ wake_up(&dev->mt76.mcu.wait);
++ ieee80211_stop_queues(mt76_hw(dev));
++ if (phy2)
++ ieee80211_stop_queues(phy2->mt76->hw);
++ if (phy3)
++ ieee80211_stop_queues(phy3->mt76->hw);
++
++ cancel_delayed_work_sync(&dev->mphy.mac_work);
++ if (phy2)
++ cancel_delayed_work_sync(&phy2->mt76->mac_work);
++ if (phy3)
++ cancel_delayed_work_sync(&phy3->mt76->mac_work);
++
++ mutex_lock(&dev->mt76.mutex);
++ for (i = 0; i < 10; i++) {
++ if (!mt7996_mac_restart(dev))
++ break;
+ }
+- spin_unlock_bh(&dev->mt76.token_lock);
+- idr_destroy(&dev->mt76.token);
++ mutex_unlock(&dev->mt76.mutex);
++
++ if (i == 10)
++ dev_err(dev->mt76.dev, "chip full reset failed\n");
++
++ ieee80211_restart_hw(mt76_hw(dev));
++ if (phy2)
++ ieee80211_restart_hw(phy2->mt76->hw);
++ if (phy3)
++ ieee80211_restart_hw(phy3->mt76->hw);
++
++ ieee80211_wake_queues(mt76_hw(dev));
++ if (phy2)
++ ieee80211_wake_queues(phy2->mt76->hw);
++ if (phy3)
++ ieee80211_wake_queues(phy3->mt76->hw);
++
++ dev->recovery.hw_full_reset = false;
++ ieee80211_queue_delayed_work(mt76_hw(dev),
++ &dev->mphy.mac_work,
++ MT7996_WATCHDOG_TIME);
++ if (phy2)
++ ieee80211_queue_delayed_work(phy2->mt76->hw,
++ &phy2->mt76->mac_work,
++ MT7996_WATCHDOG_TIME);
++ if (phy3)
++ ieee80211_queue_delayed_work(phy3->mt76->hw,
++ &phy3->mt76->mac_work,
++ MT7996_WATCHDOG_TIME);
+ }
+
+-/* system error recovery */
+ void mt7996_mac_reset_work(struct work_struct *work)
+ {
+ struct mt7996_phy *phy2, *phy3;
+@@ -1845,9 +1985,36 @@ void mt7996_mac_reset_work(struct work_struct *work)
+ phy2 = mt7996_phy2(dev);
+ phy3 = mt7996_phy3(dev);
+
+- if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA))
++ /* chip full reset */
++ if (dev->recovery.restart) {
++ /* disable WA/WM WDT */
++ mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA,
++ MT_MCU_CMD_WDT_MASK);
++
++ if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT)
++ dev->recovery.wa_reset_count++;
++ else
++ dev->recovery.wm_reset_count++;
++
++ mt7996_mac_full_reset(dev);
++
++ /* enable mcu irq */
++ mt7996_irq_enable(dev, MT_INT_MCU_CMD);
++ mt7996_irq_disable(dev, 0);
++
++ /* enable WA/WM WDT */
++ mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
++
++ dev->recovery.state = MT_MCU_CMD_NORMAL_STATE;
++ dev->recovery.restart = false;
+ return;
++ }
+
++ if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA))
++ return;
++
++ dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.",
++ wiphy_name(dev->mt76.hw->wiphy));
+ ieee80211_stop_queues(mt76_hw(dev));
+ if (phy2)
+ ieee80211_stop_queues(phy2->mt76->hw);
+@@ -1876,7 +2043,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
+ mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
+
+ if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
+- mt7996_dma_reset(dev);
++ mt7996_dma_reset(dev, false);
+
+ mt7996_tx_token_put(dev);
+ idr_init(&dev->mt76.token);
+@@ -1931,6 +2098,32 @@ void mt7996_mac_reset_work(struct work_struct *work)
+ ieee80211_queue_delayed_work(phy3->mt76->hw,
+ &phy3->mt76->mac_work,
+ MT7996_WATCHDOG_TIME);
++ dev_info(dev->mt76.dev,"\n%s L1 SER recovery completed.",
++ wiphy_name(dev->mt76.hw->wiphy));
++}
++
++void mt7996_reset(struct mt7996_dev *dev)
++{
++ if (!dev->recovery.hw_init_done)
++ return;
++
++ if (dev->recovery.hw_full_reset)
++ return;
++
++ /* wm/wa exception: do full recovery */
++ if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) {
++ dev->recovery.restart = true;
++ dev_info(dev->mt76.dev,
++ "%s indicated firmware crash, attempting recovery\n",
++ wiphy_name(dev->mt76.hw->wiphy));
++
++ mt7996_irq_disable(dev, MT_INT_MCU_CMD);
++ queue_work(dev->mt76.wq, &dev->reset_work);
++ return;
++ }
++
++ queue_work(dev->mt76.wq, &dev->reset_work);
++ wake_up(&dev->reset_wait);
+ }
+
+ void mt7996_mac_update_stats(struct mt7996_phy *phy)
+diff --git a/mt7996/main.c b/mt7996/main.c
+index d8d578c0..cb0e0d31 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -22,17 +22,13 @@ static bool mt7996_dev_running(struct mt7996_dev *dev)
+ return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+ }
+
+-static int mt7996_start(struct ieee80211_hw *hw)
++int mt7996_run(struct ieee80211_hw *hw)
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ bool running;
+ int ret;
+
+- flush_work(&dev->init_work);
+-
+- mutex_lock(&dev->mt76.mutex);
+-
+ running = mt7996_dev_running(dev);
+ if (!running) {
+ ret = mt7996_mcu_set_hdr_trans(dev, true);
+@@ -71,6 +67,18 @@ static int mt7996_start(struct ieee80211_hw *hw)
+ mt7996_mac_reset_counters(phy);
+
+ out:
++ return ret;
++}
++
++static int mt7996_start(struct ieee80211_hw *hw)
++{
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ int ret;
++
++ flush_work(&dev->init_work);
++
++ mutex_lock(&dev->mt76.mutex);
++ ret = mt7996_run(hw);
+ mutex_unlock(&dev->mt76.mutex);
+
+ return ret;
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 0dbe2e01..a949ff76 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -2629,17 +2629,10 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev)
+ MCU_WM_UNI_CMD(VOW), true);
+ }
+
+-int mt7996_mcu_init(struct mt7996_dev *dev)
++int mt7996_mcu_init_firmware(struct mt7996_dev *dev)
+ {
+- static const struct mt76_mcu_ops mt7996_mcu_ops = {
+- .headroom = sizeof(struct mt76_connac2_mcu_txd), /* reuse */
+- .mcu_skb_send_msg = mt7996_mcu_send_message,
+- .mcu_parse_response = mt7996_mcu_parse_response,
+- };
+ int ret;
+
+- dev->mt76.mcu_ops = &mt7996_mcu_ops;
+-
+ /* force firmware operation mode into normal state,
+ * which should be set before firmware download stage.
+ */
+@@ -2680,6 +2673,19 @@ int mt7996_mcu_init(struct mt7996_dev *dev)
+ MCU_WA_PARAM_RED, 0, 0);
+ }
+
++int mt7996_mcu_init(struct mt7996_dev *dev)
++{
++ static const struct mt76_mcu_ops mt7996_mcu_ops = {
++ .headroom = sizeof(struct mt76_connac2_mcu_txd), /* reuse */
++ .mcu_skb_send_msg = mt7996_mcu_send_message,
++ .mcu_parse_response = mt7996_mcu_parse_response,
++ };
++
++ dev->mt76.mcu_ops = &mt7996_mcu_ops;
++
++ return mt7996_mcu_init_firmware(dev);
++}
++
+ void mt7996_mcu_exit(struct mt7996_dev *dev)
+ {
+ mt7996_mcu_restart(&dev->mt76);
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index ad66a1f8..778deedf 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -692,23 +692,21 @@ enum {
+ };
+
+ enum {
+- UNI_CMD_SER_QUERY = 0x0,
+- UNI_CMD_SER_SET = 0x2,
+- UNI_CMD_SER_TRIGGER = 0x3,
+-};
+-
+-enum {
+- SER_QUERY,
++ UNI_CMD_SER_QUERY,
+ /* recovery */
+- SER_SET_RECOVER_L1,
+- SER_SET_RECOVER_L2,
+- SER_SET_RECOVER_L3_RX_ABORT,
+- SER_SET_RECOVER_L3_TX_ABORT,
+- SER_SET_RECOVER_L3_TX_DISABLE,
+- SER_SET_RECOVER_L3_BF,
++ UNI_CMD_SER_SET_RECOVER_L1,
++ UNI_CMD_SER_SET_RECOVER_L2,
++ UNI_CMD_SER_SET_RECOVER_L3_RX_ABORT,
++ UNI_CMD_SER_SET_RECOVER_L3_TX_ABORT,
++ UNI_CMD_SER_SET_RECOVER_L3_TX_DISABLE,
++ UNI_CMD_SER_SET_RECOVER_L3_BF,
++ UNI_CMD_SER_SET_RECOVER_L4_MDP,
++ UNI_CMD_SER_SET_RECOVER_FULL,
++ UNI_CMD_SER_SET_SYSTEM_ASSERT,
+ /* action */
+- SER_ENABLE = 2,
+- SER_RECOVER
++ UNI_CMD_SER_ENABLE = 1,
++ UNI_CMD_SER_SET,
++ UNI_CMD_SER_TRIGGER
+ };
+
+ enum {
+diff --git a/mt7996/mmio.c b/mt7996/mmio.c
+index 6610cc45..0e11f398 100644
+--- a/mt7996/mmio.c
++++ b/mt7996/mmio.c
+@@ -289,10 +289,9 @@ static void mt7996_irq_tasklet(struct tasklet_struct *t)
+ u32 val = mt76_rr(dev, MT_MCU_CMD);
+
+ mt76_wr(dev, MT_MCU_CMD, val);
+- if (val & MT_MCU_CMD_ERROR_MASK) {
+- dev->reset_state = val;
+- ieee80211_queue_work(mt76_hw(dev), &dev->reset_work);
+- wake_up(&dev->reset_wait);
++ if (val & (MT_MCU_CMD_ERROR_MASK | MT_MCU_CMD_WDT_MASK)) {
++ dev->recovery.state = val;
++ mt7996_reset(dev);
+ }
+ }
+ }
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 25b20fa6..923e6fc9 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -268,7 +268,14 @@ struct mt7996_dev {
+ struct work_struct rc_work;
+ struct work_struct reset_work;
+ wait_queue_head_t reset_wait;
+- u32 reset_state;
++ struct {
++ u32 state;
++ u32 wa_reset_count;
++ u32 wm_reset_count;
++ bool hw_full_reset:1;
++ bool hw_init_done:1;
++ bool restart:1;
++ } recovery;
+
+ struct list_head sta_rc_list;
+ struct list_head sta_poll_list;
+@@ -401,9 +408,16 @@ int mt7996_eeprom_get_target_power(struct mt7996_dev *dev,
+ struct ieee80211_channel *chan);
+ s8 mt7996_eeprom_get_power_delta(struct mt7996_dev *dev, int band);
+ int mt7996_dma_init(struct mt7996_dev *dev);
++void mt7996_dma_reset(struct mt7996_dev *dev, bool force);
+ void mt7996_dma_prefetch(struct mt7996_dev *dev);
+ void mt7996_dma_cleanup(struct mt7996_dev *dev);
++void mt7996_init_txpower(struct mt7996_dev *dev,
++ struct ieee80211_supported_band *sband);
++int mt7996_txbf_init(struct mt7996_dev *dev);
++void mt7996_reset(struct mt7996_dev *dev);
++int mt7996_run(struct ieee80211_hw *hw);
+ int mt7996_mcu_init(struct mt7996_dev *dev);
++int mt7996_mcu_init_firmware(struct mt7996_dev *dev);
+ int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev,
+ struct mt7996_vif *mvif,
+ struct mt7996_twt_flow *flow,
+@@ -496,6 +510,7 @@ static inline void mt7996_irq_disable(struct mt7996_dev *dev, u32 mask)
+ mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
+ }
+
++void mt7996_mac_init(struct mt7996_dev *dev);
+ u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw);
+ bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask);
+ void mt7996_mac_reset_counters(struct mt7996_phy *phy);
+diff --git a/mt7996/regs.h b/mt7996/regs.h
+index 7a28cae3..0775ca58 100644
+--- a/mt7996/regs.h
++++ b/mt7996/regs.h
+@@ -317,6 +317,8 @@ enum base_rev {
+ #define MT_WFDMA0_RX_INT_PCIE_SEL MT_WFDMA0(0x154)
+ #define MT_WFDMA0_RX_INT_SEL_RING3 BIT(3)
+
++#define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4)
++
+ #define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208)
+ #define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0)
+ #define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2)
+@@ -444,6 +446,10 @@ enum base_rev {
+ #define MT_MCU_CMD_NORMAL_STATE BIT(5)
+ #define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1)
+
++#define MT_MCU_CMD_WA_WDT BIT(31)
++#define MT_MCU_CMD_WM_WDT BIT(30)
++#define MT_MCU_CMD_WDT_MASK GENMASK(31, 30)
++
+ /* l1/l2 remap */
+ #define MT_HIF_REMAP_L1 0x155024
+ #define MT_HIF_REMAP_L1_MASK GENMASK(31, 16)
+@@ -468,8 +474,27 @@ enum base_rev {
+ #define MT_INFRA_MCU_END 0x7c3fffff
+
+ /* FW MODE SYNC */
+-#define MT_SWDEF_MODE 0x9143c
++#define MT_SWDEF_BASE 0x00401400
++
++#define MT_SWDEF(ofs) (MT_SWDEF_BASE + (ofs))
++#define MT_SWDEF_MODE MT_SWDEF(0x3c)
+ #define MT_SWDEF_NORMAL_MODE 0
++#define MT_SWDEF_ICAP_MODE 1
++#define MT_SWDEF_SPECTRUM_MODE 2
++
++#define MT_SWDEF_SER_STATS MT_SWDEF(0x040)
++#define MT_SWDEF_PLE_STATS MT_SWDEF(0x044)
++#define MT_SWDEF_PLE1_STATS MT_SWDEF(0x048)
++#define MT_SWDEF_PLE_AMSDU_STATS MT_SWDEF(0x04C)
++#define MT_SWDEF_PSE_STATS MT_SWDEF(0x050)
++#define MT_SWDEF_PSE1_STATS MT_SWDEF(0x054)
++#define MT_SWDEF_LAMC_WISR6_BN0_STATS MT_SWDEF(0x058)
++#define MT_SWDEF_LAMC_WISR6_BN1_STATS MT_SWDEF(0x05C)
++#define MT_SWDEF_LAMC_WISR6_BN2_STATS MT_SWDEF(0x060)
++#define MT_SWDEF_LAMC_WISR7_BN0_STATS MT_SWDEF(0x064)
++#define MT_SWDEF_LAMC_WISR7_BN1_STATS MT_SWDEF(0x068)
++#define MT_SWDEF_LAMC_WISR7_BN2_STATS MT_SWDEF(0x06C)
++#define WF_SWDEF_WFDMA_STATUS_ADDR MT_SWDEF(0x090)
+
+ /* LED */
+ #define MT_LED_TOP_BASE 0x18013000
+@@ -506,7 +531,7 @@ enum base_rev {
+ #define MT_TOP_MISC_FW_STATE GENMASK(2, 0)
+
+ #define MT_HW_REV 0x70010204
+-#define MT_WF_SUBSYS_RST 0x70002600
++#define MT_WF_SUBSYS_RST 0x70028600
+
+ /* PCIE MAC */
+ #define MT_PCIE_MAC_BASE 0x74030000
+@@ -539,4 +564,11 @@ enum base_rev {
+ #define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY BIT(18)
+ #define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR BIT(29)
+
++#define MT_MCU_WM_CIRQ_BASE 0x89010000
++#define MT_MCU_WM_CIRQ(ofs) (MT_MCU_WM_CIRQ_BASE + (ofs))
++#define MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR MT_MCU_WM_CIRQ(0x80)
++#define MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR MT_MCU_WM_CIRQ(0xc0)
++#define MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR MT_MCU_WM_CIRQ(0x108)
++#define MT_MCU_WM_CIRQ_EINT_SOFT_ADDR MT_MCU_WM_CIRQ(0x118)
++
+ #endif
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0014-wifi-mt76-mt7996-add-dsp-firmware-download.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0014-wifi-mt76-mt7996-add-dsp-firmware-download.patch
new file mode 100644
index 0000000..8193a5a
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0014-wifi-mt76-mt7996-add-dsp-firmware-download.patch
@@ -0,0 +1,194 @@
+From 2d6ca0f6974ad4f6dcf110ccbbcbbc7185aa7655 Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Fri, 17 Feb 2023 14:13:38 +0800
+Subject: [PATCH 14/19] wifi: mt76: mt7996: add dsp firmware download
+
+Add DSP firmware for phy related control. Without this patch,the
+firmware state would not be ready.
+
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+---
+ mt76_connac_mcu.h | 1 +
+ mt7996/mcu.c | 94 +++++++++++++++++++++--------------------------
+ mt7996/mt7996.h | 7 ++++
+ mt7996/pci.c | 1 +
+ 4 files changed, 50 insertions(+), 53 deletions(-)
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index fa10d823..79dde31a 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -22,6 +22,7 @@
+
+ #define FW_START_OVERRIDE BIT(0)
+ #define FW_START_WORKING_PDA_CR4 BIT(2)
++#define FW_START_WORKING_PDA_DSP BIT(3)
+
+ #define PATCH_SEC_NOT_SUPPORT GENMASK(31, 0)
+ #define PATCH_SEC_TYPE_MASK GENMASK(15, 0)
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index a949ff76..09800ff2 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -2353,7 +2353,7 @@ out:
+ static int
+ mt7996_mcu_send_ram_firmware(struct mt7996_dev *dev,
+ const struct mt7996_fw_trailer *hdr,
+- const u8 *data, bool is_wa)
++ const u8 *data, enum mt7996_ram_type type)
+ {
+ int i, offset = 0;
+ u32 override = 0, option = 0;
+@@ -2365,8 +2365,10 @@ mt7996_mcu_send_ram_firmware(struct mt7996_dev *dev,
+
+ region = (const struct mt7996_fw_region *)((const u8 *)hdr -
+ (hdr->n_region - i) * sizeof(*region));
++ /* DSP and WA use same mode */
+ mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76,
+- region->feature_set, is_wa);
++ region->feature_set,
++ type != MT7996_RAM_TYPE_WM);
+ len = le32_to_cpu(region->len);
+ addr = le32_to_cpu(region->addr);
+
+@@ -2393,8 +2395,10 @@ mt7996_mcu_send_ram_firmware(struct mt7996_dev *dev,
+ if (override)
+ option |= FW_START_OVERRIDE;
+
+- if (is_wa)
++ if (type == MT7996_RAM_TYPE_WA)
+ option |= FW_START_WORKING_PDA_CR4;
++ else if (type == MT7996_RAM_TYPE_DSP)
++ option |= FW_START_WORKING_PDA_DSP;
+
+ return mt76_connac_mcu_start_firmware(&dev->mt76, override, option);
+ }
+@@ -2405,56 +2409,40 @@ static int mt7996_load_ram(struct mt7996_dev *dev)
+ const struct firmware *fw;
+ int ret;
+
+- ret = request_firmware(&fw, MT7996_FIRMWARE_WM, dev->mt76.dev);
+- if (ret)
+- return ret;
+-
+- if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
+- dev_err(dev->mt76.dev, "Invalid firmware\n");
+- ret = -EINVAL;
+- goto out;
+- }
+-
+- hdr = (const struct mt7996_fw_trailer *)(fw->data + fw->size - sizeof(*hdr));
+-
+- dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n",
+- hdr->fw_ver, hdr->build_date);
+-
+- ret = mt7996_mcu_send_ram_firmware(dev, hdr, fw->data, false);
+- if (ret) {
+- dev_err(dev->mt76.dev, "Failed to start WM firmware\n");
+- goto out;
+- }
+-
+- release_firmware(fw);
+-
+- ret = request_firmware(&fw, MT7996_FIRMWARE_WA, dev->mt76.dev);
+- if (ret)
+- return ret;
+-
+- if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
+- dev_err(dev->mt76.dev, "Invalid firmware\n");
+- ret = -EINVAL;
+- goto out;
+- }
+-
+- hdr = (const struct mt7996_fw_trailer *)(fw->data + fw->size - sizeof(*hdr));
+-
+- dev_info(dev->mt76.dev, "WA Firmware Version: %.10s, Build Time: %.15s\n",
+- hdr->fw_ver, hdr->build_date);
+-
+- ret = mt7996_mcu_send_ram_firmware(dev, hdr, fw->data, true);
+- if (ret) {
+- dev_err(dev->mt76.dev, "Failed to start WA firmware\n");
+- goto out;
+- }
+-
+- snprintf(dev->mt76.hw->wiphy->fw_version,
+- sizeof(dev->mt76.hw->wiphy->fw_version),
+- "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
+-
+-out:
+- release_firmware(fw);
++#define LOAD_RAM(_type) \
++ do { \
++ ret = request_firmware(&fw, MT7996_FIRMWARE_##_type, dev->mt76.dev); \
++ if (ret) \
++ return ret; \
++ \
++ if (!fw || !fw->data || fw->size < sizeof(*hdr)) { \
++ dev_err(dev->mt76.dev, "Invalid firmware\n"); \
++ release_firmware(fw); \
++ return -EINVAL; \
++ } \
++ \
++ hdr = (const struct mt7996_fw_trailer *) \
++ (fw->data + fw->size - sizeof(*hdr)); \
++ \
++ dev_info(dev->mt76.dev, \
++ "%s Firmware Version: %.10s, Build Time: %.15s\n", \
++ #_type, hdr->fw_ver, hdr->build_date); \
++ \
++ ret = mt7996_mcu_send_ram_firmware(dev, hdr, fw->data, \
++ MT7996_RAM_TYPE_##_type); \
++ if (ret) { \
++ dev_err(dev->mt76.dev, "Failed to start %s firmware\n", #_type);\
++ release_firmware(fw); \
++ return ret; \
++ } \
++ \
++ release_firmware(fw); \
++ } while (0)
++
++ LOAD_RAM(WM);
++ LOAD_RAM(DSP);
++ LOAD_RAM(WA);
++#undef LOAD_RAM
+
+ return ret;
+ }
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 923e6fc9..c2f8900c 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -29,6 +29,7 @@
+
+ #define MT7996_FIRMWARE_WA "mediatek/mt7996/mt7996_wa.bin"
+ #define MT7996_FIRMWARE_WM "mediatek/mt7996/mt7996_wm.bin"
++#define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin"
+ #define MT7996_ROM_PATCH "mediatek/mt7996/mt7996_rom_patch.bin"
+
+ #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin"
+@@ -55,6 +56,12 @@ struct mt7996_sta;
+ struct mt7996_dfs_pulse;
+ struct mt7996_dfs_pattern;
+
++enum mt7996_ram_type {
++ MT7996_RAM_TYPE_WM = 0,
++ MT7996_RAM_TYPE_WA,
++ MT7996_RAM_TYPE_DSP,
++};
++
+ enum mt7996_txq_id {
+ MT7996_TXQ_FWDL = 16,
+ MT7996_TXQ_MCU_WM,
+diff --git a/mt7996/pci.c b/mt7996/pci.c
+index 64aee3fb..c5301050 100644
+--- a/mt7996/pci.c
++++ b/mt7996/pci.c
+@@ -219,4 +219,5 @@ MODULE_DEVICE_TABLE(pci, mt7996_pci_device_table);
+ MODULE_DEVICE_TABLE(pci, mt7996_hif_device_table);
+ MODULE_FIRMWARE(MT7996_FIRMWARE_WA);
+ MODULE_FIRMWARE(MT7996_FIRMWARE_WM);
++MODULE_FIRMWARE(MT7996_FIRMWARE_DSP);
+ MODULE_FIRMWARE(MT7996_ROM_PATCH);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0015-wifi-mt76-mt7996-fix-eeprom-antenna-bitfield-mask.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0015-wifi-mt76-mt7996-fix-eeprom-antenna-bitfield-mask.patch
new file mode 100644
index 0000000..236cada
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0015-wifi-mt76-mt7996-fix-eeprom-antenna-bitfield-mask.patch
@@ -0,0 +1,33 @@
+From 763303e5fb846c92c22dd19ffec95d844103e425 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Thu, 23 Feb 2023 19:18:45 +0800
+Subject: [PATCH 15/19] wifi: mt76: mt7996: fix eeprom antenna bitfield mask
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ mt7996/eeprom.h | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
+index 8da599e0..cfc48698 100644
+--- a/mt7996/eeprom.h
++++ b/mt7996/eeprom.h
+@@ -31,11 +31,11 @@ enum mt7996_eeprom_field {
+ #define MT_EE_WIFI_CONF2_BAND_SEL GENMASK(2, 0)
+
+ #define MT_EE_WIFI_CONF1_TX_PATH_BAND0 GENMASK(5, 3)
+-#define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(5, 3)
+-#define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(2, 0)
++#define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(2, 0)
++#define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(5, 3)
+ #define MT_EE_WIFI_CONF4_STREAM_NUM_BAND0 GENMASK(5, 3)
+-#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(5, 3)
+-#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(2, 0)
++#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(2, 0)
++#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(5, 3)
+
+ #define MT_EE_RATE_DELTA_MASK GENMASK(5, 0)
+ #define MT_EE_RATE_DELTA_SIGN BIT(6)
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0016-wifi-mt76-mt7996-init-mpdu-density.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0016-wifi-mt76-mt7996-init-mpdu-density.patch
new file mode 100644
index 0000000..74992ab
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0016-wifi-mt76-mt7996-init-mpdu-density.patch
@@ -0,0 +1,53 @@
+From 322307272a4c4ccb627d6596220b0ab5bd4aed45 Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Mon, 13 Feb 2023 09:46:40 +0800
+Subject: [PATCH 16/19] wifi: mt76: mt7996: init mpdu density
+
+Init mpdu density based on the hardware capability to
+prevent hardware drop.
+
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+---
+ mt7996/init.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/mt7996/init.c b/mt7996/init.c
+index ced38ac8..479b2cee 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -374,10 +374,13 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
+
+ hw->max_tx_fragments = 4;
+
+- if (phy->mt76->cap.has_2ghz)
++ if (phy->mt76->cap.has_2ghz) {
+ phy->mt76->sband_2g.sband.ht_cap.cap |=
+ IEEE80211_HT_CAP_LDPC_CODING |
+ IEEE80211_HT_CAP_MAX_AMSDU;
++ phy->mt76->sband_2g.sband.ht_cap.ampdu_density =
++ IEEE80211_HT_MPDU_DENSITY_2;
++ }
+
+ if (phy->mt76->cap.has_5ghz) {
+ phy->mt76->sband_5g.sband.ht_cap.cap |=
+@@ -389,6 +392,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
+ IEEE80211_VHT_CAP_SHORT_GI_160 |
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
++ phy->mt76->sband_5g.sband.ht_cap.ampdu_density =
++ IEEE80211_HT_MPDU_DENSITY_1;
+ }
+
+ mt76_set_stream_caps(phy->mt76, true);
+@@ -873,7 +878,7 @@ mt7996_init_he_caps(struct mt7996_phy *phy, enum nl80211_band band,
+ u16 cap = IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS |
+ IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS;
+
+- cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_2,
++ cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_0_5,
+ IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) |
+ u16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K,
+ IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) |
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0017-wifi-mt76-mt7996-fix-icv-error-when-enable-AP-and-ST.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0017-wifi-mt76-mt7996-fix-icv-error-when-enable-AP-and-ST.patch
new file mode 100644
index 0000000..0b179f4
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0017-wifi-mt76-mt7996-fix-icv-error-when-enable-AP-and-ST.patch
@@ -0,0 +1,71 @@
+From b4af2c843368e7a787fc02ebde5a8ff41edf0a76 Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Thu, 2 Mar 2023 15:44:52 +0800
+Subject: [PATCH 17/19] wifi: mt76: mt7996: fix icv error when enable AP and
+ STA simultaneously
+
+Fix mcu command content to prevent ICV error
+1. The legacy mld index needs to start from 16.
+2. The bmc_tx_wlan_idx needs to be the vif index rather
+than peer AP's index.
+
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+---
+ mt7996/mcu.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 09800ff2..829f7be6 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -664,6 +664,7 @@ mt7996_mcu_bss_txcmd_tlv(struct sk_buff *skb, bool en)
+ static void
+ mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
+ {
++#define MT7996_LEGACY_MLD_IDX_START 16
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct bss_mld_tlv *mld;
+ struct tlv *tlv;
+@@ -672,8 +673,12 @@ mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
+
+ mld = (struct bss_mld_tlv *)tlv;
+ mld->group_mld_id = 0xff;
+- mld->own_mld_id = mvif->mt76.idx;
++ mld->own_mld_id = MT7996_LEGACY_MLD_IDX_START + mvif->mt76.idx;
+ mld->remap_idx = 0xff;
++ if (vif->type == NL80211_IFTYPE_AP) {
++ mld->group_mld_id = MT7996_LEGACY_MLD_IDX_START + mvif->mt76.idx;
++ memcpy(mld->mac_addr, vif->bss_conf.bssid, ETH_ALEN);
++ }
+ }
+
+ static void
+@@ -744,6 +749,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
+ struct cfg80211_chan_def *chandef = &phy->chandef;
+ struct mt76_connac_bss_basic_tlv *bss;
+ u32 type = CONNECTION_INFRA_AP;
++ u16 sta_wlan_idx = wlan_idx;
+ struct tlv *tlv;
+ int idx;
+
+@@ -763,7 +769,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
+ struct mt76_wcid *wcid;
+
+ wcid = (struct mt76_wcid *)sta->drv_priv;
+- wlan_idx = wcid->idx;
++ sta_wlan_idx = wcid->idx;
+ }
+ rcu_read_unlock();
+ }
+@@ -783,7 +789,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
+ bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
+ bss->dtim_period = vif->bss_conf.dtim_period;
+ bss->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx);
+- bss->sta_idx = cpu_to_le16(wlan_idx);
++ bss->sta_idx = cpu_to_le16(sta_wlan_idx);
+ bss->conn_type = cpu_to_le32(type);
+ bss->omac_idx = mvif->omac_idx;
+ bss->band_idx = mvif->band_idx;
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0018-wifi-mt76-mt7996-set-wcid-in-txp.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0018-wifi-mt76-mt7996-set-wcid-in-txp.patch
new file mode 100644
index 0000000..74f4e9e
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0018-wifi-mt76-mt7996-set-wcid-in-txp.patch
@@ -0,0 +1,35 @@
+From 68649746f1862d6c9b3e06492789aadde8c4d2e5 Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Mon, 6 Mar 2023 15:52:26 +0800
+Subject: [PATCH 18/19] wifi: mt76: mt7996: set wcid in txp
+
+Set correct wcid in txp for SDO to get wtbl.
+
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+---
+ mt7996/mac.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 4c0c8f1e..bb23f531 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -1168,10 +1168,12 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ }
+
+ txp->fw.token = cpu_to_le16(id);
+- if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags))
+- txp->fw.rept_wds_wcid = cpu_to_le16(wcid->idx);
+- else
++ if ((is_8023 && is_multicast_ether_addr(tx_info->skb->data)) ||
++ is_multicast_ether_addr(hdr->addr1))
+ txp->fw.rept_wds_wcid = cpu_to_le16(0xfff);
++ else
++ txp->fw.rept_wds_wcid = cpu_to_le16(wcid->idx);
++
+ tx_info->skb = DMA_DUMMY_DATA;
+
+ /* pass partial skb header to fw */
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0007-mt76-revert-page-pool-changes.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0019-mt76-revert-page-pool-changes.patch
similarity index 92%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0007-mt76-revert-page-pool-changes.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0019-mt76-revert-page-pool-changes.patch
index ab1161f..20feead 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0007-mt76-revert-page-pool-changes.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0019-mt76-revert-page-pool-changes.patch
@@ -1,7 +1,7 @@
-From 60c4e64c0198c828fafd5e7b96027ad5fd633213 Mon Sep 17 00:00:00 2001
+From 175bf122ac5790e7e28dadecd9410370364bc16a Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Mon, 6 Feb 2023 15:34:43 +0800
-Subject: [PATCH 7/7] mt76: revert page pool changes
+Subject: [PATCH 19/19] mt76: revert page pool changes
---
dma.c | 72 ++++++++++++++++++++++++++-------------------------
@@ -10,11 +10,11 @@
mt7915/main.c | 26 +++++++------------
mt7915/mmio.c | 55 ++++++++++++++++++++++++---------------
mt7921/main.c | 31 +++-------------------
- usb.c | 42 ++++++++++++++++--------------
- 7 files changed, 108 insertions(+), 197 deletions(-)
+ usb.c | 43 +++++++++++++++---------------
+ 7 files changed, 108 insertions(+), 198 deletions(-)
diff --git a/dma.c b/dma.c
-index e3fa4f39..50a7a689 100644
+index df2ca73f..7357b398 100644
--- a/dma.c
+++ b/dma.c
@@ -173,7 +173,7 @@ mt76_free_pending_rxwi(struct mt76_dev *dev)
@@ -39,7 +39,7 @@
buf = t->ptr;
t->dma_addr = 0;
-@@ -428,9 +428,9 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
+@@ -430,9 +430,9 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
} else {
buf = e->buf;
e->buf = NULL;
@@ -52,7 +52,7 @@
}
return buf;
-@@ -582,11 +582,11 @@ free_skb:
+@@ -584,11 +584,11 @@ free_skb:
}
static int
@@ -67,7 +67,7 @@
if (!q->ndesc)
return 0;
-@@ -594,25 +594,26 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
+@@ -596,25 +596,26 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
spin_lock_bh(&q->lock);
while (q->queued < q->ndesc - 1) {
@@ -105,7 +105,7 @@
break;
}
frames++;
-@@ -656,7 +657,7 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset)
+@@ -658,7 +659,7 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset)
/* WED txfree queue needs ring to be initialized before setup */
q->flags = 0;
mt76_dma_queue_reset(dev, q);
@@ -114,7 +114,7 @@
q->flags = flags;
ret = mtk_wed_device_txfree_ring_setup(wed, q->regs);
-@@ -704,10 +705,6 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
+@@ -706,10 +707,6 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
if (!q->entry)
return -ENOMEM;
@@ -125,7 +125,7 @@
ret = mt76_dma_wed_setup(dev, q, false);
if (ret)
return ret;
-@@ -721,6 +718,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
+@@ -723,6 +720,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
static void
mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
{
@@ -133,7 +133,7 @@
void *buf;
bool more;
-@@ -734,7 +732,7 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
+@@ -736,7 +734,7 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
if (!buf)
break;
@@ -142,7 +142,7 @@
} while (1);
if (q->rx_head) {
-@@ -743,6 +741,13 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
+@@ -745,6 +743,13 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
}
spin_unlock_bh(&q->lock);
@@ -156,7 +156,7 @@
}
static void
-@@ -763,7 +768,7 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid)
+@@ -765,7 +770,7 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid)
mt76_dma_wed_setup(dev, q, true);
if (q->flags != MT_WED_Q_TXFREE) {
mt76_dma_sync_idx(dev, q);
@@ -165,7 +165,7 @@
}
}
-@@ -781,7 +786,7 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
+@@ -783,7 +788,7 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
skb_add_rx_frag(skb, nr_frags, page, offset, len, q->buf_size);
} else {
@@ -174,7 +174,7 @@
}
if (more)
-@@ -854,7 +859,6 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
+@@ -856,7 +861,6 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
goto free_frag;
skb_reserve(skb, q->buf_offset);
@@ -182,7 +182,7 @@
*(u32 *)skb->cb = info;
-@@ -870,10 +874,10 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
+@@ -872,10 +876,10 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
continue;
free_frag:
@@ -195,7 +195,7 @@
return done;
}
-@@ -918,7 +922,7 @@ mt76_dma_init(struct mt76_dev *dev,
+@@ -920,7 +924,7 @@ mt76_dma_init(struct mt76_dev *dev,
mt76_for_each_q_rx(dev, i) {
netif_napi_add(&dev->napi_dev, &dev->napi[i], poll);
@@ -204,7 +204,7 @@
napi_enable(&dev->napi[i]);
}
-@@ -969,8 +973,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
+@@ -971,8 +975,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
netif_napi_del(&dev->napi[i]);
mt76_dma_rx_cleanup(dev, q);
@@ -214,7 +214,7 @@
mt76_free_pending_txwi(dev);
diff --git a/mac80211.c b/mac80211.c
-index b117e446..8a5f21e8 100644
+index e53166fc..d69e7214 100644
--- a/mac80211.c
+++ b/mac80211.c
@@ -4,7 +4,6 @@
@@ -225,7 +225,7 @@
#include "mt76.h"
#define CHAN2G(_idx, _freq) { \
-@@ -557,47 +556,6 @@ void mt76_unregister_phy(struct mt76_phy *phy)
+@@ -562,47 +561,6 @@ void mt76_unregister_phy(struct mt76_phy *phy)
}
EXPORT_SYMBOL_GPL(mt76_unregister_phy);
@@ -273,7 +273,7 @@
struct mt76_dev *
mt76_alloc_device(struct device *pdev, unsigned int size,
const struct ieee80211_ops *ops,
-@@ -1732,21 +1690,6 @@ void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
+@@ -1746,21 +1704,6 @@ void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
}
EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
@@ -296,7 +296,7 @@
{
struct ieee80211_hw *hw = phy->hw;
diff --git a/mt76.h b/mt76.h
-index ccca0162..f6a32fe3 100644
+index c3d1313e..49da2caa 100644
--- a/mt76.h
+++ b/mt76.h
@@ -202,7 +202,7 @@ struct mt76_queue {
@@ -308,7 +308,7 @@
};
struct mt76_mcu_ops {
-@@ -1318,7 +1318,6 @@ mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len,
+@@ -1329,7 +1329,6 @@ mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len,
return usb_bulk_msg(udev, pipe, data, len, actual_len, timeout);
}
@@ -316,7 +316,7 @@
void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
struct mt76_sta_stats *stats, bool eht);
int mt76_skb_adjust_pad(struct sk_buff *skb, int pad);
-@@ -1430,25 +1429,6 @@ void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked);
+@@ -1441,25 +1440,6 @@ void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked);
struct mt76_txwi_cache *mt76_rx_token_release(struct mt76_dev *dev, int token);
int mt76_rx_token_consume(struct mt76_dev *dev, void *ptr,
struct mt76_txwi_cache *r, dma_addr_t phys);
@@ -401,7 +401,7 @@
static void
diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 225a1960..cbe6e2cd 100644
+index 6f0c0e2a..5ef43c44 100644
--- a/mt7915/mmio.c
+++ b/mt7915/mmio.c
@@ -596,9 +596,13 @@ static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed)
@@ -505,7 +505,7 @@
return -ENOMEM;
}
diff --git a/mt7921/main.c b/mt7921/main.c
-index 75eaf86c..1434ca79 100644
+index a72964e7..4c400223 100644
--- a/mt7921/main.c
+++ b/mt7921/main.c
@@ -1090,34 +1090,17 @@ static void
@@ -571,7 +571,7 @@
static u64
diff --git a/usb.c b/usb.c
-index b88959ef..3e281715 100644
+index 5e5c7bf5..3e281715 100644
--- a/usb.c
+++ b/usb.c
@@ -319,27 +319,29 @@ mt76u_set_endpoints(struct usb_interface *intf,
@@ -688,11 +688,12 @@
int i;
for (i = 0; i < q->ndesc; i++) {
-@@ -705,7 +701,13 @@ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
+@@ -705,8 +701,13 @@ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
mt76u_urb_free(q->entry[i].urb);
q->entry[i].urb = NULL;
}
- page_pool_destroy(q->page_pool);
+- q->page_pool = NULL;
+
+ if (!q->rx_page.va)
+ return;
@@ -704,5 +705,5 @@
static void mt76u_free_rx(struct mt76_dev *dev)
--
-2.25.1
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0999-mt76-mt7996-for-build-pass.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0999-mt76-mt7996-for-build-pass.patch
index dd28dc9..2f9a0c3 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0999-mt76-mt7996-for-build-pass.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0999-mt76-mt7996-for-build-pass.patch
@@ -1,4 +1,4 @@
-From e66fbcb72e09e9e6a88fcedc84f4eda0d53ef65d Mon Sep 17 00:00:00 2001
+From a126ad08af718c71b4b05261caefb68996044330 Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Thu, 3 Nov 2022 00:27:17 +0800
Subject: [PATCH] mt76: mt7996: for build pass
@@ -6,16 +6,15 @@
Change-Id: Ieb44c33ee6e6a2e6058c1ef528404c1a1cbcfdaf
---
debugfs.c | 3 +++
- dma.c | 2 +-
eeprom.c | 8 +++++++-
mcu.c | 1 +
mt7615/mcu.c | 1 +
mt76_connac_mcu.c | 1 +
mt7915/mcu.c | 1 +
mt7996/dma.c | 4 ++--
- mt7996/eeprom.c | 1 +
+ mt7996/eeprom.c | 2 ++
mt7996/mcu.c | 1 +
- 10 files changed, 19 insertions(+), 4 deletions(-)
+ 9 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/debugfs.c b/debugfs.c
index 79064a4d..e10d4cbc 100644
@@ -33,19 +32,6 @@
return 0;
}
-diff --git a/dma.c b/dma.c
-index 50a7a689..beb9f4a4 100644
---- a/dma.c
-+++ b/dma.c
-@@ -854,7 +854,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
- !(dev->drv->rx_check(dev, data, len)))
- goto free_frag;
-
-- skb = napi_build_skb(data, q->buf_size);
-+ skb = build_skb(data, q->buf_size);
- if (!skb)
- goto free_frag;
-
diff --git a/eeprom.c b/eeprom.c
index ea54b7af..90d36c8d 100644
--- a/eeprom.c
@@ -92,7 +78,7 @@
static bool prefer_offload_fw = true;
module_param(prefer_offload_fw, bool, 0644);
diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
-index efb9bfaa..4a650721 100644
+index 4e4f6b35..e5815227 100644
--- a/mt76_connac_mcu.c
+++ b/mt76_connac_mcu.c
@@ -4,6 +4,7 @@
@@ -104,7 +90,7 @@
int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option)
{
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index f151ce86..20d81f05 100644
+index d08907f5..99ef8c9c 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -6,6 +6,7 @@
@@ -116,7 +102,7 @@
#define fw_name(_dev, name, ...) ({ \
char *_fw; \
diff --git a/mt7996/dma.c b/mt7996/dma.c
-index c09fe427..8c2e060d 100644
+index 18ea758c..3e2967f7 100644
--- a/mt7996/dma.c
+++ b/mt7996/dma.c
@@ -343,8 +343,8 @@ int mt7996_dma_init(struct mt7996_dev *dev)
@@ -131,19 +117,20 @@
mt7996_dma_enable(dev);
diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index 2e48c5a4..dd322f62 100644
+index 2e48c5a4..e747cb9f 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
-@@ -98,6 +98,7 @@ static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev)
+@@ -98,6 +98,8 @@ static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev)
if (ret)
return ret;
-+ cap = 0x4b249248; /* internal hardcode */
++ /* for internal testing */
++ cap = 0x4b249248;
if (cap) {
dev->has_eht = !(cap & MODE_HE_ONLY);
dev->wtbl_size_group = u32_get_bits(cap, WTBL_SIZE_GROUP);
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 1e47b0ae..db715195 100644
+index 829f7be6..0d9d309f 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -5,6 +5,7 @@
@@ -155,5 +142,5 @@
#include "mcu.h"
#include "mac.h"
--
-2.25.1
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/patches.inc b/recipes-wifi/linux-mt76/files/patches-3.x/patches.inc
index cf59945..51df096 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/patches.inc
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/patches.inc
@@ -1,12 +1,23 @@
#patch patches (come from openwrt/lede/target/linux/mediatek)
SRC_URI_append = " \
- file://0000-sync-to-master.patch \
- file://0001-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_tx_compl.patch \
- file://0002-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_skb_.patch \
- file://0003-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_comm.patch \
- file://0004-wifi-mt76-mt7996-add-muru-support.patch \
- file://0005-wifi-mt76-mt7996-set-txd-v1.patch \
- file://0006-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch \
- file://0007-mt76-revert-page-pool-changes.patch \
+ file://0001-wifi-mt76-mt7996-add-eht-rx-rate-support.patch \
+ file://0002-wifi-mt76-mt7996-let-non-bufferable-MMPDUs-use-corre.patch \
+ file://0003-wifi-mt76-mt7996-reduce-repeated-bss_info-and-sta_re.patch \
+ file://0004-wifi-mt76-mt7996-move-radio-enable-command-to-mt7996.patch \
+ file://0005-wifi-mt76-connac-set-correct-muar_idx-for-connac3-ch.patch \
+ file://0006-wifi-mt76-mt7996-fix-pointer-calculation-in-ie-count.patch \
+ file://0007-wifi-mt76-mt7996-remove-mt7996_mcu_set_pm.patch \
+ file://0008-wifi-mt76-mt7996-add-muru-support.patch \
+ file://0009-wifi-mt76-mt7996-set-txd-v1.patch \
+ file://0010-wifi-mt76-mt7996-add-thermal-protection-support.patch \
+ file://0011-wifi-mt76-mt7996-add-thermal-sensor-device-support.patch \
+ file://0012-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch \
+ file://0013-wifi-mt76-mt7996-add-L0.5-system-error-recovery-supp.patch \
+ file://0014-wifi-mt76-mt7996-add-dsp-firmware-download.patch \
+ file://0015-wifi-mt76-mt7996-fix-eeprom-antenna-bitfield-mask.patch \
+ file://0016-wifi-mt76-mt7996-init-mpdu-density.patch \
+ file://0017-wifi-mt76-mt7996-fix-icv-error-when-enable-AP-and-ST.patch \
+ file://0018-wifi-mt76-mt7996-set-wcid-in-txp.patch \
+ file://0019-mt76-revert-page-pool-changes.patch \
file://0999-mt76-mt7996-for-build-pass.patch \
"
diff --git a/recipes-wifi/linux-mt76/files/patches/0001-wifi-mt76-mt7915-rework-mt7915_thermal_init.patch b/recipes-wifi/linux-mt76/files/patches/0001-wifi-mt76-mt7915-rework-mt7915_thermal_init.patch
deleted file mode 100644
index 0494b40..0000000
--- a/recipes-wifi/linux-mt76/files/patches/0001-wifi-mt76-mt7915-rework-mt7915_thermal_init.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From e4a095d551a5d2252887b88d064dee43fcb4149d Mon Sep 17 00:00:00 2001
-From: Howard Hsu <howard-yh.hsu@mediatek.com>
-Date: Thu, 19 Jan 2023 11:03:44 +0800
-Subject: [PATCH] wifi: mt76: mt7915: rework mt7915_thermal_init()
-
-If the kernel configuration "CONFIG_HWMON" is not set to Y, the
-critial/maximum high temperature will not be initialised to the correct
-setting. Rework mt7915_thermal_init to fix this.
----
- mt7915/init.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/mt7915/init.c b/mt7915/init.c
-index ec297e04..8485a154 100644
---- a/mt7915/init.c
-+++ b/mt7915/init.c
-@@ -202,6 +202,10 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
- phy->cdev = cdev;
- }
-
-+ /* initialize critical/maximum high temperature */
-+ phy->throttle_temp[MT7915_CRIT_TEMP_IDX] = MT7915_CRIT_TEMP;
-+ phy->throttle_temp[MT7915_MAX_TEMP_IDX] = MT7915_MAX_TEMP;
-+
- if (!IS_REACHABLE(CONFIG_HWMON))
- return 0;
-
-@@ -210,10 +214,6 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
- if (IS_ERR(hwmon))
- return PTR_ERR(hwmon);
-
-- /* initialize critical/maximum high temperature */
-- phy->throttle_temp[MT7915_CRIT_TEMP_IDX] = MT7915_CRIT_TEMP;
-- phy->throttle_temp[MT7915_MAX_TEMP_IDX] = MT7915_MAX_TEMP;
--
- return 0;
- }
-
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches/1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch b/recipes-wifi/linux-mt76/files/patches/1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch
index 492a5de..ef37684 100644
--- a/recipes-wifi/linux-mt76/files/patches/1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch
@@ -1,7 +1,7 @@
-From 0585e668ca5e848c1b30f6f492ba0897ddb4071b Mon Sep 17 00:00:00 2001
+From 764731bb9676e58e8819bdbe48719b1076625032 Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Wed, 22 Jun 2022 10:39:47 +0800
-Subject: [PATCH] mt76: mt7915: add mtk internal debug tools for mt76
+Subject: [PATCH 1001/1009] mt76: mt7915: add mtk internal debug tools for mt76
---
mt76_connac_mcu.h | 6 +
@@ -22,10 +22,10 @@
create mode 100644 mt7915/mtk_mcu.c
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index a5e6ee4d..cbe0c52a 100644
+index 40a99e0c..312e7b3c 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1151,6 +1151,7 @@ enum {
+@@ -1148,6 +1148,7 @@ enum {
MCU_EXT_CMD_SET_TX_POWER_CTRL = 0x11,
MCU_EXT_CMD_FW_LOG_2_HOST = 0x13,
MCU_EXT_CMD_TXBF_ACTION = 0x1e,
@@ -33,7 +33,7 @@
MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21,
MCU_EXT_CMD_THERMAL_PROT = 0x23,
MCU_EXT_CMD_STA_REC_UPDATE = 0x25,
-@@ -1174,6 +1175,11 @@ enum {
+@@ -1171,6 +1172,11 @@ enum {
MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58,
MCU_EXT_CMD_RXDCOC_CAL = 0x59,
MCU_EXT_CMD_GET_MIB_INFO = 0x5a,
@@ -258,7 +258,7 @@
goto out;
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index f151ce86..ff718f78 100644
+index d08907f5..1fecd4b1 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -199,6 +199,11 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
@@ -285,7 +285,7 @@
{
#define RED_DISABLE 0
#define RED_BY_WA_ENABLE 2
-@@ -3377,6 +3385,8 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
+@@ -3379,6 +3387,8 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
.sku_enable = enable,
};
@@ -294,7 +294,7 @@
return mt76_mcu_send_msg(&dev->mt76,
MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
sizeof(req), true);
-@@ -3814,6 +3824,23 @@ int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
+@@ -3816,6 +3826,23 @@ int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
&req, sizeof(req), true);
}
@@ -318,7 +318,7 @@
int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set)
{
struct {
-@@ -3842,3 +3869,22 @@ int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set)
+@@ -3844,3 +3871,22 @@ int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set)
return 0;
}
diff --git a/recipes-wifi/linux-mt76/files/patches/1002-mt76-mt7915-csi-implement-csi-support.patch b/recipes-wifi/linux-mt76/files/patches/1002-mt76-mt7915-csi-implement-csi-support.patch
index bde66c3..125a023 100644
--- a/recipes-wifi/linux-mt76/files/patches/1002-mt76-mt7915-csi-implement-csi-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1002-mt76-mt7915-csi-implement-csi-support.patch
@@ -1,4 +1,4 @@
-From f7a36f2ff5ca5cdf4a5fca215b14622da6257016 Mon Sep 17 00:00:00 2001
+From 41752b5e4ac73781e070aabff226904ab9efb5e4 Mon Sep 17 00:00:00 2001
From: Bo Jiao <Bo.Jiao@mediatek.com>
Date: Mon, 6 Jun 2022 20:13:02 +0800
Subject: [PATCH 1002/1009] mt76: mt7915: csi: implement csi support
@@ -17,10 +17,10 @@
create mode 100644 mt7915/vendor.h
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index cbe0c52a..32156d35 100644
+index 312e7b3c..39a7f691 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1003,6 +1003,7 @@ enum {
+@@ -1000,6 +1000,7 @@ enum {
MCU_EXT_EVENT_CSA_NOTIFY = 0x4f,
MCU_EXT_EVENT_BCC_NOTIFY = 0x75,
MCU_EXT_EVENT_MURU_CTRL = 0x9f,
@@ -28,7 +28,7 @@
};
/* unified event table */
-@@ -1196,6 +1197,7 @@ enum {
+@@ -1193,6 +1194,7 @@ enum {
MCU_EXT_CMD_GROUP_PRE_CAL_INFO = 0xab,
MCU_EXT_CMD_DPD_PRE_CAL_INFO = 0xac,
MCU_EXT_CMD_PHY_STAT_INFO = 0xad,
@@ -54,10 +54,10 @@
mt7915e-$(CONFIG_NL80211_TESTMODE) += testmode.o
mt7915e-$(CONFIG_MT7986_WMAC) += soc.o
diff --git a/mt7915/init.c b/mt7915/init.c
-index 8485a154..06ac261f 100644
+index b88c3827..c27469e4 100644
--- a/mt7915/init.c
+++ b/mt7915/init.c
-@@ -652,6 +652,12 @@ mt7915_register_ext_phy(struct mt7915_dev *dev, struct mt7915_phy *phy)
+@@ -664,6 +664,12 @@ mt7915_register_ext_phy(struct mt7915_dev *dev, struct mt7915_phy *phy)
/* init wiphy according to mphy and phy */
mt7915_init_wiphy(phy);
@@ -70,7 +70,7 @@
ret = mt76_register_phy(mphy, true, mt76_rates,
ARRAY_SIZE(mt76_rates));
if (ret)
-@@ -1144,6 +1150,25 @@ void mt7915_set_stream_he_caps(struct mt7915_phy *phy)
+@@ -1165,6 +1171,25 @@ void mt7915_set_stream_he_caps(struct mt7915_phy *phy)
}
}
@@ -96,7 +96,7 @@
static void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
{
struct mt7915_phy *phy = mt7915_ext_phy(dev);
-@@ -1152,6 +1177,10 @@ static void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
+@@ -1173,6 +1198,10 @@ static void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
if (!phy)
return;
@@ -107,7 +107,7 @@
mt7915_unregister_thermal(phy);
mt76_unregister_phy(mphy);
ieee80211_free_hw(mphy->hw);
-@@ -1164,6 +1193,10 @@ static void mt7915_stop_hardware(struct mt7915_dev *dev)
+@@ -1185,6 +1214,10 @@ static void mt7915_stop_hardware(struct mt7915_dev *dev)
mt7915_dma_cleanup(dev);
tasklet_disable(&dev->irq_tasklet);
@@ -118,7 +118,7 @@
if (is_mt7986(&dev->mt76))
mt7986_wmac_disable(dev);
}
-@@ -1204,6 +1237,12 @@ int mt7915_register_device(struct mt7915_dev *dev)
+@@ -1225,6 +1258,12 @@ int mt7915_register_device(struct mt7915_dev *dev)
dev->mt76.test_ops = &mt7915_testmode_ops;
#endif
@@ -132,7 +132,7 @@
ARRAY_SIZE(mt76_rates));
if (ret)
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index ff718f78..59cce553 100644
+index 1fecd4b1..40f77428 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -36,6 +36,10 @@ static bool sr_scene_detect = true;
@@ -158,7 +158,7 @@
case MCU_EXT_EVENT_BCC_NOTIFY:
mt7915_mcu_rx_bcc_notify(dev, skb);
break;
-@@ -3824,6 +3833,108 @@ int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
+@@ -3826,6 +3835,108 @@ int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
&req, sizeof(req), true);
}
@@ -353,7 +353,7 @@
+
#endif
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 19880099..bd2ca6cc 100644
+index 5fcc8ace..e0133b13 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
@@ -294,6 +294,20 @@ struct mt7915_phy {
@@ -377,7 +377,7 @@
};
struct mt7915_dev {
-@@ -675,6 +689,12 @@ void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+@@ -674,6 +688,12 @@ void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
bool pci, int *irq);
diff --git a/recipes-wifi/linux-mt76/files/patches/1003-mt76-mt7915-air-monitor-support.patch b/recipes-wifi/linux-mt76/files/patches/1003-mt76-mt7915-air-monitor-support.patch
index c59c63d..b3388ce 100644
--- a/recipes-wifi/linux-mt76/files/patches/1003-mt76-mt7915-air-monitor-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1003-mt76-mt7915-air-monitor-support.patch
@@ -1,4 +1,4 @@
-From a97766c58f1dc2a25421f1bc527a06b59cd5f0dc Mon Sep 17 00:00:00 2001
+From f6b5a16ecd5e9cc986a3dde75a84a447aa729449 Mon Sep 17 00:00:00 2001
From: Bo Jiao <Bo.Jiao@mediatek.com>
Date: Tue, 11 Jan 2022 12:03:23 +0800
Subject: [PATCH 1003/1009] mt76: mt7915: air monitor support
@@ -13,10 +13,10 @@
6 files changed, 440 insertions(+)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 32156d35..60161c9e 100644
+index 39a7f691..d35f9e92 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1197,6 +1197,8 @@ enum {
+@@ -1194,6 +1194,8 @@ enum {
MCU_EXT_CMD_GROUP_PRE_CAL_INFO = 0xab,
MCU_EXT_CMD_DPD_PRE_CAL_INFO = 0xac,
MCU_EXT_CMD_PHY_STAT_INFO = 0xad,
@@ -55,7 +55,7 @@
}
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index bd2ca6cc..9a9d7f55 100644
+index e0133b13..df0d7a1e 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
@@ -250,6 +250,35 @@ struct mt7915_hif {
@@ -103,7 +103,7 @@
#endif
};
-@@ -693,6 +724,9 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
+@@ -692,6 +723,9 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
void mt7915_vendor_register(struct mt7915_phy *phy);
int mt7915_mcu_set_csi(struct mt7915_phy *phy, u8 mode,
u8 cfg, u8 v1, u32 v2, u8 *mac_addr);
diff --git a/recipes-wifi/linux-mt76/files/patches/1004-mt76-mt7915-add-support-for-muru_onoff-via-debugfs.patch b/recipes-wifi/linux-mt76/files/patches/1004-mt76-mt7915-add-support-for-muru_onoff-via-debugfs.patch
index 30c30f1..b2739d3 100644
--- a/recipes-wifi/linux-mt76/files/patches/1004-mt76-mt7915-add-support-for-muru_onoff-via-debugfs.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1004-mt76-mt7915-add-support-for-muru_onoff-via-debugfs.patch
@@ -1,4 +1,4 @@
-From f45e6908cbe43d1dd02f92569ed2549e021822e1 Mon Sep 17 00:00:00 2001
+From 7a1f0d570d96e8e23b771976da052e94def589b9 Mon Sep 17 00:00:00 2001
From: MeiChia Chiu <meichia.chiu@mediatek.com>
Date: Wed, 22 Jun 2022 10:45:53 +0800
Subject: [PATCH 1004/1009] mt76: mt7915: add support for muru_onoff via
@@ -13,10 +13,10 @@
5 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/mt7915/init.c b/mt7915/init.c
-index 06ac261..3897ac4 100644
+index c27469e4..1177e4e7 100644
--- a/mt7915/init.c
+++ b/mt7915/init.c
-@@ -433,6 +433,8 @@ mt7915_init_wiphy(struct mt7915_phy *phy)
+@@ -445,6 +445,8 @@ mt7915_init_wiphy(struct mt7915_phy *phy)
mphy->leds.cdev.brightness_set = mt7915_led_set_brightness;
mphy->leds.cdev.blink_set = mt7915_led_set_blink;
}
@@ -26,7 +26,7 @@
static void
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 59cce55..cf9a3e2 100644
+index 40f77428..b507f14f 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -864,6 +864,7 @@ mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
@@ -60,7 +60,7 @@
muru->mimo_dl.vht_mu_bfee =
!!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index c776417..275a0ec 100644
+index c776417b..275a0ece 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -609,4 +609,10 @@ struct csi_data {
@@ -75,7 +75,7 @@
+
#endif
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index df0d7a1..e94970b 100644
+index df0d7a1e..e94970ba 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
@@ -307,6 +307,8 @@ struct mt7915_phy {
@@ -88,7 +88,7 @@
struct mt76_channel_state state_ts;
diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index 4fb845b..1aafe04 100644
+index 530bde1a..824ddeda 100644
--- a/mt7915/mtk_debugfs.c
+++ b/mt7915/mtk_debugfs.c
@@ -2558,6 +2558,38 @@ static int mt7915_token_txd_read(struct seq_file *s, void *data)
@@ -139,5 +139,5 @@
&fops_fw_debug_module);
debugfs_create_file("fw_debug_level", 0600, dir, dev,
--
-2.39.0
+2.18.0
diff --git a/recipes-wifi/linux-mt76/files/patches/1005-mt76-mt7915-certification-patches.patch b/recipes-wifi/linux-mt76/files/patches/1005-mt76-mt7915-certification-patches.patch
index 1c216ec..8bb1195 100644
--- a/recipes-wifi/linux-mt76/files/patches/1005-mt76-mt7915-certification-patches.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1005-mt76-mt7915-certification-patches.patch
@@ -1,4 +1,4 @@
-From a3246b4d0ebb9b123c552f05226b0dc612c70788 Mon Sep 17 00:00:00 2001
+From a3b277ab5965fc3ea056d9d4f2f9a9dedd4fef51 Mon Sep 17 00:00:00 2001
From: MeiChia Chiu <meichia.chiu@mediatek.com>
Date: Mon, 6 Jun 2022 20:15:51 +0800
Subject: [PATCH 1005/1009] mt76: mt7915: certification patches
@@ -6,20 +6,20 @@
---
mt76_connac_mcu.h | 1 +
mt7915/mac.c | 23 +++
- mt7915/main.c | 15 +-
+ mt7915/main.c | 13 +-
mt7915/mcu.c | 466 +++++++++++++++++++++++++++++++++++++++++++
mt7915/mcu.h | 207 ++++++++++++++++++-
mt7915/mt7915.h | 13 ++
- mt7915/mtk_debugfs.c | 25 +--
+ mt7915/mtk_debugfs.c | 7 +-
mt7915/vendor.c | 187 +++++++++++++++++
mt7915/vendor.h | 42 ++++
- 9 files changed, 965 insertions(+), 14 deletions(-)
+ 9 files changed, 954 insertions(+), 5 deletions(-)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 60161c9..ff114cb 100644
+index d35f9e92..68e9c7e1 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1199,6 +1199,7 @@ enum {
+@@ -1196,6 +1196,7 @@ enum {
MCU_EXT_CMD_PHY_STAT_INFO = 0xad,
/* for vendor csi and air monitor */
MCU_EXT_CMD_SMESH_CTRL = 0xae,
@@ -28,7 +28,7 @@
};
diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 547519c..599d328 100644
+index 547519cc..599d328d 100644
--- a/mt7915/mac.c
+++ b/mt7915/mac.c
@@ -8,6 +8,7 @@
@@ -76,7 +76,7 @@
IEEE80211_RC_NSS_CHANGED |
IEEE80211_RC_BW_CHANGED))
diff --git a/mt7915/main.c b/mt7915/main.c
-index 3ded65d..05a5fbc 100644
+index 3ded65de..f0cbfbef 100644
--- a/mt7915/main.c
+++ b/mt7915/main.c
@@ -678,6 +678,9 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
@@ -107,10 +107,10 @@
void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index cf9a3e2..c15dce3 100644
+index b507f14f..057ea6ee 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
-@@ -3939,6 +3939,472 @@ mt7915_mcu_report_csi(struct mt7915_dev *dev, struct sk_buff *skb)
+@@ -3941,6 +3941,472 @@ mt7915_mcu_report_csi(struct mt7915_dev *dev, struct sk_buff *skb)
return 0;
}
@@ -584,7 +584,7 @@
#ifdef MTK_DEBUG
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 275a0ec..714bc44 100644
+index 275a0ece..714bc44d 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -416,10 +416,14 @@ enum {
@@ -818,7 +818,7 @@
#endif
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index e94970b..8b292c3 100644
+index e94970ba..8b292c3c 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
@@ -722,6 +722,19 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
@@ -842,10 +842,10 @@
int mt7915_mcu_set_csi(struct mt7915_phy *phy, u8 mode,
u8 cfg, u8 v1, u32 v2, u8 *mac_addr);
diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index 1aafe04..e0af645 100644
+index 824ddeda..4662f46f 100644
--- a/mt7915/mtk_debugfs.c
+++ b/mt7915/mtk_debugfs.c
-@@ -2564,7 +2564,8 @@ static int mt7915_muru_onoff_get(void *d
+@@ -2564,7 +2564,8 @@ static int mt7915_muru_onoff_get(void *data, u64 *val)
*val = phy->muru_onoff;
@@ -855,7 +855,7 @@
!!(phy->muru_onoff & MUMIMO_UL),
!!(phy->muru_onoff & MUMIMO_DL),
!!(phy->muru_onoff & OFDMA_UL),
-@@ -2577,8 +2578,8 @@ static int mt7915_muru_onoff_set(void *d
+@@ -2577,8 +2578,8 @@ static int mt7915_muru_onoff_set(void *data, u64 val)
{
struct mt7915_phy *phy = data;
@@ -867,7 +867,7 @@
}
diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index b94d787..beb0583 100644
+index b94d787e..beb0583a 100644
--- a/mt7915/vendor.c
+++ b/mt7915/vendor.c
@@ -22,6 +22,29 @@ csi_ctrl_policy[NUM_MTK_VENDOR_ATTRS_CSI_CTRL] = {
@@ -1079,7 +1079,7 @@
};
diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index 976817f..1b08321 100644
+index 976817f3..1b08321c 100644
--- a/mt7915/vendor.h
+++ b/mt7915/vendor.h
@@ -6,6 +6,48 @@
@@ -1132,5 +1132,5 @@
enum mtk_vendor_attr_csi_ctrl {
--
-2.39.0
+2.18.0
diff --git a/recipes-wifi/linux-mt76/files/patches/1006-mt76-mt7915-add-support-for-runtime-set-in-band-disc.patch b/recipes-wifi/linux-mt76/files/patches/1006-mt76-mt7915-add-support-for-runtime-set-in-band-disc.patch
index 8ed42b3..b1db4b7 100644
--- a/recipes-wifi/linux-mt76/files/patches/1006-mt76-mt7915-add-support-for-runtime-set-in-band-disc.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1006-mt76-mt7915-add-support-for-runtime-set-in-band-disc.patch
@@ -1,4 +1,4 @@
-From 1a60e2ba1ae97e6109e1e27dc48ae074b46043ff Mon Sep 17 00:00:00 2001
+From 8999d582213c666073a3bf3c855b66b16be16a52 Mon Sep 17 00:00:00 2001
From: MeiChia Chiu <meichia.chiu@mediatek.com>
Date: Fri, 27 May 2022 15:51:48 +0800
Subject: [PATCH 1006/1009] mt76: mt7915: add support for runtime set in-band
@@ -10,10 +10,10 @@
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 40b17b5f..f7ed1049 100644
+index 057ea6ee..03c94349 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
-@@ -1993,8 +1993,7 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
+@@ -1994,8 +1994,7 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
u8 *buf, interval;
int len;
@@ -23,7 +23,7 @@
interval = vif->bss_conf.fils_discovery.max_interval;
skb = ieee80211_get_fils_discovery_tmpl(hw, vif);
} else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP &&
-@@ -2029,7 +2028,7 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
+@@ -2030,7 +2029,7 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY);
discov->tx_interval = interval;
discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
diff --git a/recipes-wifi/linux-mt76/files/patches/1007-mt76-mt7915-add-mt76-vendor-muru-onoff-command.patch b/recipes-wifi/linux-mt76/files/patches/1007-mt76-mt7915-add-mt76-vendor-muru-onoff-command.patch
index 050a40b..39d4df8 100644
--- a/recipes-wifi/linux-mt76/files/patches/1007-mt76-mt7915-add-mt76-vendor-muru-onoff-command.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1007-mt76-mt7915-add-mt76-vendor-muru-onoff-command.patch
@@ -1,4 +1,4 @@
-From 7197b9ba537a486c3ba398d2e0a806f093b682a3 Mon Sep 17 00:00:00 2001
+From b789f416faea7dc90e4c83119274c773d417069c Mon Sep 17 00:00:00 2001
From: MeiChia Chiu <meichia.chiu@mediatek.com>
Date: Wed, 22 Jun 2022 10:53:43 +0800
Subject: [PATCH 1007/1009] mt76: mt7915: add mt76 vendor muru onoff command
@@ -11,10 +11,10 @@
4 files changed, 63 insertions(+)
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 3a0e87a..62d83bf 100644
+index 03c94349..70349a75 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
-@@ -3958,6 +3958,13 @@ void mt7915_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
+@@ -3960,6 +3960,13 @@ void mt7915_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
if (val == 0)
phy->muru_onoff = MUMIMO_DL_CERT | MUMIMO_DL;
break;
@@ -29,7 +29,7 @@
}
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 714bc44..aaea323 100644
+index 714bc44d..ac4e6c8b 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -423,6 +423,7 @@ enum {
@@ -41,7 +41,7 @@
};
diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index beb0583..5acbd2d 100644
+index beb0583a..8d864c86 100644
--- a/mt7915/vendor.c
+++ b/mt7915/vendor.c
@@ -34,6 +34,11 @@ wireless_ctrl_policy[NUM_MTK_VENDOR_ATTRS_WIRELESS_CTRL] = {
@@ -109,7 +109,7 @@
};
diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index 1b08321..a8e4ebf 100644
+index 1b08321c..2be5fc89 100644
--- a/mt7915/vendor.h
+++ b/mt7915/vendor.h
@@ -8,6 +8,7 @@ enum mtk_nl80211_vendor_subcmds {
@@ -139,5 +139,5 @@
MTK_VENDOR_ATTR_RFEATURE_CTRL_UNSPEC,
--
-2.39.0
+2.18.0
diff --git a/recipes-wifi/linux-mt76/files/patches/1008-mt76-mt7915-drop-undefined-action-frame.patch b/recipes-wifi/linux-mt76/files/patches/1008-mt76-mt7915-drop-undefined-action-frame.patch
index eea5003..a48e596 100644
--- a/recipes-wifi/linux-mt76/files/patches/1008-mt76-mt7915-drop-undefined-action-frame.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1008-mt76-mt7915-drop-undefined-action-frame.patch
@@ -1,4 +1,4 @@
-From d23718033b7a128a1bcffc203b38609116428374 Mon Sep 17 00:00:00 2001
+From d88b52321783cfb7cb51bc383d13ed270ccced43 Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Thu, 14 Apr 2022 15:18:02 +0800
Subject: [PATCH 1008/1009] mt76: mt7915: drop undefined action frame
diff --git a/recipes-wifi/linux-mt76/files/patches/1009-mt76-mt7915-add-fw_version-dump.patch b/recipes-wifi/linux-mt76/files/patches/1009-mt76-mt7915-add-fw_version-dump.patch
index 89c073a..f405a43 100644
--- a/recipes-wifi/linux-mt76/files/patches/1009-mt76-mt7915-add-fw_version-dump.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1009-mt76-mt7915-add-fw_version-dump.patch
@@ -1,4 +1,4 @@
-From e64af60e5c5642dec30e8605967b74dff53ada80 Mon Sep 17 00:00:00 2001
+From 5034a64c8d1905c639f2bb26f538f4d2d7703a21 Mon Sep 17 00:00:00 2001
From: Evelyn Tsai <evelyn.tsai@mediatek.com>
Date: Wed, 17 Aug 2022 13:40:24 +0800
Subject: [PATCH 1009/1009] mt76: mt7915: add fw_version dump
@@ -10,10 +10,10 @@
3 files changed, 32 insertions(+)
diff --git a/mt76.h b/mt76.h
-index ccca0162..00f1cd0d 100644
+index 183b0fc5..55751e8f 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -843,6 +843,10 @@ struct mt76_dev {
+@@ -844,6 +844,10 @@ struct mt76_dev {
struct mt76_usb usb;
struct mt76_sdio sdio;
};
@@ -59,7 +59,7 @@
struct mt76_connac2_patch_sec *sec;
u32 len, addr, mode;
diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index f8d2cbbb..cba38513 100644
+index 4662f46f..05dc7d5a 100644
--- a/mt7915/mtk_debugfs.c
+++ b/mt7915/mtk_debugfs.c
@@ -2799,6 +2799,22 @@ static int mt7915_agginfo_read_band1(struct seq_file *s, void *data)
diff --git a/recipes-wifi/linux-mt76/files/patches/1111-mt76-testmode-rework-testmode-init-registers.patch b/recipes-wifi/linux-mt76/files/patches/1111-mt76-testmode-rework-testmode-init-registers.patch
index 54c27fb..d8bcf4c 100644
--- a/recipes-wifi/linux-mt76/files/patches/1111-mt76-testmode-rework-testmode-init-registers.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1111-mt76-testmode-rework-testmode-init-registers.patch
@@ -1,7 +1,7 @@
-From 6517389a3eb0ee290151240c1639a94405fdfbd8 Mon Sep 17 00:00:00 2001
+From 67a19923b1e9f0491531d7f641725310b5152f87 Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Mon, 6 Jun 2022 19:46:26 +0800
-Subject: [PATCH 1111/1133] mt76: testmode: rework testmode init registers
+Subject: [PATCH 1111/1132] mt76: testmode: rework testmode init registers
---
mac80211.c | 3 +-
@@ -17,10 +17,10 @@
10 files changed, 164 insertions(+), 35 deletions(-)
diff --git a/mac80211.c b/mac80211.c
-index b117e446..00e7b4f3 100644
+index 87902f4b..ad5d6f8b 100644
--- a/mac80211.c
+++ b/mac80211.c
-@@ -817,7 +817,8 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
+@@ -826,7 +826,8 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
}
#ifdef CONFIG_NL80211_TESTMODE
@@ -31,10 +31,10 @@
if (status->flag & RX_FLAG_FAILED_FCS_CRC)
phy->test.rx_stats.fcs_error[q]++;
diff --git a/mt76.h b/mt76.h
-index 00f1cd0d..25ad0f6b 100644
+index 55751e8f..ca664489 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -643,6 +643,8 @@ struct mt76_testmode_ops {
+@@ -644,6 +644,8 @@ struct mt76_testmode_ops {
int (*dump_stats)(struct mt76_phy *phy, struct sk_buff *msg);
};
@@ -43,7 +43,7 @@
struct mt76_testmode_data {
enum mt76_testmode_state state;
-@@ -674,6 +676,8 @@ struct mt76_testmode_data {
+@@ -675,6 +677,8 @@ struct mt76_testmode_data {
u8 addr[3][ETH_ALEN];
@@ -52,7 +52,7 @@
u32 tx_pending;
u32 tx_queued;
u16 tx_queued_limit;
-@@ -681,6 +685,7 @@ struct mt76_testmode_data {
+@@ -682,6 +686,7 @@ struct mt76_testmode_data {
struct {
u64 packets[__MT_RXQ_MAX];
u64 fcs_error[__MT_RXQ_MAX];
@@ -61,10 +61,10 @@
};
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index ff114cb9..1a146563 100644
+index 68e9c7e1..8ba8ebfe 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1193,6 +1193,7 @@ enum {
+@@ -1190,6 +1190,7 @@ enum {
MCU_EXT_CMD_OFFCH_SCAN_CTRL = 0x9a,
MCU_EXT_CMD_SET_RDD_TH = 0x9d,
MCU_EXT_CMD_MURU_CTRL = 0x9f,
@@ -73,7 +73,7 @@
MCU_EXT_CMD_GROUP_PRE_CAL_INFO = 0xab,
MCU_EXT_CMD_DPD_PRE_CAL_INFO = 0xac,
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index aaea3230..a4b7ef82 100644
+index ac4e6c8b..3c16d214 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -9,6 +9,7 @@
@@ -85,7 +85,7 @@
MCU_ATE_CLEAN_TXQUEUE = 0x1c,
};
diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 225a1960..6d8455d5 100644
+index 6f0c0e2a..dbafb5ff 100644
--- a/mt7915/mmio.c
+++ b/mt7915/mmio.c
@@ -120,6 +120,7 @@ static const u32 mt7986_reg[] = {
diff --git a/recipes-wifi/linux-mt76/files/patches/1112-mt76-testmode-additional-supports.patch b/recipes-wifi/linux-mt76/files/patches/1112-mt76-testmode-additional-supports.patch
index 1430ef9..e5beb49 100644
--- a/recipes-wifi/linux-mt76/files/patches/1112-mt76-testmode-additional-supports.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1112-mt76-testmode-additional-supports.patch
@@ -1,9 +1,10 @@
-From 947b0a84d32ca9fbdfc5befc133da50c1349694e Mon Sep 17 00:00:00 2001
+From ec2f469639d9c5119fb6f1592df8407f3f45a8fe Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Thu, 21 Apr 2022 15:43:19 +0800
-Subject: [PATCH 1112/1133] mt76: testmode: additional supports
+Subject: [PATCH 1112/1116] mt76: testmode: additional supports
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
dma.c | 3 +-
mac80211.c | 12 +
@@ -18,16 +19,16 @@
mt7915/mmio.c | 2 +
mt7915/mt7915.h | 14 +-
mt7915/regs.h | 3 +
- mt7915/testmode.c | 1172 ++++++++++++++++++++++++++++++++++++++++++---
+ mt7915/testmode.c | 1177 ++++++++++++++++++++++++++++++++++++++++++---
mt7915/testmode.h | 278 +++++++++++
testmode.c | 275 +++++++++--
testmode.h | 75 +++
- tools/fields.c | 80 ++++
+ tools/fields.c | 80 +++
tx.c | 3 +-
- 19 files changed, 1964 insertions(+), 148 deletions(-)
+ 19 files changed, 1969 insertions(+), 148 deletions(-)
diff --git a/dma.c b/dma.c
-index e3fa4f39..a6bb3730 100644
+index e3fa4f3..a6bb373 100644
--- a/dma.c
+++ b/dma.c
@@ -566,8 +566,7 @@ free:
@@ -41,7 +42,7 @@
#endif
diff --git a/mac80211.c b/mac80211.c
-index 00e7b4f3..2a66b1dd 100644
+index 00e7b4f..2a66b1d 100644
--- a/mac80211.c
+++ b/mac80211.c
@@ -56,6 +56,13 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = {
@@ -71,7 +72,7 @@
static const struct ieee80211_channel mt76_channels_6ghz[] = {
diff --git a/mt76.h b/mt76.h
-index 25ad0f6b..cde52268 100644
+index 25ad0f6..cde5226 100644
--- a/mt76.h
+++ b/mt76.h
@@ -641,6 +641,21 @@ struct mt76_testmode_ops {
@@ -233,7 +234,7 @@
static inline void mt76_testmode_reset(struct mt76_phy *phy, bool disable)
{
diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
-index 2fefac68..b6c2ccf0 100644
+index 2fefac6..b6c2ccf 100644
--- a/mt76_connac_mcu.c
+++ b/mt76_connac_mcu.c
@@ -394,6 +394,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb,
@@ -255,7 +256,7 @@
return;
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 1a146563..f616bcea 100644
+index 1a14656..f616bce 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -999,6 +999,7 @@ enum {
@@ -275,10 +276,10 @@
MCU_EXT_CMD_CSI_CTRL = 0xc2,
};
diff --git a/mt7915/init.c b/mt7915/init.c
-index f73d34a9..19447ad1 100644
+index 3897ac4..0a13a83 100644
--- a/mt7915/init.c
+++ b/mt7915/init.c
-@@ -681,7 +681,7 @@ static void mt7915_init_work(struct work_struct *work)
+@@ -683,7 +683,7 @@ static void mt7915_init_work(struct work_struct *work)
struct mt7915_dev *dev = container_of(work, struct mt7915_dev,
init_work);
@@ -288,7 +289,7 @@
mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband);
mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband);
diff --git a/mt7915/mac.c b/mt7915/mac.c
-index de2bdba5..1460a32b 100644
+index de2bdba..1460a32 100644
--- a/mt7915/mac.c
+++ b/mt7915/mac.c
@@ -627,16 +627,38 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
@@ -370,7 +371,7 @@
goto out;
diff --git a/mt7915/main.c b/mt7915/main.c
-index e4d1c27b..ea0d22fe 100644
+index f0cbfbe..651887c 100644
--- a/mt7915/main.c
+++ b/mt7915/main.c
@@ -238,7 +238,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
@@ -383,7 +384,7 @@
mvif->mt76.wmm_idx += 2;
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 6ec12fd2..4d878665 100644
+index 62d83bf..0e5ed14 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -383,6 +383,11 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb)
@@ -406,7 +407,7 @@
!rxd->seq)
mt7915_mcu_rx_unsolicited_event(dev, skb);
else
-@@ -2847,14 +2853,14 @@ static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev)
+@@ -2848,14 +2854,14 @@ static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev)
return 0;
}
@@ -424,7 +425,7 @@
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE),
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index a4b7ef82..1671d563 100644
+index a4b7ef8..1671d56 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -8,10 +8,15 @@
@@ -481,7 +482,7 @@
enum {
diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 6d8455d5..9a666d0f 100644
+index 6d8455d..9a666d0 100644
--- a/mt7915/mmio.c
+++ b/mt7915/mmio.c
@@ -134,6 +134,7 @@ static const u32 mt7915_offs[] = {
@@ -501,10 +502,10 @@
[AGG_PCR0] = 0x040,
[AGG_ACR0] = 0x054,
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 018fd23e..c45e42c5 100644
+index 8b292c3..9d9c5fc 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
-@@ -321,6 +321,9 @@ struct mt7915_phy {
+@@ -323,6 +323,9 @@ struct mt7915_phy {
u8 last_snr;
u8 spe_idx;
@@ -514,7 +515,7 @@
} test;
#endif
-@@ -420,6 +423,14 @@ struct mt7915_dev {
+@@ -422,6 +425,14 @@ struct mt7915_dev {
void __iomem *dcm;
void __iomem *sku;
@@ -529,7 +530,7 @@
#ifdef MTK_DEBUG
u16 wlan_idx;
struct {
-@@ -591,7 +602,7 @@ int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
+@@ -592,7 +603,7 @@ int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
void *data, u32 field);
@@ -538,7 +539,7 @@
int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset);
int mt7915_mcu_get_eeprom_free_block(struct mt7915_dev *dev, u8 *block_num);
int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable,
-@@ -629,6 +640,7 @@ int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl);
+@@ -630,6 +641,7 @@ int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl);
int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level);
void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb);
void mt7915_mcu_exit(struct mt7915_dev *dev);
@@ -547,7 +548,7 @@
static inline u16 mt7915_wtbl_size(struct mt7915_dev *dev)
{
diff --git a/mt7915/regs.h b/mt7915/regs.h
-index d6a05f13..e8768488 100644
+index d6a05f1..e876848 100644
--- a/mt7915/regs.h
+++ b/mt7915/regs.h
@@ -62,6 +62,7 @@ enum offs_rev {
@@ -568,7 +569,7 @@
(_n) * 4))
#define MT_AGG_PCR0(_band, _n) MT_WF_AGG(_band, (__OFFS(AGG_PCR0) + \
diff --git a/mt7915/testmode.c b/mt7915/testmode.c
-index 46939191..e0ba088f 100644
+index 4693919..9317a8e 100644
--- a/mt7915/testmode.c
+++ b/mt7915/testmode.c
@@ -9,6 +9,9 @@
@@ -1829,7 +1830,19 @@
}
static int
-@@ -807,6 +1771,7 @@ static int
+@@ -737,6 +1701,11 @@ mt7915_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)
+ struct mt7915_phy *phy = mphy->priv;
+ enum mt76_testmode_state prev_state = td->state;
+
++ if (!phy->monitor_vif) {
++ dev_err(phy->dev->mt76.dev, "Please make sure monitor interface is up\n");
++ return -ENOTCONN;
++ }
++
+ mphy->test.state = state;
+
+ if (prev_state == MT76_TM_STATE_TX_FRAMES ||
+@@ -807,6 +1776,7 @@ static int
mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)
{
struct mt7915_phy *phy = mphy->priv;
@@ -1837,7 +1850,7 @@
void *rx, *rssi;
int i;
-@@ -852,11 +1817,68 @@ mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)
+@@ -852,11 +1822,68 @@ mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)
nla_nest_end(msg, rx);
@@ -1907,7 +1920,7 @@
+ .set_eeprom = mt7915_tm_set_eeprom,
};
diff --git a/mt7915/testmode.h b/mt7915/testmode.h
-index a1c54c89..01b08e9e 100644
+index a1c54c8..01b08e9 100644
--- a/mt7915/testmode.h
+++ b/mt7915/testmode.h
@@ -4,6 +4,8 @@
@@ -2222,7 +2235,7 @@
+
#endif
diff --git a/testmode.c b/testmode.c
-index 1d0d5d30..7a9ed543 100644
+index 1d0d5d3..7a9ed54 100644
--- a/testmode.c
+++ b/testmode.c
@@ -27,28 +27,16 @@ const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
@@ -2689,7 +2702,7 @@
a = nla_nest_start(msg, MT76_TM_ATTR_TX_POWER);
if (!a)
diff --git a/testmode.h b/testmode.h
-index 89613266..57949f2b 100644
+index 8961326..57949f2 100644
--- a/testmode.h
+++ b/testmode.h
@@ -6,6 +6,8 @@
@@ -2794,7 +2807,7 @@
+
#endif
diff --git a/tools/fields.c b/tools/fields.c
-index e3f69089..6e36ab27 100644
+index e3f6908..6e36ab2 100644
--- a/tools/fields.c
+++ b/tools/fields.c
@@ -10,6 +10,7 @@ static const char * const testmode_state[] = {
@@ -2920,7 +2933,7 @@
};
diff --git a/tx.c b/tx.c
-index 1f309d05..6d55566f 100644
+index 1f309d0..6d55566 100644
--- a/tx.c
+++ b/tx.c
@@ -250,8 +250,7 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *
diff --git a/recipes-wifi/linux-mt76/files/patches/1113-mt76-testmode-add-pre-cal-support.patch b/recipes-wifi/linux-mt76/files/patches/1113-mt76-testmode-add-pre-cal-support.patch
index 496d3a6..137b15a 100644
--- a/recipes-wifi/linux-mt76/files/patches/1113-mt76-testmode-add-pre-cal-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1113-mt76-testmode-add-pre-cal-support.patch
@@ -1,7 +1,7 @@
-From 7e220c97e2010f5a36f5d86928bb0bb7f3f5aa16 Mon Sep 17 00:00:00 2001
+From 52d97d39f652d9b7441bbbe52de72b25796df4a0 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Wed, 31 Aug 2022 20:06:52 +0800
-Subject: [PATCH 1113/1133] mt76: testmode: add pre-cal support
+Subject: [PATCH 1113/1116] mt76: testmode: add pre-cal support
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Change-Id: Ibfbbc3443de994eeb4daa5e364b0a90f5d7d3bcd
@@ -20,7 +20,7 @@
11 files changed, 562 insertions(+), 13 deletions(-)
diff --git a/eeprom.c b/eeprom.c
-index 0a88048b..cb6ff17a 100644
+index 0a88048..cb6ff17 100644
--- a/eeprom.c
+++ b/eeprom.c
@@ -89,8 +89,10 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
@@ -37,7 +37,7 @@
out_put_node:
diff --git a/mt76.h b/mt76.h
-index cde52268..e22f82c7 100644
+index cde5226..e22f82c 100644
--- a/mt76.h
+++ b/mt76.h
@@ -642,6 +642,7 @@ struct mt76_testmode_ops {
@@ -49,7 +49,7 @@
struct mt76_testmode_entry_data {
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index f616bcea..89411ba6 100644
+index f616bce..89411ba 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -995,6 +995,7 @@ enum {
@@ -61,7 +61,7 @@
MCU_EXT_EVENT_FW_LOG_2_HOST = 0x13,
MCU_EXT_EVENT_THERMAL_PROTECT = 0x22,
diff --git a/mt7915/eeprom.h b/mt7915/eeprom.h
-index f3e56817..88aaa16a 100644
+index f3e5681..88aaa16 100644
--- a/mt7915/eeprom.h
+++ b/mt7915/eeprom.h
@@ -39,10 +39,18 @@ enum mt7915_eeprom_field {
@@ -114,7 +114,7 @@
#endif
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 4d878665..fb89686b 100644
+index 0e5ed14..4922e73 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -387,6 +387,9 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb)
@@ -127,7 +127,7 @@
#endif
default:
break;
-@@ -2950,7 +2953,7 @@ int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev)
+@@ -2951,7 +2954,7 @@ int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev)
u8 idx = 0, *cal = dev->cal, *eep = dev->mt76.eeprom.data;
u32 total = MT_EE_CAL_GROUP_SIZE;
@@ -136,7 +136,7 @@
return 0;
/*
-@@ -3030,11 +3033,29 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy)
+@@ -3031,11 +3034,29 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
@@ -169,10 +169,10 @@
idx = mt7915_dpd_freq_idx(center_freq, chandef->width);
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index c45e42c5..5d12cbbc 100644
+index 9d9c5fc..d6fe9e7 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
-@@ -407,6 +407,10 @@ struct mt7915_dev {
+@@ -409,6 +409,10 @@ struct mt7915_dev {
struct rchan *relay_fwlog;
void *cal;
@@ -183,7 +183,7 @@
struct {
u8 debug_wm;
-@@ -641,6 +645,7 @@ int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level);
+@@ -642,6 +646,7 @@ int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level);
void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb);
void mt7915_mcu_exit(struct mt7915_dev *dev);
int mt7915_tm_txbf_status_read(struct mt7915_dev *dev, struct sk_buff *skb);
@@ -192,7 +192,7 @@
static inline u16 mt7915_wtbl_size(struct mt7915_dev *dev)
{
diff --git a/mt7915/testmode.c b/mt7915/testmode.c
-index e0ba088f..a9e57e4b 100644
+index 9317a8e..a7c185f 100644
--- a/mt7915/testmode.c
+++ b/mt7915/testmode.c
@@ -5,6 +5,7 @@
@@ -541,7 +541,7 @@
static void
mt7915_tm_update_params(struct mt7915_phy *phy, u32 changed)
{
-@@ -1715,6 +2024,10 @@ mt7915_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)
+@@ -1720,6 +2029,10 @@ mt7915_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)
else if (prev_state == MT76_TM_STATE_OFF ||
state == MT76_TM_STATE_OFF)
mt7915_tm_init(phy, !(state == MT76_TM_STATE_OFF));
@@ -552,7 +552,7 @@
if ((state == MT76_TM_STATE_IDLE &&
prev_state == MT76_TM_STATE_OFF) ||
-@@ -1876,9 +2189,113 @@ mt7915_tm_set_eeprom(struct mt76_phy *mphy, u32 offset, u8 *val, u8 action)
+@@ -1881,9 +2194,113 @@ mt7915_tm_set_eeprom(struct mt76_phy *mphy, u32 offset, u8 *val, u8 action)
return ret;
}
@@ -667,7 +667,7 @@
+ .dump_precal = mt7915_tm_dump_precal,
};
diff --git a/mt7915/testmode.h b/mt7915/testmode.h
-index 01b08e9e..d500987d 100644
+index 01b08e9..d500987 100644
--- a/mt7915/testmode.h
+++ b/mt7915/testmode.h
@@ -81,6 +81,11 @@ struct tm_tx_cont {
@@ -735,7 +735,7 @@
TAM_ARB_OP_MODE_NORMAL = 1,
TAM_ARB_OP_MODE_TEST,
diff --git a/testmode.c b/testmode.c
-index 7a9ed543..42da6f08 100644
+index 7a9ed54..42da6f0 100644
--- a/testmode.c
+++ b/testmode.c
@@ -763,6 +763,18 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
@@ -768,7 +768,7 @@
if (nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, td->tx_count) ||
diff --git a/testmode.h b/testmode.h
-index 57949f2b..34936e5f 100644
+index 57949f2..34936e5 100644
--- a/testmode.h
+++ b/testmode.h
@@ -19,6 +19,7 @@
@@ -824,7 +824,7 @@
/* keep last */
diff --git a/tools/fields.c b/tools/fields.c
-index 6e36ab27..1be1ffd6 100644
+index 6e36ab2..1be1ffd 100644
--- a/tools/fields.c
+++ b/tools/fields.c
@@ -11,6 +11,14 @@ static const char * const testmode_state[] = {
diff --git a/recipes-wifi/linux-mt76/files/patches/1114-mt76-testmode-add-iBF-command-mode-support.patch b/recipes-wifi/linux-mt76/files/patches/1114-mt76-testmode-add-iBF-command-mode-support.patch
index 8f8b4dc..ff74c33 100644
--- a/recipes-wifi/linux-mt76/files/patches/1114-mt76-testmode-add-iBF-command-mode-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1114-mt76-testmode-add-iBF-command-mode-support.patch
@@ -1,7 +1,7 @@
-From 0f8a11a93fd25593e5e778e0d0abda8d61127117 Mon Sep 17 00:00:00 2001
+From 074ca69eba297963caa63b79a20d2cdf962045d2 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Mon, 12 Sep 2022 18:16:54 +0800
-Subject: [PATCH 1114/1133] mt76: testmode: add iBF command mode support
+Subject: [PATCH 1114/1116] mt76: testmode: add iBF command mode support
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Change-Id: I7eea1d6412563f889e5774e787e58ce9eba001bd
@@ -13,7 +13,7 @@
4 files changed, 85 insertions(+), 7 deletions(-)
diff --git a/mt7915/testmode.c b/mt7915/testmode.c
-index a9e57e4b..99582d9c 100644
+index a7c185f..668f483 100644
--- a/mt7915/testmode.c
+++ b/mt7915/testmode.c
@@ -701,6 +701,7 @@ mt7915_tm_txbf_profile_update(struct mt7915_phy *phy, u16 *val, bool ebf)
@@ -105,7 +105,7 @@
mt7915_tm_set_tx_len(phy, tx_time);
diff --git a/testmode.c b/testmode.c
-index 42da6f08..b605a4bc 100644
+index 42da6f0..b605a4b 100644
--- a/testmode.c
+++ b/testmode.c
@@ -530,6 +530,42 @@ out:
@@ -164,7 +164,7 @@
nla_for_each_nested(cur, tb[MT76_TM_ATTR_TXBF_PARAM], rem) {
if (nla_len(cur) != 2 ||
diff --git a/testmode.h b/testmode.h
-index 34936e5f..bbfb313f 100644
+index 34936e5..bbfb313 100644
--- a/testmode.h
+++ b/testmode.h
@@ -281,8 +281,10 @@ enum mt76_testmode_txbf_act {
@@ -179,7 +179,7 @@
/* keep last */
diff --git a/tools/fields.c b/tools/fields.c
-index 1be1ffd6..47fc69f9 100644
+index 1be1ffd..47fc69f 100644
--- a/tools/fields.c
+++ b/tools/fields.c
@@ -32,6 +32,20 @@ static const char * const testmode_tx_mode[] = {
diff --git a/recipes-wifi/linux-mt76/files/patches/1115-mt76-testmode-add-ZWDFS-test-mode-support.patch b/recipes-wifi/linux-mt76/files/patches/1115-mt76-testmode-add-ZWDFS-test-mode-support.patch
index 10a8119..1128a92 100644
--- a/recipes-wifi/linux-mt76/files/patches/1115-mt76-testmode-add-ZWDFS-test-mode-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1115-mt76-testmode-add-ZWDFS-test-mode-support.patch
@@ -1,7 +1,7 @@
-From b269297b9cb95ea651d363ba49fff3d25d06f99b Mon Sep 17 00:00:00 2001
+From 34ccd9ebdfd36f8e6e7b554446eaeb022141307d Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Thu, 27 Oct 2022 17:42:07 +0800
-Subject: [PATCH 1115/1133] mt76: testmode: add ZWDFS test mode support
+Subject: [PATCH 1115/1116] mt76: testmode: add ZWDFS test mode support
Change-Id: I14d104b7158a35acf6b0595357d07fb87f5a9d94
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
@@ -19,7 +19,7 @@
10 files changed, 452 insertions(+), 1 deletion(-)
diff --git a/mt76.h b/mt76.h
-index e22f82c7..d5f5054f 100644
+index e22f82c..d5f5054 100644
--- a/mt76.h
+++ b/mt76.h
@@ -725,6 +725,15 @@ struct mt76_testmode_data {
@@ -39,7 +39,7 @@
struct mt76_vif {
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 89411ba6..5cef308a 100644
+index 89411ba..5cef308 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -1195,6 +1195,7 @@ enum {
@@ -59,10 +59,10 @@
enum {
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index fb89686b..988c55c6 100644
+index 4922e73..cce622d 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
-@@ -2685,6 +2685,7 @@ mt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy,
+@@ -2686,6 +2686,7 @@ mt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy,
req.monitor_chan = chandef->chan->hw_value;
req.monitor_central_chan =
ieee80211_frequency_to_channel(chandef->center_freq1);
@@ -70,7 +70,7 @@
req.band_idx = phy->mt76->band_idx;
req.scan_mode = 2;
break;
-@@ -4503,3 +4504,68 @@ int mt7915_mcu_set_amsdu_algo(struct mt7915_dev *dev, u16 wcid, u8 enable)
+@@ -4504,3 +4505,68 @@ int mt7915_mcu_set_amsdu_algo(struct mt7915_dev *dev, u16 wcid, u8 enable)
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MEC_CTRL), &req, sizeof(req), true);
}
#endif
@@ -140,7 +140,7 @@
+ return 0;
+}
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 1671d563..d780415c 100644
+index 1671d56..d780415 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -629,6 +629,52 @@ struct csi_data {
@@ -197,10 +197,10 @@
#define OFDMA_DL BIT(0)
#define OFDMA_UL BIT(1)
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 5d12cbbc..2b42fb11 100644
+index d6fe9e7..e99b586 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
-@@ -309,6 +309,7 @@ struct mt7915_phy {
+@@ -311,6 +311,7 @@ struct mt7915_phy {
struct mib_stats mib;
struct mt76_channel_state state_ts;
@@ -208,7 +208,7 @@
#ifdef CONFIG_NL80211_TESTMODE
struct {
-@@ -759,6 +760,9 @@ int mt7915_vendor_amnt_sta_remove(struct mt7915_phy *phy,
+@@ -760,6 +761,9 @@ int mt7915_vendor_amnt_sta_remove(struct mt7915_phy *phy,
struct ieee80211_sta *sta);
#endif
@@ -219,7 +219,7 @@
int mt7915_mtk_init_debugfs(struct mt7915_phy *phy, struct dentry *dir);
int mt7915_dbg_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3, bool wait_resp);
diff --git a/mt7915/regs.h b/mt7915/regs.h
-index e8768488..f4b57099 100644
+index e876848..f4b5709 100644
--- a/mt7915/regs.h
+++ b/mt7915/regs.h
@@ -1194,6 +1194,8 @@ enum offs_rev {
@@ -232,7 +232,7 @@
#define MT_WF_PHY_BASE 0x83080000
#define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs))
diff --git a/mt7915/testmode.c b/mt7915/testmode.c
-index 99582d9c..2ae6c07f 100644
+index 668f483..23dcabd 100644
--- a/mt7915/testmode.c
+++ b/mt7915/testmode.c
@@ -13,6 +13,12 @@ enum {
@@ -503,7 +503,7 @@
static int
diff --git a/testmode.c b/testmode.c
-index b605a4bc..58280a40 100644
+index b605a4b..58280a4 100644
--- a/testmode.c
+++ b/testmode.c
@@ -24,6 +24,13 @@ const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
@@ -567,7 +567,7 @@
nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) ||
(mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) &&
diff --git a/testmode.h b/testmode.h
-index bbfb313f..e03fa6df 100644
+index bbfb313..e03fa6d 100644
--- a/testmode.h
+++ b/testmode.h
@@ -63,6 +63,20 @@
@@ -635,7 +635,7 @@
+
#endif
diff --git a/tools/fields.c b/tools/fields.c
-index 47fc69f9..6f07eed0 100644
+index 47fc69f..6f07eed 100644
--- a/tools/fields.c
+++ b/tools/fields.c
@@ -46,6 +46,14 @@ static const char * const testmode_txbf_act[] = {
diff --git a/recipes-wifi/linux-mt76/files/patches/1116-mt76-testmode-add-iBF-eBF-cal-and-cert-commands-with.patch b/recipes-wifi/linux-mt76/files/patches/1116-mt76-testmode-add-iBF-eBF-cal-and-cert-commands-with.patch
index 8e9b2aa..fb5bb23 100644
--- a/recipes-wifi/linux-mt76/files/patches/1116-mt76-testmode-add-iBF-eBF-cal-and-cert-commands-with.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1116-mt76-testmode-add-iBF-eBF-cal-and-cert-commands-with.patch
@@ -1,7 +1,7 @@
-From e6da252b1895b1aebdfe737dcd57572d877cd1f1 Mon Sep 17 00:00:00 2001
+From a00620522ddc62d8070077e4d4a1ec18a8402bf9 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Thu, 15 Dec 2022 19:45:18 +0800
-Subject: [PATCH 1116/1133] mt76: testmode: add iBF/eBF cal and cert commands
+Subject: [PATCH 1116/1116] mt76: testmode: add iBF/eBF cal and cert commands
with golden
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
@@ -25,7 +25,7 @@
16 files changed, 856 insertions(+), 324 deletions(-)
diff --git a/mt76.h b/mt76.h
-index d5f5054f..6ab689af 100644
+index d5f5054..6ab689a 100644
--- a/mt76.h
+++ b/mt76.h
@@ -687,6 +687,7 @@ struct mt76_testmode_data {
@@ -47,7 +47,7 @@
u32 tx_pending;
u32 tx_queued;
diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
-index b6c2ccf0..6f5c81ce 100644
+index b6c2ccf..6f5c81c 100644
--- a/mt76_connac_mcu.c
+++ b/mt76_connac_mcu.c
@@ -2802,6 +2802,7 @@ int mt76_connac_mcu_bss_basic_tlv(struct sk_buff *skb,
@@ -68,7 +68,7 @@
memcpy(bss->bssid, phy->macaddr, ETH_ALEN);
}
diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 1460a32b..35b85843 100644
+index 1460a32..35b8584 100644
--- a/mt7915/mac.c
+++ b/mt7915/mac.c
@@ -752,8 +752,10 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
@@ -84,7 +84,7 @@
txwi[6] |= cpu_to_le32(val);
#endif
diff --git a/mt7915/main.c b/mt7915/main.c
-index ea0d22fe..ecd023f6 100644
+index 651887c..21ad3b0 100644
--- a/mt7915/main.c
+++ b/mt7915/main.c
@@ -205,46 +205,37 @@ static void mt7915_init_bitrate_mask(struct ieee80211_vif *vif)
@@ -175,7 +175,7 @@
return ret;
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 988c55c6..e82b7e14 100644
+index cce622d..d8a1b00 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -193,6 +193,7 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
@@ -227,7 +227,7 @@
if (enable) {
mt7915_mcu_bss_rfch_tlv(skb, vif, phy);
-@@ -3452,6 +3466,7 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
+@@ -3453,6 +3467,7 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action)
{
@@ -235,7 +235,7 @@
struct {
u8 action;
union {
-@@ -3478,7 +3493,6 @@ int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action)
+@@ -3479,7 +3494,6 @@ int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action)
.action = action,
};
@@ -243,7 +243,7 @@
switch (action) {
case MT_BF_SOUNDING_ON:
req.snd.snd_mode = MT_BF_PROCESSING;
-@@ -4396,6 +4410,9 @@ int mt7915_mcu_set_txbf_sound_info(struct mt7915_phy *phy, u8 action,
+@@ -4397,6 +4411,9 @@ int mt7915_mcu_set_txbf_sound_info(struct mt7915_phy *phy, u8 action,
req.he_opt = v2;
req.glo_opt = v3;
break;
@@ -254,7 +254,7 @@
return -EINVAL;
}
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index d780415c..5c5c92fc 100644
+index d780415..5c5c92f 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -476,10 +476,12 @@ enum {
@@ -448,7 +448,7 @@
MURU_SET_ARB_OP_MODE = 14,
MURU_SET_PLATFORM_TYPE = 25,
diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 9a666d0f..95ded131 100644
+index 9a666d0..95ded13 100644
--- a/mt7915/mmio.c
+++ b/mt7915/mmio.c
@@ -133,6 +133,7 @@ static const u32 mt7915_offs[] = {
@@ -468,10 +468,10 @@
[AGG_AALCR0] = 0x028,
[AGG_AWSCR0] = 0x030,
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 2b42fb11..ae06a7c6 100644
+index e99b586..bb9c374 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
-@@ -323,7 +323,6 @@ struct mt7915_phy {
+@@ -325,7 +325,6 @@ struct mt7915_phy {
u8 spe_idx;
@@ -479,7 +479,7 @@
bool bf_ever_en;
} test;
#endif
-@@ -428,7 +427,7 @@ struct mt7915_dev {
+@@ -430,7 +429,7 @@ struct mt7915_dev {
void __iomem *dcm;
void __iomem *sku;
@@ -488,7 +488,7 @@
struct {
void *txbf_phase_cal;
void *txbf_pfmu_data;
-@@ -567,6 +566,7 @@ void mt7915_dma_prefetch(struct mt7915_dev *dev);
+@@ -568,6 +567,7 @@ void mt7915_dma_prefetch(struct mt7915_dev *dev);
void mt7915_dma_cleanup(struct mt7915_dev *dev);
int mt7915_dma_reset(struct mt7915_dev *dev, bool force);
int mt7915_txbf_init(struct mt7915_dev *dev);
@@ -496,7 +496,7 @@
void mt7915_init_txpower(struct mt7915_dev *dev,
struct ieee80211_supported_band *sband);
void mt7915_reset(struct mt7915_dev *dev);
-@@ -645,8 +645,10 @@ int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl);
+@@ -646,8 +646,10 @@ int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl);
int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level);
void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb);
void mt7915_mcu_exit(struct mt7915_dev *dev);
@@ -508,7 +508,7 @@
static inline u16 mt7915_wtbl_size(struct mt7915_dev *dev)
{
-@@ -783,4 +785,10 @@ enum {
+@@ -784,4 +786,10 @@ enum {
#endif
@@ -520,7 +520,7 @@
+
#endif
diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index cba38513..867d52d1 100644
+index 05dc7d5..a130f56 100644
--- a/mt7915/mtk_debugfs.c
+++ b/mt7915/mtk_debugfs.c
@@ -2908,6 +2908,36 @@ mt7915_txpower_level_set(void *data, u64 val)
@@ -573,7 +573,7 @@
debugfs_create_devm_seqfile(dev->mt76.dev, "fw_version", dir,
diff --git a/mt7915/mtk_mcu.c b/mt7915/mtk_mcu.c
-index 143dae26..906c8725 100644
+index 143dae2..906c872 100644
--- a/mt7915/mtk_mcu.c
+++ b/mt7915/mtk_mcu.c
@@ -1,9 +1,10 @@
@@ -836,7 +836,7 @@
+}
+#endif
diff --git a/mt7915/regs.h b/mt7915/regs.h
-index f4b57099..007fd4d2 100644
+index f4b5709..007fd4d 100644
--- a/mt7915/regs.h
+++ b/mt7915/regs.h
@@ -61,6 +61,7 @@ enum offs_rev {
@@ -858,7 +858,7 @@
#define MT_WF_RMAC_BASE(_band) ((_band) ? 0x820f5000 : 0x820e5000)
#define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs))
diff --git a/mt7915/testmode.c b/mt7915/testmode.c
-index 2ae6c07f..e4af5e1c 100644
+index 23dcabd..ad1865e 100644
--- a/mt7915/testmode.c
+++ b/mt7915/testmode.c
@@ -53,6 +53,8 @@ struct reg_band {
@@ -1701,7 +1701,7 @@
rateval = mode << 6 | rate_idx;
tx_cont->rateval = cpu_to_le16(rateval);
diff --git a/mt7915/testmode.h b/mt7915/testmode.h
-index d500987d..19823694 100644
+index d500987..1982369 100644
--- a/mt7915/testmode.h
+++ b/mt7915/testmode.h
@@ -311,137 +311,7 @@ struct mt7915_tm_muru {
@@ -1845,7 +1845,7 @@
#endif
diff --git a/testmode.c b/testmode.c
-index 58280a40..a6b0c160 100644
+index 58280a4..a6b0c16 100644
--- a/testmode.c
+++ b/testmode.c
@@ -191,6 +191,7 @@ mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len,
@@ -1857,7 +1857,7 @@
memcpy(hdr->addr2, addr[1], ETH_ALEN);
memcpy(hdr->addr3, addr[2], ETH_ALEN);
diff --git a/testmode.h b/testmode.h
-index e03fa6df..0e96173b 100644
+index e03fa6d..0e96173 100644
--- a/testmode.h
+++ b/testmode.h
@@ -299,7 +299,10 @@ enum mt76_testmode_cfg {
@@ -1885,7 +1885,7 @@
/* keep last */
NUM_MT76_TM_TXBF_ACT,
diff --git a/tools/fields.c b/tools/fields.c
-index 6f07eed0..7211ec52 100644
+index 6f07eed..7211ec5 100644
--- a/tools/fields.c
+++ b/tools/fields.c
@@ -33,7 +33,10 @@ static const char * const testmode_tx_mode[] = {
diff --git a/recipes-wifi/linux-mt76/files/patches/1117-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch b/recipes-wifi/linux-mt76/files/patches/1117-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch
index 04e2217..43a0ae7 100644
--- a/recipes-wifi/linux-mt76/files/patches/1117-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1117-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch
@@ -1,14 +1,14 @@
-From 57e604539560994584444115d893df77a24fafe0 Mon Sep 17 00:00:00 2001
+From 55254f381217a874a2bb20c288107bb3d2f3811d Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Sun, 24 Apr 2022 10:07:00 +0800
-Subject: [PATCH 1117/1133] mt76: mt7915: init rssi in WTBL when add station
+Subject: [PATCH 1117/1132] mt76: mt7915: init rssi in WTBL when add station
---
mt7915/main.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/mt7915/main.c b/mt7915/main.c
-index ecd023f6..c32df9b1 100644
+index 21ad3b07..d1135d9f 100644
--- a/mt7915/main.c
+++ b/mt7915/main.c
@@ -692,6 +692,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
diff --git a/recipes-wifi/linux-mt76/files/patches/1118-mt76-connac-airtime-fairness-feature-off-in-mac80211.patch b/recipes-wifi/linux-mt76/files/patches/1118-mt76-connac-airtime-fairness-feature-off-in-mac80211.patch
index 27f8787..df0677d 100644
--- a/recipes-wifi/linux-mt76/files/patches/1118-mt76-connac-airtime-fairness-feature-off-in-mac80211.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1118-mt76-connac-airtime-fairness-feature-off-in-mac80211.patch
@@ -1,7 +1,7 @@
-From d0a0b51c3aea4e3a948e70aef7d137a5c4b235f3 Mon Sep 17 00:00:00 2001
+From 8ede062234d043820c188e0d25e68a9f71cb0e28 Mon Sep 17 00:00:00 2001
From: Evelyn Tsai <evelyn.tsai@mediatek.com>
Date: Fri, 6 May 2022 15:58:42 +0800
-Subject: [PATCH 1118/1133] mt76: connac: airtime fairness feature off in
+Subject: [PATCH 1118/1132] mt76: connac: airtime fairness feature off in
mac80211
---
@@ -9,10 +9,10 @@
1 file changed, 1 deletion(-)
diff --git a/mac80211.c b/mac80211.c
-index 2a66b1dd..e79568d1 100644
+index 9107c0c1..e2122c78 100644
--- a/mac80211.c
+++ b/mac80211.c
-@@ -436,7 +436,6 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
+@@ -437,7 +437,6 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
WIPHY_FLAG_AP_UAPSD;
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
diff --git a/recipes-wifi/linux-mt76/files/patches/1119-mt76-mt7915-add-mt7986-and-mt7916-pre-calibration.patch b/recipes-wifi/linux-mt76/files/patches/1119-mt76-mt7915-add-mt7986-and-mt7916-pre-calibration.patch
index c754c64..026f079 100644
--- a/recipes-wifi/linux-mt76/files/patches/1119-mt76-mt7915-add-mt7986-and-mt7916-pre-calibration.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1119-mt76-mt7915-add-mt7986-and-mt7916-pre-calibration.patch
@@ -1,7 +1,7 @@
-From 1d8b96957fe7ad695caf20a1525118bd48cf34f3 Mon Sep 17 00:00:00 2001
+From 166c44f4a9dfde91ac01c1cd04f79a3b9c8fe23e Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Fri, 20 May 2022 19:19:25 +0800
-Subject: [PATCH 1119/1133] mt76: mt7915: add mt7986 and mt7916 pre-calibration
+Subject: [PATCH 1119/1132] mt76: mt7915: add mt7986 and mt7916 pre-calibration
Add pre-calibration for mt7986 and mt7916. It has different data size
with mt7915. Group cal needs 54k and 94k for 2G + 5G and 2G + 6G,
@@ -62,10 +62,10 @@
MT_EE_RATE_DELTA_5G = 0x29d,
MT_EE_TX0_POWER_2G = 0x2fc,
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index d8a1b00e..185b6495 100644
+index e5cb9317..7da5bdfb 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
-@@ -2967,7 +2967,8 @@ static int mt7915_mcu_set_pre_cal(struct mt7915_dev *dev, u8 idx,
+@@ -2969,7 +2969,8 @@ static int mt7915_mcu_set_pre_cal(struct mt7915_dev *dev, u8 idx,
int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev)
{
u8 idx = 0, *cal = dev->cal, *eep = dev->mt76.eeprom.data;
@@ -75,7 +75,7 @@
if (!(eep[offs] & MT_EE_WIFI_CAL_GROUP))
return 0;
-@@ -3005,9 +3006,9 @@ static int mt7915_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur)
+@@ -3007,9 +3008,9 @@ static int mt7915_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur)
return -1;
}
@@ -87,7 +87,7 @@
5180, 5200, 5220, 5240,
5260, 5280, 5300, 5320,
5500, 5520, 5540, 5560,
-@@ -3015,34 +3016,69 @@ static int mt7915_dpd_freq_idx(u16 freq, u8 bw)
+@@ -3017,34 +3018,69 @@ static int mt7915_dpd_freq_idx(u16 freq, u8 bw)
5660, 5680, 5700, 5745,
5765, 5785, 5805, 5825
};
@@ -167,7 +167,7 @@
}
int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy)
-@@ -3074,24 +3110,24 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy)
+@@ -3076,24 +3112,24 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy)
if (!(eep[offs] & dpd_mask))
return 0;
diff --git a/recipes-wifi/linux-mt76/files/patches/1120-mt76-mt7915-add-phy-capability-vendor-command.patch b/recipes-wifi/linux-mt76/files/patches/1120-mt76-mt7915-add-phy-capability-vendor-command.patch
index 302d0ab..de77b3a 100644
--- a/recipes-wifi/linux-mt76/files/patches/1120-mt76-mt7915-add-phy-capability-vendor-command.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1120-mt76-mt7915-add-phy-capability-vendor-command.patch
@@ -1,7 +1,7 @@
-From 99d36c925c886a383d62fb3e9d009265161cf62a Mon Sep 17 00:00:00 2001
+From d181881aaeb24db4a51c75ac607eaeacc252e050 Mon Sep 17 00:00:00 2001
From: Yi-Chia Hsieh <Yi-Chia.Hsieh@mediatek.com>
Date: Tue, 12 Jul 2022 10:04:35 -0700
-Subject: [PATCH 1120/1133] mt76: mt7915: add phy capability vendor command
+Subject: [PATCH 1120/1132] mt76: mt7915: add phy capability vendor command
---
mt7915/mt7915.h | 1 +
@@ -22,7 +22,7 @@
#define MT7916_WTBL_SIZE 544
#define MT7915_WTBL_RESERVED (mt7915_wtbl_size(dev) - 1)
diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index 5acbd2d7..526eb6b2 100644
+index 8d864c86..607e66bb 100644
--- a/mt7915/vendor.c
+++ b/mt7915/vendor.c
@@ -50,6 +50,18 @@ rfeature_ctrl_policy[NUM_MTK_VENDOR_ATTRS_RFEATURE_CTRL] = {
@@ -99,7 +99,7 @@
};
diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index a8e4ebf9..719b851f 100644
+index 2be5fc89..ffdb466b 100644
--- a/mt7915/vendor.h
+++ b/mt7915/vendor.h
@@ -9,6 +9,7 @@ enum mtk_nl80211_vendor_subcmds {
diff --git a/recipes-wifi/linux-mt76/files/patches/1121-mt76-mt7915-add-vendor-subcmd-EDCCA-ctrl-enable-thre.patch b/recipes-wifi/linux-mt76/files/patches/1121-mt76-mt7915-add-vendor-subcmd-EDCCA-ctrl-enable-thre.patch
index ca559be..fc68b4d 100644
--- a/recipes-wifi/linux-mt76/files/patches/1121-mt76-mt7915-add-vendor-subcmd-EDCCA-ctrl-enable-thre.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1121-mt76-mt7915-add-vendor-subcmd-EDCCA-ctrl-enable-thre.patch
@@ -1,7 +1,7 @@
-From 9f4ef5f8637f597acf5fc876d40f9159e051e512 Mon Sep 17 00:00:00 2001
+From 0519381004e17ba76e11bda6d806bc5a4aedd013 Mon Sep 17 00:00:00 2001
From: Howard Hsu <howard-yh.hsu@mediatek.com>
Date: Fri, 24 Jun 2022 11:15:45 +0800
-Subject: [PATCH] mt76: mt7915: add vendor subcmd EDCCA ctrl
+Subject: [PATCH 1121/1132] mt76: mt7915: add vendor subcmd EDCCA ctrl
enable/threshold/compensation
Change-Id: I06a3f94d5e444be894200e2b6588d76ed38d09d0
@@ -16,10 +16,10 @@
7 files changed, 265 insertions(+), 1 deletion(-)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 5cef308a..65863a0d 100644
+index f4a329e8..e04500f5 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1205,6 +1205,7 @@ enum {
+@@ -1202,6 +1202,7 @@ enum {
MCU_EXT_CMD_SMESH_CTRL = 0xae,
MCU_EXT_CMD_RX_STAT_USER_CTRL = 0xb3,
MCU_EXT_CMD_CERT_CFG = 0xb7,
@@ -42,10 +42,10 @@
ret = mt7915_set_channel(phy);
if (ret)
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 185b6495..85bb60c9 100644
+index 7da5bdfb..28b2a624 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
-@@ -4623,3 +4623,76 @@ int mt7915_mcu_ipi_hist_scan(struct mt7915_phy *phy, void *data, u8 mode, bool w
+@@ -4625,3 +4625,76 @@ int mt7915_mcu_ipi_hist_scan(struct mt7915_phy *phy, void *data, u8 mode, bool w
return 0;
}
@@ -123,7 +123,7 @@
+ return 0;
+}
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 5c5c92fc..c87fe8e8 100644
+index 7d1dc500..7558726c 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -1058,6 +1058,27 @@ enum {
@@ -169,7 +169,7 @@
int mt7915_mcu_ipi_hist_scan(struct mt7915_phy *phy, void *data, u8 mode, bool wait_resp);
diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index 526eb6b2..f712d67c 100644
+index 607e66bb..e748ab16 100644
--- a/mt7915/vendor.c
+++ b/mt7915/vendor.c
@@ -62,6 +62,24 @@ phy_capa_dump_policy[NUM_MTK_VENDOR_ATTRS_PHY_CAPA_DUMP] = {
@@ -326,7 +326,7 @@
};
diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index 719b851f..72319717 100644
+index ffdb466b..0c96377f 100644
--- a/mt7915/vendor.h
+++ b/mt7915/vendor.h
@@ -2,6 +2,7 @@
diff --git a/recipes-wifi/linux-mt76/files/patches/1122-mt76-mt7915-implement-bin-file-mode.patch b/recipes-wifi/linux-mt76/files/patches/1122-mt76-mt7915-implement-bin-file-mode.patch
index fdd6c4d..c9c4ad9 100644
--- a/recipes-wifi/linux-mt76/files/patches/1122-mt76-mt7915-implement-bin-file-mode.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1122-mt76-mt7915-implement-bin-file-mode.patch
@@ -1,7 +1,7 @@
-From 8a6c47c698f273485f749c8aa2c3fd2b6a946c86 Mon Sep 17 00:00:00 2001
+From 5650267fdb5d7e237e58908b5f11c9bd12170c3a Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Thu, 7 Jul 2022 11:09:59 +0800
-Subject: [PATCH 1122/1133] mt76: mt7915: implement bin file mode
+Subject: [PATCH 1122/1132] mt76: mt7915: implement bin file mode
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
@@ -46,10 +46,10 @@
mt76_eeprom_override(struct mt76_phy *phy)
{
diff --git a/mt76.h b/mt76.h
-index 6ab689af..1638ef63 100644
+index 4cbe3670..675c12a4 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -900,9 +900,11 @@ struct mt76_dev {
+@@ -901,9 +901,11 @@ struct mt76_dev {
struct mt76_sdio sdio;
};
@@ -61,7 +61,7 @@
};
struct mt76_power_limits {
-@@ -1039,6 +1041,7 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
+@@ -1040,6 +1042,7 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
int mt76_eeprom_init(struct mt76_dev *dev, int len);
void mt76_eeprom_override(struct mt76_phy *phy);
int mt76_get_of_eeprom(struct mt76_dev *dev, void *data, int offset, int len);
@@ -203,7 +203,7 @@
#define PKT_BIN_DEBUG_MAGIC 0xc8763123
enum {
diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index da444f38..5f34afc7 100644
+index a130f564..1f347efe 100644
--- a/mt7915/mtk_debugfs.c
+++ b/mt7915/mtk_debugfs.c
@@ -3,6 +3,7 @@
diff --git a/recipes-wifi/linux-mt76/files/patches/1123-mt76-mt7915-initialize-wcid.patch b/recipes-wifi/linux-mt76/files/patches/1123-mt76-mt7915-initialize-wcid.patch
index 066630e..8c0393c 100644
--- a/recipes-wifi/linux-mt76/files/patches/1123-mt76-mt7915-initialize-wcid.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1123-mt76-mt7915-initialize-wcid.patch
@@ -1,7 +1,7 @@
-From 9758ae301b7a08ace837a88d9534c7f22e4fef7f Mon Sep 17 00:00:00 2001
+From 76dcae6805d85864d5ebea700fcc488f80fbd75d Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Tue, 12 Jul 2022 13:56:07 +0800
-Subject: [PATCH 1123/1133] mt76: mt7915: initialize wcid
+Subject: [PATCH 1123/1132] mt76: mt7915: initialize wcid
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
---
diff --git a/recipes-wifi/linux-mt76/files/patches/1124-mt76-mt7915-Add-mu-dump-support.patch b/recipes-wifi/linux-mt76/files/patches/1124-mt76-mt7915-Add-mu-dump-support.patch
index b3789c3..bac5e25 100644
--- a/recipes-wifi/linux-mt76/files/patches/1124-mt76-mt7915-Add-mu-dump-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1124-mt76-mt7915-Add-mu-dump-support.patch
@@ -1,7 +1,7 @@
-From dc1ea53db698073c61765925cdb17d28043c6f2d Mon Sep 17 00:00:00 2001
+From 0dbdca6f8f719929258c851bccd3dacbe78c4ad5 Mon Sep 17 00:00:00 2001
From: TomLiu <tomml.liu@mediatek.com>
Date: Thu, 11 Aug 2022 18:09:45 -0700
-Subject: [PATCH 1124/1133] mt76: mt7915: Add mu dump support
+Subject: [PATCH 1124/1132] mt76: mt7915: Add mu dump support
Change-Id: I521214f3feb6f0d528a9f550255050ffd1ec96d2
---
@@ -10,7 +10,7 @@
2 files changed, 25 insertions(+)
diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index f712d67c..83f38e07 100644
+index e748ab16..6915ac8d 100644
--- a/mt7915/vendor.c
+++ b/mt7915/vendor.c
@@ -37,6 +37,7 @@ wireless_ctrl_policy[NUM_MTK_VENDOR_ATTRS_WIRELESS_CTRL] = {
@@ -59,7 +59,7 @@
.maxattr = MTK_VENDOR_ATTR_MU_CTRL_MAX,
},
diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index 72319717..c19ffe72 100644
+index 0c96377f..d8e23d34 100644
--- a/mt7915/vendor.h
+++ b/mt7915/vendor.h
@@ -72,6 +72,7 @@ enum mtk_vendor_attr_mu_ctrl {
diff --git a/recipes-wifi/linux-mt76/files/patches/1125-mt76-mt7915-add-vendor-subcmd-three-wire-PTA-ctrl.patch b/recipes-wifi/linux-mt76/files/patches/1125-mt76-mt7915-add-vendor-subcmd-three-wire-PTA-ctrl.patch
index cd5fd8f..066ae83 100644
--- a/recipes-wifi/linux-mt76/files/patches/1125-mt76-mt7915-add-vendor-subcmd-three-wire-PTA-ctrl.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1125-mt76-mt7915-add-vendor-subcmd-three-wire-PTA-ctrl.patch
@@ -1,7 +1,7 @@
-From 6d68ed1f6ead694289dc9d2a98ef3d49dcb778dd Mon Sep 17 00:00:00 2001
+From 305cf303e1ab242784019ff78a2b534f7c9df707 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Fri, 28 Oct 2022 10:15:56 +0800
-Subject: [PATCH 1125/1133] mt76: mt7915: add vendor subcmd three wire (PTA)
+Subject: [PATCH 1125/1132] mt76: mt7915: add vendor subcmd three wire (PTA)
ctrl
Change-Id: Ic1044698f294455594a0c6254f55326fdab90580
@@ -16,10 +16,10 @@
6 files changed, 111 insertions(+), 29 deletions(-)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 65863a0d..41859dc3 100644
+index e04500f5..1ff517f0 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1204,7 +1204,7 @@ enum {
+@@ -1201,7 +1201,7 @@ enum {
/* for vendor csi and air monitor */
MCU_EXT_CMD_SMESH_CTRL = 0xae,
MCU_EXT_CMD_RX_STAT_USER_CTRL = 0xb3,
@@ -29,10 +29,10 @@
MCU_EXT_CMD_CSI_CTRL = 0xc2,
MCU_EXT_CMD_IPI_HIST_SCAN = 0xc5,
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 3408555e..ebe00300 100644
+index 28b2a624..baf74440 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
-@@ -4322,37 +4322,33 @@ void mt7915_mcu_set_dynalgo(struct mt7915_phy *phy, u8 enable)
+@@ -4324,37 +4324,33 @@ void mt7915_mcu_set_dynalgo(struct mt7915_phy *phy, u8 enable)
&req, sizeof(req), false);
}
@@ -94,7 +94,7 @@
void mt7915_mcu_set_bypass_smthint(struct mt7915_phy *phy, u8 val)
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index c87fe8e8..16517099 100644
+index 7558726c..0aee6948 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -847,6 +847,35 @@ struct mt7915_mcu_rdd_ipi_scan {
@@ -146,7 +146,7 @@
void mt7915_vendor_register(struct mt7915_phy *phy);
int mt7915_mcu_set_csi(struct mt7915_phy *phy, u8 mode,
diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index 83f38e07..48d124e0 100644
+index 6915ac8d..b26b1cc6 100644
--- a/mt7915/vendor.c
+++ b/mt7915/vendor.c
@@ -40,6 +40,11 @@ mu_ctrl_policy[NUM_MTK_VENDOR_ATTRS_MU_CTRL] = {
@@ -229,7 +229,7 @@
};
diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index c19ffe72..d96e5c23 100644
+index d8e23d34..de3cbe2c 100644
--- a/mt7915/vendor.h
+++ b/mt7915/vendor.h
@@ -12,6 +12,7 @@ enum mtk_nl80211_vendor_subcmds {
diff --git a/recipes-wifi/linux-mt76/files/patches/1126-mt76-mt7915-add-ibf-control-vendor-cmd.patch b/recipes-wifi/linux-mt76/files/patches/1126-mt76-mt7915-add-ibf-control-vendor-cmd.patch
index 1fa6a9a..72672ac 100644
--- a/recipes-wifi/linux-mt76/files/patches/1126-mt76-mt7915-add-ibf-control-vendor-cmd.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1126-mt76-mt7915-add-ibf-control-vendor-cmd.patch
@@ -1,7 +1,7 @@
-From 169a6fe9914e6480b9981f5cd6a3911e8700e46c Mon Sep 17 00:00:00 2001
+From 2557e2878455ac38e0458a34d8e9fa4c0fcabe7e Mon Sep 17 00:00:00 2001
From: mtk27835 <shurong.wen@mediatek.com>
Date: Wed, 7 Sep 2022 14:01:29 -0700
-Subject: [PATCH 1126/1133] mt76: mt7915: add ibf control vendor cmd
+Subject: [PATCH 1126/1132] mt76: mt7915: add ibf control vendor cmd
Signed-off-by: mtk27835 <shurong.wen@mediatek.com>
---
@@ -10,7 +10,7 @@
2 files changed, 89 insertions(+), 1 deletion(-)
diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index 48d124e0..9cd6e811 100644
+index b26b1cc6..3e5c479e 100644
--- a/mt7915/vendor.c
+++ b/mt7915/vendor.c
@@ -86,6 +86,11 @@ edcca_dump_policy[NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP] = {
@@ -100,7 +100,7 @@
};
diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index d96e5c23..949c8853 100644
+index de3cbe2c..a6309a32 100644
--- a/mt7915/vendor.h
+++ b/mt7915/vendor.h
@@ -12,7 +12,8 @@ enum mtk_nl80211_vendor_subcmds {
diff --git a/recipes-wifi/linux-mt76/files/patches/1127-mt76-mt7915-add-E3-re-bonding-for-low-yield-rate-iss.patch b/recipes-wifi/linux-mt76/files/patches/1127-mt76-mt7915-add-E3-re-bonding-for-low-yield-rate-iss.patch
index b06c540..1669e0c 100644
--- a/recipes-wifi/linux-mt76/files/patches/1127-mt76-mt7915-add-E3-re-bonding-for-low-yield-rate-iss.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1127-mt76-mt7915-add-E3-re-bonding-for-low-yield-rate-iss.patch
@@ -1,7 +1,7 @@
-From 2cd8e8385970f43311305c6849b31cd86cc40f5a Mon Sep 17 00:00:00 2001
+From 8f2a166a0af3f1c6b1f77335685beb56b9d908f3 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Thu, 13 Oct 2022 13:22:05 +0800
-Subject: [PATCH 1127/1133] mt76: mt7915: add E3 re-bonding for low yield rate
+Subject: [PATCH 1127/1132] mt76: mt7915: add E3 re-bonding for low yield rate
issue
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
@@ -64,10 +64,10 @@
if (ret)
return ret;
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index ebe00300..292351fb 100644
+index baf74440..9d934748 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
-@@ -2886,7 +2886,7 @@ int mt7915_mcu_set_eeprom(struct mt7915_dev *dev, bool flash_mode)
+@@ -2888,7 +2888,7 @@ int mt7915_mcu_set_eeprom(struct mt7915_dev *dev, bool flash_mode)
&req, sizeof(req), true);
}
@@ -76,7 +76,7 @@
{
struct mt7915_mcu_eeprom_info req = {
.addr = cpu_to_le32(round_down(offset,
-@@ -2904,8 +2904,15 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)
+@@ -2906,8 +2906,15 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)
return ret;
res = (struct mt7915_mcu_eeprom_info *)skb->data;
diff --git a/recipes-wifi/linux-mt76/files/patches/1128-mt76-mt7915-support-on-off-SW-ACI-through-debugfs.patch b/recipes-wifi/linux-mt76/files/patches/1128-mt76-mt7915-support-on-off-SW-ACI-through-debugfs.patch
index 3fc342b..998228b 100644
--- a/recipes-wifi/linux-mt76/files/patches/1128-mt76-mt7915-support-on-off-SW-ACI-through-debugfs.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1128-mt76-mt7915-support-on-off-SW-ACI-through-debugfs.patch
@@ -1,7 +1,7 @@
-From 7cc147efe8e493d163b9670b8b737fd3bf8d59e0 Mon Sep 17 00:00:00 2001
+From 19ed70a278de504a58054906f9b25b4f5c3cf3d0 Mon Sep 17 00:00:00 2001
From: Evelyn Tsai <evelyn.tsai@mediatek.com>
Date: Fri, 14 Oct 2022 11:15:13 +0800
-Subject: [PATCH 1128/1133] mt76: mt7915: support on off SW ACI through debugfs
+Subject: [PATCH 1128/1132] mt76: mt7915: support on off SW ACI through debugfs
Signed-off-by: Evelyn Tsai <evelyn.tsai@mediatek.com>
Change-Id: I8a9c277c41d1ba76f9737d8af6f42e5e8f00ba64
@@ -11,10 +11,10 @@
2 files changed, 22 insertions(+)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 41859dc3..73a5509a 100644
+index 1ff517f0..1a13cee0 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1206,6 +1206,7 @@ enum {
+@@ -1203,6 +1203,7 @@ enum {
MCU_EXT_CMD_RX_STAT_USER_CTRL = 0xb3,
MCU_EXT_CMD_SET_CFG = 0xb7,
MCU_EXT_CMD_EDCCA = 0xba,
@@ -23,7 +23,7 @@
MCU_EXT_CMD_IPI_HIST_SCAN = 0xc5,
};
diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index 5f34afc7..b99519dd 100644
+index 1f347efe..224d9960 100644
--- a/mt7915/mtk_debugfs.c
+++ b/mt7915/mtk_debugfs.c
@@ -3040,6 +3040,25 @@ static int mt7915_show_eeprom_mode(struct seq_file *s, void *data)
diff --git a/recipes-wifi/linux-mt76/files/patches/1129-mt76-mt7915-add-bf-backoff-limit-table-support.patch b/recipes-wifi/linux-mt76/files/patches/1129-mt76-mt7915-add-bf-backoff-limit-table-support.patch
index c916131..213e390 100644
--- a/recipes-wifi/linux-mt76/files/patches/1129-mt76-mt7915-add-bf-backoff-limit-table-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1129-mt76-mt7915-add-bf-backoff-limit-table-support.patch
@@ -1,7 +1,7 @@
-From cd6e64e5bdea2ee410c1cc8e83f78322bf9f3982 Mon Sep 17 00:00:00 2001
+From 82351f298ec49641998232fb648606996b3c5a37 Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Mon, 5 Dec 2022 18:21:51 +0800
-Subject: [PATCH 1129/1133] mt76: mt7915: add bf backoff limit table support
+Subject: [PATCH 1129/1132] mt76: mt7915: add bf backoff limit table support
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
---
@@ -57,10 +57,10 @@
}
EXPORT_SYMBOL_GPL(mt76_get_rate_power_limits);
diff --git a/mt76.h b/mt76.h
-index 1638ef63..5e24d03c 100644
+index 675c12a4..dbb120cc 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -912,6 +912,14 @@ struct mt76_power_limits {
+@@ -913,6 +913,14 @@ struct mt76_power_limits {
s8 ofdm[8];
s8 mcs[4][10];
s8 ru[7][12];
@@ -188,10 +188,10 @@
mt7915_twt_stats);
debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 292351fb..ff309294 100644
+index 9d934748..5e74ed6e 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
-@@ -3331,7 +3331,8 @@ int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
+@@ -3333,7 +3333,8 @@ int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
int ret;
s8 txpower_sku[MT7915_SKU_RATE_NUM];
@@ -201,7 +201,7 @@
if (ret)
return ret;
-@@ -3373,51 +3374,98 @@ int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
+@@ -3375,51 +3376,98 @@ int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
{
@@ -325,7 +325,7 @@
struct mt7915_dev *dev = phy->dev;
struct {
u8 format_id;
-@@ -3426,10 +3474,9 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
+@@ -3428,10 +3476,9 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
u8 _rsv;
} __packed req = {
.format_id = TX_POWER_LIMIT_INFO,
@@ -337,7 +337,7 @@
struct sk_buff *skb;
int ret, i;
-@@ -3439,9 +3486,15 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
+@@ -3441,9 +3488,15 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
if (ret)
return ret;
@@ -356,7 +356,7 @@
dev_kfree_skb(skb);
-@@ -3483,9 +3536,18 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
+@@ -3485,9 +3538,18 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
.band_idx = phy->mt76->band_idx,
.sku_enable = enable,
};
@@ -376,7 +376,7 @@
MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
sizeof(req), true);
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 16517099..e869a9f5 100644
+index 0aee6948..a07bb9ac 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -447,12 +447,18 @@ enum {
diff --git a/recipes-wifi/linux-mt76/files/patches/1130-mt76-mt7915-amsdu-set-and-get-control.patch b/recipes-wifi/linux-mt76/files/patches/1130-mt76-mt7915-amsdu-set-and-get-control.patch
index 54ca9d2..be8c506 100644
--- a/recipes-wifi/linux-mt76/files/patches/1130-mt76-mt7915-amsdu-set-and-get-control.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1130-mt76-mt7915-amsdu-set-and-get-control.patch
@@ -1,7 +1,7 @@
-From 3991eb6b59ffaf4f30815206fb451bc32e2e2af6 Mon Sep 17 00:00:00 2001
+From dc16e6198fe467ca6db8701ba98f5dbdfecc1211 Mon Sep 17 00:00:00 2001
From: TomLiu <tomml.liu@mediatek.com>
Date: Wed, 14 Dec 2022 00:44:07 -0800
-Subject: [PATCH 1130/1133] mt76: mt7915: amsdu set and get control
+Subject: [PATCH 1130/1132] mt76: mt7915: amsdu set and get control
---
mt7915/mac.c | 10 ++++++++++
@@ -44,7 +44,7 @@
void mt7915_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif);
void mt7915_mcu_set_rfeature_starec(void *data, struct mt7915_dev *dev,
diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index 9cd6e811..766fa595 100644
+index 3e5c479e..2e5f07c3 100644
--- a/mt7915/vendor.c
+++ b/mt7915/vendor.c
@@ -30,10 +30,16 @@ wireless_ctrl_policy[NUM_MTK_VENDOR_ATTRS_WIRELESS_CTRL] = {
@@ -109,7 +109,7 @@
.maxattr = MTK_VENDOR_ATTR_WIRELESS_CTRL_MAX,
},
diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index 949c8853..cbff910b 100644
+index a6309a32..33c75dc9 100644
--- a/mt7915/vendor.h
+++ b/mt7915/vendor.h
@@ -74,6 +74,7 @@ enum mtk_vendor_attr_wireless_ctrl {
diff --git a/recipes-wifi/linux-mt76/files/patches/1131-wifi-mt76-mt7915-add-support-for-he-ldpc-control-fro.patch b/recipes-wifi/linux-mt76/files/patches/1131-wifi-mt76-mt7915-add-support-for-he-ldpc-control-fro.patch
index ef0375b..6da2c9f 100644
--- a/recipes-wifi/linux-mt76/files/patches/1131-wifi-mt76-mt7915-add-support-for-he-ldpc-control-fro.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1131-wifi-mt76-mt7915-add-support-for-he-ldpc-control-fro.patch
@@ -1,7 +1,7 @@
-From 1fb0932ca2be712c94a8f57be5a7069541266201 Mon Sep 17 00:00:00 2001
+From 60271e19265ab37376b428decece440458156aa2 Mon Sep 17 00:00:00 2001
From: MeiChia Chiu <meichia.chiu@mediatek.com>
Date: Thu, 12 Jan 2023 15:15:42 +0800
-Subject: [PATCH 1131/1133] wifi: mt76: mt7915: add support for he ldpc control
+Subject: [PATCH 1131/1132] wifi: mt76: mt7915: add support for he ldpc control
from hostapd
---
@@ -9,7 +9,7 @@
1 file changed, 1 insertion(+)
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index ff309294..2cfad0a3 100644
+index 5e74ed6e..dffd1761 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -1983,6 +1983,7 @@ mt7915_mcu_beacon_check_caps(struct mt7915_phy *phy, struct ieee80211_vif *vif,
diff --git a/recipes-wifi/linux-mt76/files/patches/1132-mt76-mt7915-Add-vendor-command-attribute-for-RTS-BW-.patch b/recipes-wifi/linux-mt76/files/patches/1132-mt76-mt7915-Add-vendor-command-attribute-for-RTS-BW-.patch
index 6a891bf..dea4ae5 100644
--- a/recipes-wifi/linux-mt76/files/patches/1132-mt76-mt7915-Add-vendor-command-attribute-for-RTS-BW-.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1132-mt76-mt7915-Add-vendor-command-attribute-for-RTS-BW-.patch
@@ -1,7 +1,7 @@
-From 610518420411975d6d4cb88c722a8abf645c88f2 Mon Sep 17 00:00:00 2001
+From 81f9124f106441a6ac2f9c43efb9de9f5cc60cb4 Mon Sep 17 00:00:00 2001
From: "himanshu.goyal" <himanshu.goyal@mediatek.com>
Date: Tue, 24 Jan 2023 14:32:08 +0800
-Subject: [PATCH 1132/1133] mt76: mt7915: Add vendor command attribute for RTS
+Subject: [PATCH 1132/1132] mt76: mt7915: Add vendor command attribute for RTS
BW signaling.
Signed-off-by: himanshu.goyal <himanshu.goyal@mediatek.com>
@@ -13,10 +13,10 @@
4 files changed, 20 insertions(+)
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 2cfad0a3..4f1d2fe6 100644
+index dffd1761..e07197d0 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
-@@ -4408,6 +4408,12 @@ int mt7915_mcu_set_cfg(struct mt7915_phy *phy, u8 cfg_info, u8 type)
+@@ -4410,6 +4410,12 @@ int mt7915_mcu_set_cfg(struct mt7915_phy *phy, u8 cfg_info, u8 type)
req.cert.length = cpu_to_le16(tlv_len);
req.cert.cert_program = type;
break;
@@ -30,7 +30,7 @@
tlv_len = sizeof(struct three_wire_cfg);
req.three_wire.tag = cpu_to_le16(cfg_info);
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index e869a9f5..03ee600a 100644
+index a07bb9ac..8cbd37ca 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -867,6 +867,13 @@ struct three_wire_cfg {
@@ -62,7 +62,7 @@
};
diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index 766fa595..7fbf67d6 100644
+index 2e5f07c3..3b7ac098 100644
--- a/mt7915/vendor.c
+++ b/mt7915/vendor.c
@@ -33,6 +33,7 @@ wireless_ctrl_policy[NUM_MTK_VENDOR_ATTRS_WIRELESS_CTRL] = {
@@ -84,7 +84,7 @@
return 0;
diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index cbff910b..41d6ff26 100644
+index 33c75dc9..6001ce4a 100644
--- a/mt7915/vendor.h
+++ b/mt7915/vendor.h
@@ -76,6 +76,7 @@ enum mtk_vendor_attr_wireless_ctrl {
diff --git a/recipes-wifi/linux-mt76/files/patches/1133-mt76-mt7915-Allow-AP-to-change-channel-width-for-40M.patch b/recipes-wifi/linux-mt76/files/patches/1133-mt76-mt7915-Allow-AP-to-change-channel-width-for-40M.patch
deleted file mode 100644
index 5f558ea..0000000
--- a/recipes-wifi/linux-mt76/files/patches/1133-mt76-mt7915-Allow-AP-to-change-channel-width-for-40M.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 48e04e1209ec16bdb258c13a2939ad48f29deec1 Mon Sep 17 00:00:00 2001
-From: "himanshu.goyal" <himanshu.goyal@mediatek.com>
-Date: Mon, 30 Jan 2023 17:47:06 +0800
-Subject: [PATCH 1133/1133] mt76: mt7915: Allow AP to change channel width for
- 40Mhz Intolerant STA
-
-Ref: WFA 11n Test Case: 4.2.41 AP 20/40 MHz Coexistence
-
-Signed-off-by: himanshu.goyal <himanshu.goyal@mediatek.com>
----
- mac80211.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/mac80211.c b/mac80211.c
-index e79568d1..35fd0347 100644
---- a/mac80211.c
-+++ b/mac80211.c
-@@ -430,7 +430,8 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
- SET_IEEE80211_DEV(hw, dev->dev);
- SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
-
-- wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
-+ wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
-+ NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
- wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
- WIPHY_FLAG_SUPPORTS_TDLS |
- WIPHY_FLAG_AP_UAPSD;
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches/1134-mt76-mt7915-add-vendor-cmd-to-get-available-color-bi.patch b/recipes-wifi/linux-mt76/files/patches/1134-mt76-mt7915-add-vendor-cmd-to-get-available-color-bi.patch
new file mode 100644
index 0000000..ec25241
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches/1134-mt76-mt7915-add-vendor-cmd-to-get-available-color-bi.patch
@@ -0,0 +1,106 @@
+From 1ecc90eee785504c9671985cabd6631ff1640f64 Mon Sep 17 00:00:00 2001
+From: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
+Date: Thu, 26 Jan 2023 08:50:47 +0800
+Subject: [PATCH] mt76: mt7915: add vendor cmd to get available color bitmap
+
+Add a vendor cmd to notify user space available color bitmap.
+The OBSS BSS color bitmap is maintained in mac80211, so mt76 will make use of that.
+
+Signed-off-by: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
+---
+ mt7915/vendor.c | 37 +++++++++++++++++++++++++++++++++++++
+ mt7915/vendor.h | 11 +++++++++++
+ 2 files changed, 48 insertions(+)
+
+diff --git a/mt7915/vendor.c b/mt7915/vendor.c
+index a1f526c..5cbe856 100644
+--- a/mt7915/vendor.c
++++ b/mt7915/vendor.c
+@@ -97,6 +97,11 @@ ibf_ctrl_policy[NUM_MTK_VENDOR_ATTRS_IBF_CTRL] = {
+ [MTK_VENDOR_ATTR_IBF_CTRL_ENABLE] = { .type = NLA_U8 },
+ };
+
++static struct nla_policy
++bss_color_ctrl_policy[NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL] = {
++ [MTK_VENDOR_ATTR_AVAL_BSS_COLOR_BMP] = { .type = NLA_U64 },
++};
++
+ struct csi_null_tone {
+ u8 start;
+ u8 end;
+@@ -1272,6 +1277,27 @@ mt7915_vendor_ibf_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
+ return 1;
+ }
+
++static int
++mt7915_vendor_bss_color_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
++ struct sk_buff *skb, const void *data, int data_len,
++ unsigned long *storage)
++{
++ struct ieee80211_vif *vif = wdev_to_ieee80211_vif(wdev);
++ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
++ int len = 0;
++
++ if (*storage == 1)
++ return -ENOENT;
++ *storage = 1;
++
++ if (nla_put_u64_64bit(skb,
++ MTK_VENDOR_ATTR_AVAL_BSS_COLOR_BMP,
++ ~bss_conf->he_bss_color.used_color_bitmap, NL80211_ATTR_PAD))
++ return -ENOMEM;
++ len += 1;
++
++ return len;
++}
+
+ static const struct wiphy_vendor_command mt7915_vendor_commands[] = {
+ {
+@@ -1378,6 +1404,17 @@ static const struct wiphy_vendor_command mt7915_vendor_commands[] = {
+ .dumpit = mt7915_vendor_ibf_ctrl_dump,
+ .policy = ibf_ctrl_policy,
+ .maxattr = MTK_VENDOR_ATTR_IBF_CTRL_MAX,
++ },
++ {
++ .info = {
++ .vendor_id = MTK_NL80211_VENDOR_ID,
++ .subcmd = MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL,
++ },
++ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
++ WIPHY_VENDOR_CMD_NEED_RUNNING,
++ .dumpit = mt7915_vendor_bss_color_ctrl_dump,
++ .policy = bss_color_ctrl_policy,
++ .maxattr = MTK_VENDOR_ATTR_BSS_COLOR_CTRL_MAX,
+ }
+ };
+
+diff --git a/mt7915/vendor.h b/mt7915/vendor.h
+index cbff910..dda1447 100644
+--- a/mt7915/vendor.h
++++ b/mt7915/vendor.h
+@@ -14,6 +14,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,
+ };
+
+
+@@ -257,4 +258,14 @@ enum mtk_vendor_attr_ibf_dump {
+ NUM_MTK_VENDOR_ATTRS_IBF_DUMP - 1
+ };
+
++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
++};
+ #endif
+--
+2.39.0
+
diff --git a/recipes-wifi/linux-mt76/files/patches/3001-mt76-mt7915-wed-add-wed-tx-support.patch b/recipes-wifi/linux-mt76/files/patches/3001-mt76-mt7915-wed-add-wed-tx-support.patch
index 500ec0f..deab403 100644
--- a/recipes-wifi/linux-mt76/files/patches/3001-mt76-mt7915-wed-add-wed-tx-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches/3001-mt76-mt7915-wed-add-wed-tx-support.patch
@@ -1,7 +1,7 @@
-From 783c715b2271209d23b965517d97e5a834fcfa76 Mon Sep 17 00:00:00 2001
+From af605bd8d821cc9cd9dd4f3928c4632113574dc4 Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Fri, 25 Nov 2022 10:38:53 +0800
-Subject: [PATCH 3001/3015] mt76: mt7915: wed: add wed tx support
+Subject: [PATCH 3001/3013] mt76: mt7915: wed: add wed tx support
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
---
@@ -86,7 +86,7 @@
ctx->dev = NULL;
diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 95ded131..6ebb969f 100644
+index 568b5feb..890af388 100644
--- a/mt7915/mmio.c
+++ b/mt7915/mmio.c
@@ -13,7 +13,7 @@
diff --git a/recipes-wifi/linux-mt76/files/patches/3002-mt76-mt7915-wed-add-wds-support-when-wed-is-enabled.patch b/recipes-wifi/linux-mt76/files/patches/3002-mt76-mt7915-wed-add-wds-support-when-wed-is-enabled.patch
index 46fbf0c..46a68b5 100644
--- a/recipes-wifi/linux-mt76/files/patches/3002-mt76-mt7915-wed-add-wds-support-when-wed-is-enabled.patch
+++ b/recipes-wifi/linux-mt76/files/patches/3002-mt76-mt7915-wed-add-wds-support-when-wed-is-enabled.patch
@@ -1,21 +1,21 @@
-From 443b9ce1fa3d69fbfdbb6051c4ed46029556083d Mon Sep 17 00:00:00 2001
+From e7caf441138764cd701c00bf8c3bd6b7747ed323 Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Tue, 13 Dec 2022 17:51:26 +0800
-Subject: [PATCH 3002/3015] mt76: mt7915: wed: add wds support when wed is
+Subject: [PATCH 3002/3013] mt76: mt7915: wed: add wds support when wed is
enabled
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
---
mt76.h | 6 ++++++
mt7915/main.c | 22 ++++++++++++++++++++--
- mt7915/mcu.c | 13 +++++++++++--
+ mt7915/mcu.c | 16 ++++++++++++----
mt7915/mcu.h | 1 +
util.c | 40 +++++++++++++++++++++++++++++++++++++---
util.h | 7 ++++++-
- 6 files changed, 81 insertions(+), 8 deletions(-)
+ 6 files changed, 82 insertions(+), 10 deletions(-)
diff --git a/mt76.h b/mt76.h
-index 5e24d03c..cb34391a 100644
+index dbb120cc..d8438953 100644
--- a/mt76.h
+++ b/mt76.h
@@ -60,6 +60,12 @@ enum mt76_wed_type {
@@ -81,17 +81,20 @@
ctx->dev = NULL;
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 4f1d2fe6..d046ce0f 100644
+index e07197d0..6b90f338 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
-@@ -2416,8 +2416,17 @@ int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
+@@ -2416,10 +2416,18 @@ int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
if (ret)
return ret;
-- if (mtk_wed_device_active(&dev->mt76.mmio.wed) && is_mt7915(&dev->mt76))
+- if ((mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+- is_mt7915(&dev->mt76)) ||
+- !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
- mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
-+ if (is_mt7915(&dev->mt76))
++ if (is_mt7915(&dev->mt76) ||
++ !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
+ ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY),
+ 0, 0, 0);
+ else
@@ -105,7 +108,7 @@
ret = mt7915_mcu_set_mwds(dev, 1);
if (ret)
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 03ee600a..24d0efd3 100644
+index 8cbd37ca..0f845075 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -284,6 +284,7 @@ enum {
diff --git a/recipes-wifi/linux-mt76/files/patches/3003-mt76-mt7915-wed-add-fill-receive-path-to-report-wed-.patch b/recipes-wifi/linux-mt76/files/patches/3003-mt76-mt7915-wed-add-fill-receive-path-to-report-wed-.patch
index 528c44c..5d3affc 100644
--- a/recipes-wifi/linux-mt76/files/patches/3003-mt76-mt7915-wed-add-fill-receive-path-to-report-wed-.patch
+++ b/recipes-wifi/linux-mt76/files/patches/3003-mt76-mt7915-wed-add-fill-receive-path-to-report-wed-.patch
@@ -1,7 +1,7 @@
-From b52fb2adf7b44ed323983b10721612347b86b569 Mon Sep 17 00:00:00 2001
+From 3cdc91efeb0dcb344b79c832373a62c09c4ceee9 Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Thu, 19 May 2022 13:44:42 +0800
-Subject: [PATCH 3003/3015] mt76: mt7915: wed: add fill receive path to report
+Subject: [PATCH 3003/3013] mt76: mt7915: wed: add fill receive path to report
wed idx
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
diff --git a/recipes-wifi/linux-mt76/files/patches/3004-mt76-mt7915-wed-find-rx-token-by-physical-address.patch b/recipes-wifi/linux-mt76/files/patches/3004-mt76-mt7915-wed-find-rx-token-by-physical-address.patch
index 21367e9..a958a8f 100644
--- a/recipes-wifi/linux-mt76/files/patches/3004-mt76-mt7915-wed-find-rx-token-by-physical-address.patch
+++ b/recipes-wifi/linux-mt76/files/patches/3004-mt76-mt7915-wed-find-rx-token-by-physical-address.patch
@@ -1,7 +1,7 @@
-From fc10309ea47b4d34ace30e6f4e7ff0c0ffa71db2 Mon Sep 17 00:00:00 2001
+From b454d9a320895e76b3211a3c176dbf3ab24c1a8a Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Fri, 25 Nov 2022 14:32:35 +0800
-Subject: [PATCH 3004/3015] mt76: mt7915: wed: find rx token by physical
+Subject: [PATCH 3004/3013] mt76: mt7915: wed: find rx token by physical
address
The token id in RxDMAD may be incorrect when it is not the last frame due to
@@ -9,21 +9,19 @@
Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
---
- dma.c | 27 ++++++++++++++++++++++++++-
- 1 file changed, 26 insertions(+), 1 deletion(-)
+ dma.c | 25 ++++++++++++++++++++++++-
+ 1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/dma.c b/dma.c
-index a6bb3730..b58579c5 100644
+index fe65e0f3..14553b24 100644
--- a/dma.c
+++ b/dma.c
-@@ -402,10 +402,35 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
- *info = le32_to_cpu(desc->info);
+@@ -403,9 +403,32 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
if (mt76_queue_is_wed_rx(q)) {
-+ __le32 buf1;
+ u32 buf1 = le32_to_cpu(desc->buf1);
+ u32 id, find = 0;
- u32 token = FIELD_GET(MT_DMA_CTL_TOKEN,
- le32_to_cpu(desc->buf1));
+ u32 token = FIELD_GET(MT_DMA_CTL_TOKEN, buf1);
- struct mt76_txwi_cache *t = mt76_rx_token_release(dev, token);
+ struct mt76_txwi_cache *t;
+
@@ -36,10 +34,9 @@
+ token = id;
+
+ /* Write correct id back to DMA*/
-+ buf1 = desc->buf1;
-+ buf1 = le32_replace_bits(buf1, id,
-+ MT_DMA_CTL_TOKEN);
-+ WRITE_ONCE(desc->buf1, buf1);
++ u32p_replace_bits(&buf1, id,
++ MT_DMA_CTL_TOKEN);
++ WRITE_ONCE(desc->buf1, cpu_to_le32(buf1));
+ break;
+ }
+ }
diff --git a/recipes-wifi/linux-mt76/files/patches/3006-mt76-mt7915-wed-HW-ATF-support-for-mt7986.patch b/recipes-wifi/linux-mt76/files/patches/3005-mt76-mt7915-wed-HW-ATF-support-for-mt7986.patch
similarity index 98%
rename from recipes-wifi/linux-mt76/files/patches/3006-mt76-mt7915-wed-HW-ATF-support-for-mt7986.patch
rename to recipes-wifi/linux-mt76/files/patches/3005-mt76-mt7915-wed-HW-ATF-support-for-mt7986.patch
index c22106c..c163906 100644
--- a/recipes-wifi/linux-mt76/files/patches/3006-mt76-mt7915-wed-HW-ATF-support-for-mt7986.patch
+++ b/recipes-wifi/linux-mt76/files/patches/3005-mt76-mt7915-wed-HW-ATF-support-for-mt7986.patch
@@ -1,7 +1,7 @@
-From b2b4b6a891b1c9e4232addc929a0dac8cd548a06 Mon Sep 17 00:00:00 2001
+From c040b9a6ac177c22283388bff0b7a8c72271b45c Mon Sep 17 00:00:00 2001
From: Lian Chen <lian.chen@mediatek.com>
Date: Mon, 7 Nov 2022 14:47:44 +0800
-Subject: [PATCH 3006/3010] mt76: mt7915: wed: HW ATF support for mt7986
+Subject: [PATCH 3005/3013] mt76: mt7915: wed: HW ATF support for mt7986
Signed-off-by: Lian Chen <lian.chen@mediatek.com>
---
@@ -15,10 +15,10 @@
7 files changed, 826 insertions(+), 1 deletion(-)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 73a5509a..130a8d25 100644
+index 1a13cee0..ad6f845b 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1164,6 +1164,7 @@ enum {
+@@ -1161,6 +1161,7 @@ enum {
MCU_EXT_CMD_THERMAL_CTRL = 0x2c,
MCU_EXT_CMD_WTBL_UPDATE = 0x32,
MCU_EXT_CMD_SET_DRR_CTRL = 0x36,
@@ -26,7 +26,7 @@
MCU_EXT_CMD_SET_RDD_CTRL = 0x3a,
MCU_EXT_CMD_ATE_CTRL = 0x3d,
MCU_EXT_CMD_PROTECT_CTRL = 0x3e,
-@@ -1173,6 +1174,7 @@ enum {
+@@ -1170,6 +1171,7 @@ enum {
MCU_EXT_CMD_MUAR_UPDATE = 0x48,
MCU_EXT_CMD_BCN_OFFLOAD = 0x49,
MCU_EXT_CMD_RX_AIRTIME_CTRL = 0x4a,
@@ -465,10 +465,10 @@
if (!dev->dbdc_support || phy->mt76->band_idx) {
debugfs_create_u32("dfs_hw_pattern", 0400, dir,
diff --git a/mt7915/init.c b/mt7915/init.c
-index 19447ad1..92977b98 100644
+index f40d09c3..27395316 100644
--- a/mt7915/init.c
+++ b/mt7915/init.c
-@@ -559,10 +559,46 @@ mt7915_init_led_mux(struct mt7915_dev *dev)
+@@ -571,10 +571,46 @@ mt7915_init_led_mux(struct mt7915_dev *dev)
}
}
@@ -515,7 +515,7 @@
/* config pse qid6 wfdma port selection */
if (!is_mt7915(&dev->mt76) && dev->hif2)
-@@ -584,6 +620,9 @@ void mt7915_mac_init(struct mt7915_dev *dev)
+@@ -596,6 +632,9 @@ void mt7915_mac_init(struct mt7915_dev *dev)
mt7915_mac_init_band(dev, i);
mt7915_init_led_mux(dev);
@@ -526,7 +526,7 @@
int mt7915_txbf_init(struct mt7915_dev *dev)
diff --git a/mt7915/main.c b/mt7915/main.c
-index 9a5dac91..a9980e70 100644
+index 7d25a93f..c549a183 100644
--- a/mt7915/main.c
+++ b/mt7915/main.c
@@ -209,6 +209,7 @@ int mt7915_init_vif(struct mt7915_phy *phy, struct ieee80211_vif *vif, bool bf_e
@@ -573,10 +573,10 @@
}
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 64789b80..e3b7d824 100644
+index 6b90f338..da10895c 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
-@@ -3580,6 +3580,171 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
+@@ -3581,6 +3581,171 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
&req, sizeof(req), false);
}
@@ -749,7 +749,7 @@
{
#define MT_BF_PROCESSING 4
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index eb24b45f..a1ef8359 100644
+index c14d13ae..0fbc1047 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
@@ -127,6 +127,58 @@ struct mt7915_twt_flow {
@@ -856,7 +856,7 @@
int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy);
int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len,
diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index 576995dc..5e64fe91 100644
+index 224d9960..2dc4cb87 100644
--- a/mt7915/mtk_debugfs.c
+++ b/mt7915/mtk_debugfs.c
@@ -1368,7 +1368,6 @@ static EMPTY_QUEUE_INFO_T ple_txcmd_queue_empty_info[] = {
diff --git a/recipes-wifi/linux-mt76/files/patches/3005-mt76-mt7915-wed-drop-scatter-and-gather-frame.patch b/recipes-wifi/linux-mt76/files/patches/3005-mt76-mt7915-wed-drop-scatter-and-gather-frame.patch
deleted file mode 100644
index 4f5d2c6..0000000
--- a/recipes-wifi/linux-mt76/files/patches/3005-mt76-mt7915-wed-drop-scatter-and-gather-frame.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From d99756a5e6b4b3d1d520aba763fddeadff53a529 Mon Sep 17 00:00:00 2001
-From: Peter Chiu <chui-hao.chiu@mediatek.com>
-Date: Fri, 25 Nov 2022 14:37:58 +0800
-Subject: [PATCH 3005/3015] mt76: mt7915: wed: drop scatter and gather frame
-
-The scatter and gather frame may be incorrect because WED and WO may
-send frames to host driver interleaved.
-
-Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
----
- dma.c | 9 +++++++++
- dma.h | 1 +
- mt76.h | 1 +
- 3 files changed, 11 insertions(+)
-
-diff --git a/dma.c b/dma.c
-index b58579c5..86b0bf84 100644
---- a/dma.c
-+++ b/dma.c
-@@ -449,6 +449,15 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
-
- *drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A |
- MT_DMA_CTL_DROP));
-+
-+ if (*more || (q->flags & MT_QFLAG_WED_FRAG)) {
-+ *drop = true;
-+
-+ if (!(*more) && FIELD_GET(MT_DMA_CTL_WO, desc->buf1))
-+ q->flags &= ~MT_QFLAG_WED_FRAG;
-+ else
-+ q->flags |= MT_QFLAG_WED_FRAG;
-+ }
- }
- } else {
- buf = e->buf;
-diff --git a/dma.h b/dma.h
-index 4b9bc7f4..ce8ac426 100644
---- a/dma.h
-+++ b/dma.h
-@@ -19,6 +19,7 @@
- #define MT_DMA_CTL_TO_HOST_A BIT(12)
- #define MT_DMA_CTL_DROP BIT(14)
- #define MT_DMA_CTL_TOKEN GENMASK(31, 16)
-+#define MT_DMA_CTL_WO BIT(8)
-
- #define MT_DMA_PPE_CPU_REASON GENMASK(15, 11)
- #define MT_DMA_PPE_ENTRY GENMASK(30, 16)
-diff --git a/mt76.h b/mt76.h
-index cb34391a..982d0bbf 100644
---- a/mt76.h
-+++ b/mt76.h
-@@ -30,6 +30,7 @@
- #define MT_QFLAG_WED_RING GENMASK(1, 0)
- #define MT_QFLAG_WED_TYPE GENMASK(3, 2)
- #define MT_QFLAG_WED BIT(4)
-+#define MT_QFLAG_WED_FRAG BIT(5)
-
- #define __MT_WED_Q(_type, _n) (MT_QFLAG_WED | \
- FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches/3008-mt76-mt7915-wed-add-rxwi-for-further-in-chip-rro.patch b/recipes-wifi/linux-mt76/files/patches/3006-mt76-mt7915-wed-add-rxwi-for-further-in-chip-rro.patch
similarity index 93%
rename from recipes-wifi/linux-mt76/files/patches/3008-mt76-mt7915-wed-add-rxwi-for-further-in-chip-rro.patch
rename to recipes-wifi/linux-mt76/files/patches/3006-mt76-mt7915-wed-add-rxwi-for-further-in-chip-rro.patch
index 78e257d..4e22353 100644
--- a/recipes-wifi/linux-mt76/files/patches/3008-mt76-mt7915-wed-add-rxwi-for-further-in-chip-rro.patch
+++ b/recipes-wifi/linux-mt76/files/patches/3006-mt76-mt7915-wed-add-rxwi-for-further-in-chip-rro.patch
@@ -1,7 +1,7 @@
-From 8d7faa4d207c13487196d09de0c1c452703f1b84 Mon Sep 17 00:00:00 2001
+From 72dda83ffb5d48393da817757f537770aeca4e40 Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Fri, 6 Jan 2023 18:18:50 +0800
-Subject: [PATCH 3008/3015] mt76: mt7915: wed: add rxwi for further in chip rro
+Subject: [PATCH 3006/3013] mt76: mt7915: wed: add rxwi for further in chip rro
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
---
@@ -15,7 +15,7 @@
7 files changed, 86 insertions(+), 79 deletions(-)
diff --git a/dma.c b/dma.c
-index 86b0bf84..76af6506 100644
+index 14553b24..d1a1dae4 100644
--- a/dma.c
+++ b/dma.c
@@ -59,17 +59,17 @@ mt76_alloc_txwi(struct mt76_dev *dev)
@@ -180,10 +180,10 @@
q->entry[idx].skb = skb;
q->entry[idx].wcid = 0xffff;
-@@ -406,13 +407,13 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
+@@ -405,13 +406,13 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
+ u32 buf1 = le32_to_cpu(desc->buf1);
u32 id, find = 0;
- u32 token = FIELD_GET(MT_DMA_CTL_TOKEN,
- le32_to_cpu(desc->buf1));
+ u32 token = FIELD_GET(MT_DMA_CTL_TOKEN, buf1);
- struct mt76_txwi_cache *t;
+ struct mt76_rxwi_cache *r;
@@ -197,7 +197,7 @@
find = 1;
token = id;
-@@ -430,19 +431,19 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
+@@ -428,19 +429,19 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
return NULL;
}
@@ -224,7 +224,7 @@
if (drop) {
u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl));
-@@ -510,7 +511,7 @@ mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q,
+@@ -501,7 +502,7 @@ mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q,
buf.len = skb->len;
spin_lock_bh(&q->lock);
@@ -233,7 +233,7 @@
mt76_dma_kick_queue(dev, q);
spin_unlock_bh(&q->lock);
-@@ -587,7 +588,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
+@@ -578,7 +579,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
goto unmap;
return mt76_dma_add_buf(dev, q, tx_info.buf, tx_info.nbuf,
@@ -243,10 +243,10 @@
unmap:
for (n--; n > 0; n--)
diff --git a/mac80211.c b/mac80211.c
-index 35fd0347..95861d47 100644
+index e2122c78..4655f814 100644
--- a/mac80211.c
+++ b/mac80211.c
-@@ -640,7 +640,6 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
+@@ -644,7 +644,6 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
spin_lock_init(&dev->lock);
spin_lock_init(&dev->cc_lock);
spin_lock_init(&dev->status_lock);
@@ -254,7 +254,7 @@
mutex_init(&dev->mutex);
init_waitqueue_head(&dev->tx_wait);
-@@ -671,6 +670,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
+@@ -675,6 +674,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
INIT_LIST_HEAD(&dev->txwi_cache);
INIT_LIST_HEAD(&dev->rxwi_cache);
dev->token_size = dev->drv->token_size;
@@ -263,10 +263,10 @@
for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
skb_queue_head_init(&dev->rx_skb[i]);
diff --git a/mt76.h b/mt76.h
-index 982d0bbf..a36a978b 100644
+index d8438953..7919cda8 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -166,6 +166,7 @@ struct mt76_queue_entry {
+@@ -165,6 +165,7 @@ struct mt76_queue_entry {
};
union {
struct mt76_txwi_cache *txwi;
@@ -274,7 +274,7 @@
struct urb *urb;
int buf_sz;
};
-@@ -357,10 +358,15 @@ struct mt76_txwi_cache {
+@@ -356,10 +357,15 @@ struct mt76_txwi_cache {
struct list_head list;
dma_addr_t dma_addr;
@@ -334,10 +334,10 @@
static inline void mt76_put_page_pool_buf(void *buf, bool allow_direct)
{
diff --git a/mt7915/dma.c b/mt7915/dma.c
-index 52fabde0..4dd321ee 100644
+index 43a5456d..6d9b2d15 100644
--- a/mt7915/dma.c
+++ b/mt7915/dma.c
-@@ -491,7 +491,6 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
+@@ -493,7 +493,6 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
mtk_wed_get_rx_capa(&mdev->mmio.wed)) {
dev->mt76.q_rx[MT_RXQ_MAIN].flags =
MT_WED_Q_RX(MT7915_RXQ_BAND0);
@@ -345,7 +345,7 @@
}
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
-@@ -528,7 +527,6 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
+@@ -530,7 +529,6 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
mtk_wed_get_rx_capa(&mdev->mmio.wed)) {
dev->mt76.q_rx[MT_RXQ_BAND1].flags =
MT_WED_Q_RX(MT7915_RXQ_BAND1);
diff --git a/recipes-wifi/linux-mt76/files/patches/3009-mt76-mt7915-add-mt7915_net_setup_tc-to-support-wifi2.patch b/recipes-wifi/linux-mt76/files/patches/3007-mt76-mt7915-add-mt7915_net_setup_tc-to-support-wifi2.patch
similarity index 90%
rename from recipes-wifi/linux-mt76/files/patches/3009-mt76-mt7915-add-mt7915_net_setup_tc-to-support-wifi2.patch
rename to recipes-wifi/linux-mt76/files/patches/3007-mt76-mt7915-add-mt7915_net_setup_tc-to-support-wifi2.patch
index d5bbee7..bce65e6 100644
--- a/recipes-wifi/linux-mt76/files/patches/3009-mt76-mt7915-add-mt7915_net_setup_tc-to-support-wifi2.patch
+++ b/recipes-wifi/linux-mt76/files/patches/3007-mt76-mt7915-add-mt7915_net_setup_tc-to-support-wifi2.patch
@@ -1,7 +1,7 @@
-From b3a12a2a257355951c1f1a5902eb793a982bc23c Mon Sep 17 00:00:00 2001
+From 38e99f5b8641c3b1c054244d3c74229a9c0a470e Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Tue, 27 Dec 2022 09:45:14 +0800
-Subject: [PATCH 3009/3015] mt76: mt7915: add mt7915_net_setup_tc to support
+Subject: [PATCH 3007/3013] mt76: mt7915: add mt7915_net_setup_tc to support
wifi2wifi offload
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
diff --git a/recipes-wifi/linux-mt76/files/patches/3007-mt76-mt7915-wed-add-mt7916-2-pcie-support-when-wed-o.patch b/recipes-wifi/linux-mt76/files/patches/3007-mt76-mt7915-wed-add-mt7916-2-pcie-support-when-wed-o.patch
deleted file mode 100644
index 4917bae..0000000
--- a/recipes-wifi/linux-mt76/files/patches/3007-mt76-mt7915-wed-add-mt7916-2-pcie-support-when-wed-o.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From 76a6c0fd812fa4682abca05d94594f063808d815 Mon Sep 17 00:00:00 2001
-From: Sujuan Chen <sujuan.chen@mediatek.com>
-Date: Fri, 2 Dec 2022 17:17:06 +0800
-Subject: [PATCH 3007/3015] mt76: mt7915: wed: add mt7916 2 pcie support when
- wed on
-
-It should use bit 23 in interrupt mask for wfdma band1 data
-for 2 pcie mt7916, and use bit 19 for band1 data for 1 pcie.
-
-Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
----
- mt7915/dma.c | 8 ++++++--
- mt7915/mcu.c | 3 ++-
- mt7915/mmio.c | 10 +++++-----
- 3 files changed, 13 insertions(+), 8 deletions(-)
-
-diff --git a/mt7915/dma.c b/mt7915/dma.c
-index abe17dac..52fabde0 100644
---- a/mt7915/dma.c
-+++ b/mt7915/dma.c
-@@ -87,8 +87,12 @@ static void mt7915_dma_config(struct mt7915_dev *dev)
- MT7916_RXQ_BAND0);
- RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_WED_RX_DONE_WA_MT7916,
- MT7916_RXQ_MCU_WA);
-- RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_WED_RX_DONE_BAND1_MT7916,
-- MT7916_RXQ_BAND1);
-+ if (dev->hif2)
-+ RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1_MT7916,
-+ MT7916_RXQ_BAND1);
-+ else
-+ RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_WED_RX_DONE_BAND1_MT7916,
-+ MT7916_RXQ_BAND1);
- RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_WED_RX_DONE_WA_MAIN_MT7916,
- MT7916_RXQ_MCU_WA_MAIN);
- TXQ_CONFIG(0, WFDMA0, MT_INT_WED_TX_DONE_BAND0,
-diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 134dc5cb..7301ec1d 100644
---- a/mt7915/mcu.c
-+++ b/mt7915/mcu.c
-@@ -2417,7 +2417,8 @@ int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
- return ret;
-
- if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
-- if (is_mt7915(&dev->mt76))
-+ if (is_mt7915(&dev->mt76) ||
-+ !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
- ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY),
- 0, 0, 0);
- else
-diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 6ebb969f..890af388 100644
---- a/mt7915/mmio.c
-+++ b/mt7915/mmio.c
-@@ -996,13 +996,13 @@ irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
- struct mt7915_dev *dev = dev_instance;
- struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
-
-- if (mtk_wed_device_active(wed)) {
-+ if (mtk_wed_device_active(wed))
- mtk_wed_device_irq_set_mask(wed, 0);
-- } else {
-+ else
- mt76_wr(dev, MT_INT_MASK_CSR, 0);
-- if (dev->hif2)
-- mt76_wr(dev, MT_INT1_MASK_CSR, 0);
-- }
-+
-+ if (dev->hif2)
-+ mt76_wr(dev, MT_INT1_MASK_CSR, 0);
-
- if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
- return IRQ_NONE;
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches/3010-wifi-mt76-mt7915-add-wa-command-to-get-tx-msdu-count.patch b/recipes-wifi/linux-mt76/files/patches/3008-wifi-mt76-mt7915-add-wa-command-to-get-tx-msdu-count.patch
similarity index 94%
rename from recipes-wifi/linux-mt76/files/patches/3010-wifi-mt76-mt7915-add-wa-command-to-get-tx-msdu-count.patch
rename to recipes-wifi/linux-mt76/files/patches/3008-wifi-mt76-mt7915-add-wa-command-to-get-tx-msdu-count.patch
index 85d97b1..9f30456 100644
--- a/recipes-wifi/linux-mt76/files/patches/3010-wifi-mt76-mt7915-add-wa-command-to-get-tx-msdu-count.patch
+++ b/recipes-wifi/linux-mt76/files/patches/3008-wifi-mt76-mt7915-add-wa-command-to-get-tx-msdu-count.patch
@@ -1,7 +1,7 @@
-From dbd25fa4a361f77c713e2f95e11c3806c490877e Mon Sep 17 00:00:00 2001
+From 101ab7022c500ad4adacb5faf90bef25d897c70a Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Wed, 18 Jan 2023 16:37:22 +0800
-Subject: [PATCH 3010/3015] wifi: mt76: mt7915: add wa command to get tx msdu
+Subject: [PATCH 3008/3013] wifi: mt76: mt7915: add wa command to get tx msdu
count
---
@@ -16,10 +16,10 @@
8 files changed, 78 insertions(+), 11 deletions(-)
diff --git a/mt76.h b/mt76.h
-index a36a978b..0d1f3cbf 100644
+index 7919cda8..08945d66 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -285,7 +285,7 @@ struct mt76_sta_stats {
+@@ -284,7 +284,7 @@ struct mt76_sta_stats {
u64 tx_mcs[16]; /* mcs idx */
u64 tx_bytes;
/* WED TX */
@@ -41,7 +41,7 @@
/* RXD DW1 */
diff --git a/mt76_connac_mac.c b/mt76_connac_mac.c
-index aed4ee95..2643f5aa 100644
+index 8d316d3a..1816bcbc 100644
--- a/mt76_connac_mac.c
+++ b/mt76_connac_mac.c
@@ -491,7 +491,9 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
@@ -68,10 +68,10 @@
le32_get_bits(txs_data[6], MT_TXS6_MPDU_FAIL_CNT);
stats->tx_retries +=
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 130a8d25..34df625a 100644
+index ad6f845b..7afd9d09 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1003,6 +1003,7 @@ enum {
+@@ -1000,6 +1000,7 @@ enum {
MCU_EXT_EVENT_BF_STATUS_READ = 0x35,
MCU_EXT_EVENT_RDD_REPORT = 0x3a,
MCU_EXT_EVENT_CSA_NOTIFY = 0x4f,
@@ -106,7 +106,7 @@
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL);
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 7301ec1d..3e0c3ab1 100644
+index da10895c..076480ba 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -168,7 +168,9 @@ mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
@@ -192,7 +192,7 @@
struct cfg80211_he_bss_color *he_bss_color)
{
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 24d0efd3..5f6c7c80 100644
+index 0f845075..d761fa59 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -292,6 +292,17 @@ enum {
diff --git a/recipes-wifi/linux-mt76/files/patches/3011-wifi-mt76-get-tx-count-and-tx-failed-from-mcu-comman.patch b/recipes-wifi/linux-mt76/files/patches/3009-wifi-mt76-get-tx-count-and-tx-failed-from-mcu-comman.patch
similarity index 94%
rename from recipes-wifi/linux-mt76/files/patches/3011-wifi-mt76-get-tx-count-and-tx-failed-from-mcu-comman.patch
rename to recipes-wifi/linux-mt76/files/patches/3009-wifi-mt76-get-tx-count-and-tx-failed-from-mcu-comman.patch
index 617ee6c..f1d5c88 100644
--- a/recipes-wifi/linux-mt76/files/patches/3011-wifi-mt76-get-tx-count-and-tx-failed-from-mcu-comman.patch
+++ b/recipes-wifi/linux-mt76/files/patches/3009-wifi-mt76-get-tx-count-and-tx-failed-from-mcu-comman.patch
@@ -1,7 +1,7 @@
-From 2a8cadb17c7c31806a41c5af0e97d76aed47fd94 Mon Sep 17 00:00:00 2001
+From 8fa8a22a16c04d8f18e27af2c02b960f0c02c91b Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Wed, 11 Jan 2023 10:56:27 +0800
-Subject: [PATCH 3011/3015] wifi: mt76: get tx count and tx failed from mcu
+Subject: [PATCH 3009/3013] wifi: mt76: get tx count and tx failed from mcu
command
---
@@ -15,10 +15,10 @@
7 files changed, 138 insertions(+), 5 deletions(-)
diff --git a/mt76.h b/mt76.h
-index 0d1f3cbf..22c6531a 100644
+index 08945d66..bc0c9ae7 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -286,6 +286,7 @@ struct mt76_sta_stats {
+@@ -285,6 +285,7 @@ struct mt76_sta_stats {
u64 tx_bytes;
/* WED TX */
u32 tx_packets; /* unit: MSDU */
@@ -27,7 +27,7 @@
u32 tx_failed;
/* WED RX */
diff --git a/mt76_connac_mac.c b/mt76_connac_mac.c
-index 2643f5aa..05ba5f26 100644
+index 1816bcbc..abcb9a27 100644
--- a/mt76_connac_mac.c
+++ b/mt76_connac_mac.c
@@ -579,8 +579,6 @@ bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid,
@@ -38,12 +38,12 @@
- le32_get_bits(txs_data[6], MT_TXS6_MPDU_FAIL_CNT);
stats->tx_retries +=
le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_CNT);
- }
+
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 34df625a..747ae7e9 100644
+index 7afd9d09..287cffcc 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1163,6 +1163,7 @@ enum {
+@@ -1160,6 +1160,7 @@ enum {
MCU_EXT_CMD_EDCA_UPDATE = 0x27,
MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A,
MCU_EXT_CMD_THERMAL_CTRL = 0x2c,
@@ -78,7 +78,7 @@
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL);
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 3e0c3ab1..16a82e92 100644
+index 076480ba..e1c08178 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -4137,6 +4137,114 @@ out:
@@ -197,7 +197,7 @@
struct cfg80211_he_bss_color *he_bss_color)
{
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 5f6c7c80..7b611fb7 100644
+index d761fa59..41d5ea19 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -1018,6 +1018,28 @@ struct mt7915_muru {
diff --git a/recipes-wifi/linux-mt76/files/patches/3012-wifi-mt76-mt7915-enable-PPDU-TxS-to-host-when-wed-en.patch b/recipes-wifi/linux-mt76/files/patches/3010-wifi-mt76-mt7915-enable-PPDU-TxS-to-host-when-wed-en.patch
similarity index 93%
rename from recipes-wifi/linux-mt76/files/patches/3012-wifi-mt76-mt7915-enable-PPDU-TxS-to-host-when-wed-en.patch
rename to recipes-wifi/linux-mt76/files/patches/3010-wifi-mt76-mt7915-enable-PPDU-TxS-to-host-when-wed-en.patch
index 4dcba32..d7af854 100644
--- a/recipes-wifi/linux-mt76/files/patches/3012-wifi-mt76-mt7915-enable-PPDU-TxS-to-host-when-wed-en.patch
+++ b/recipes-wifi/linux-mt76/files/patches/3010-wifi-mt76-mt7915-enable-PPDU-TxS-to-host-when-wed-en.patch
@@ -1,7 +1,7 @@
-From 3c70695fbf551ae8eaf90fa92f08ab45199f69e4 Mon Sep 17 00:00:00 2001
+From 5c346af2c8a9352b9303d1e7f9e6f424417dfc98 Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Wed, 18 Jan 2023 11:50:38 +0800
-Subject: [PATCH 3012/3015] wifi: mt76: mt7915: enable PPDU-TxS to host when
+Subject: [PATCH 3010/3013] wifi: mt76: mt7915: enable PPDU-TxS to host when
wed enable
Calculate tx bytes and tx retries from PPDU-TxS
@@ -13,7 +13,7 @@
4 files changed, 12 insertions(+), 23 deletions(-)
diff --git a/mt76_connac_mac.c b/mt76_connac_mac.c
-index 05ba5f26..4e24c492 100644
+index abcb9a27..5a5861a8 100644
--- a/mt76_connac_mac.c
+++ b/mt76_connac_mac.c
@@ -490,8 +490,6 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
@@ -26,10 +26,10 @@
wcid->stats.tx_packets++;
}
diff --git a/mt7915/init.c b/mt7915/init.c
-index c3b186c8..a1be5b7d 100644
+index 27395316..70563c9d 100644
--- a/mt7915/init.c
+++ b/mt7915/init.c
-@@ -491,6 +491,12 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
+@@ -503,6 +503,12 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) |
FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3);
mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set);
diff --git a/recipes-wifi/linux-mt76/files/patches/3013-wifi-mt76-mt7915-get-tx-retries-from-tx-free-done-ev.patch b/recipes-wifi/linux-mt76/files/patches/3011-wifi-mt76-mt7915-get-tx-retries-from-tx-free-done-ev.patch
similarity index 95%
rename from recipes-wifi/linux-mt76/files/patches/3013-wifi-mt76-mt7915-get-tx-retries-from-tx-free-done-ev.patch
rename to recipes-wifi/linux-mt76/files/patches/3011-wifi-mt76-mt7915-get-tx-retries-from-tx-free-done-ev.patch
index e596240..6904bea 100644
--- a/recipes-wifi/linux-mt76/files/patches/3013-wifi-mt76-mt7915-get-tx-retries-from-tx-free-done-ev.patch
+++ b/recipes-wifi/linux-mt76/files/patches/3011-wifi-mt76-mt7915-get-tx-retries-from-tx-free-done-ev.patch
@@ -1,8 +1,8 @@
-From be812eb6a9ceafc732c518070458fed74a09cd2e Mon Sep 17 00:00:00 2001
+From 47c0c3360a84cb4f8d5500ef1190a1eea394e2e8 Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Tue, 17 Jan 2023 21:15:00 +0800
-Subject: [PATCH] wifi: mt76: mt7915: get tx retries from tx free done event
- for sw path
+Subject: [PATCH 3011/3013] wifi: mt76: mt7915: get tx retries from tx free
+ done event for sw path
---
mt7915/mac.c | 14 +++++++++++---
diff --git a/recipes-wifi/linux-mt76/files/patches/3014-wifi-mt76-update-debugfs-knob-for-reset-counter-and-.patch b/recipes-wifi/linux-mt76/files/patches/3012-wifi-mt76-update-debugfs-knob-for-reset-counter-and-.patch
similarity index 93%
rename from recipes-wifi/linux-mt76/files/patches/3014-wifi-mt76-update-debugfs-knob-for-reset-counter-and-.patch
rename to recipes-wifi/linux-mt76/files/patches/3012-wifi-mt76-update-debugfs-knob-for-reset-counter-and-.patch
index 96c308b..c852b73 100644
--- a/recipes-wifi/linux-mt76/files/patches/3014-wifi-mt76-update-debugfs-knob-for-reset-counter-and-.patch
+++ b/recipes-wifi/linux-mt76/files/patches/3012-wifi-mt76-update-debugfs-knob-for-reset-counter-and-.patch
@@ -1,7 +1,7 @@
-From 5b02de4f8b414de462c2c2df61aed85e745d5999 Mon Sep 17 00:00:00 2001
+From 655d403531165600ea621dc7889165a091971331 Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Mon, 30 Jan 2023 11:36:32 +0800
-Subject: [PATCH 3014/3015] wifi: mt76: update debugfs knob for reset counter
+Subject: [PATCH 3012/3013] wifi: mt76: update debugfs knob for reset counter
and get tx packet error rate
---
@@ -9,7 +9,7 @@
1 file changed, 62 insertions(+)
diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index d203facf..479da4a0 100644
+index 2dc4cb87..87a7ca98 100644
--- a/mt7915/mtk_debugfs.c
+++ b/mt7915/mtk_debugfs.c
@@ -3190,6 +3190,66 @@ mt7915_sw_aci_set(void *data, u64 val)
diff --git a/recipes-wifi/linux-mt76/files/patches/3015-mt76-connac-wed-add-wed-rx-copy-skb-and-revert-page_.patch b/recipes-wifi/linux-mt76/files/patches/3013-mt76-connac-wed-add-wed-rx-copy-skb-and-revert-page_.patch
similarity index 93%
rename from recipes-wifi/linux-mt76/files/patches/3015-mt76-connac-wed-add-wed-rx-copy-skb-and-revert-page_.patch
rename to recipes-wifi/linux-mt76/files/patches/3013-mt76-connac-wed-add-wed-rx-copy-skb-and-revert-page_.patch
index 883312e..89b423c 100644
--- a/recipes-wifi/linux-mt76/files/patches/3015-mt76-connac-wed-add-wed-rx-copy-skb-and-revert-page_.patch
+++ b/recipes-wifi/linux-mt76/files/patches/3013-mt76-connac-wed-add-wed-rx-copy-skb-and-revert-page_.patch
@@ -1,7 +1,7 @@
-From a8e76b8635c6daf65fb029ea4476ef777768c092 Mon Sep 17 00:00:00 2001
+From 40bc4191469a25ab239596071faf7d8ad69e9fb3 Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Thu, 5 Jan 2023 16:43:57 +0800
-Subject: [PATCH 3015/3015] mt76: connac: wed: add wed rx copy skb and revert
+Subject: [PATCH 3013/3013] mt76: connac: wed: add wed rx copy skb and revert
page_pool
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
@@ -13,10 +13,10 @@
mt7915/mmio.c | 74 +++++++++++++++++++--------
mt7921/main.c | 31 ++----------
usb.c | 42 +++++++--------
- 7 files changed, 180 insertions(+), 210 deletions(-)
+ 7 files changed, 179 insertions(+), 211 deletions(-)
diff --git a/dma.c b/dma.c
-index 76af6506..79da538c 100644
+index d1a1dae4..3adb1136 100644
--- a/dma.c
+++ b/dma.c
@@ -173,7 +173,7 @@ mt76_free_pending_rxwi(struct mt76_dev *dev)
@@ -66,7 +66,7 @@
{
struct mt76_queue_entry *e = &q->entry[idx];
struct mt76_desc *desc = &q->desc[idx];
-@@ -435,15 +437,47 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
+@@ -433,15 +435,47 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
if (!r)
return NULL;
@@ -121,7 +121,7 @@
if (drop) {
u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl));
-@@ -463,9 +497,9 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
+@@ -454,9 +488,9 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
} else {
buf = e->buf;
e->buf = NULL;
@@ -134,7 +134,7 @@
}
return buf;
-@@ -489,7 +523,7 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
+@@ -480,7 +514,7 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
q->tail = (q->tail + 1) % q->ndesc;
q->queued--;
@@ -143,7 +143,7 @@
}
static int
-@@ -616,11 +650,12 @@ free_skb:
+@@ -607,11 +641,12 @@ free_skb:
}
static int
@@ -159,7 +159,7 @@
if (!q->ndesc)
return 0;
-@@ -628,31 +663,35 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
+@@ -619,31 +654,35 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
spin_lock_bh(&q->lock);
while (q->queued < q->ndesc - 1) {
@@ -208,7 +208,7 @@
mt76_dma_kick_queue(dev, q);
spin_unlock_bh(&q->lock);
-@@ -690,7 +729,7 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset)
+@@ -681,7 +720,7 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset)
/* WED txfree queue needs ring to be initialized before setup */
q->flags = 0;
mt76_dma_queue_reset(dev, q);
@@ -217,7 +217,7 @@
q->flags = flags;
ret = mtk_wed_device_txfree_ring_setup(wed, q->regs);
-@@ -738,10 +777,6 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
+@@ -729,10 +768,6 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
if (!q->entry)
return -ENOMEM;
@@ -228,7 +228,7 @@
ret = mt76_dma_wed_setup(dev, q, false);
if (ret)
return ret;
-@@ -755,6 +790,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
+@@ -746,6 +781,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
static void
mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
{
@@ -236,7 +236,7 @@
void *buf;
bool more;
-@@ -768,7 +804,7 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
+@@ -759,7 +795,7 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
if (!buf)
break;
@@ -245,7 +245,7 @@
} while (1);
if (q->rx_head) {
-@@ -777,6 +813,15 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
+@@ -768,6 +804,15 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
}
spin_unlock_bh(&q->lock);
@@ -261,7 +261,7 @@
}
static void
-@@ -797,7 +842,7 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid)
+@@ -788,7 +833,7 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid)
mt76_dma_wed_setup(dev, q, true);
if (q->flags != MT_WED_Q_TXFREE) {
mt76_dma_sync_idx(dev, q);
@@ -270,7 +270,7 @@
}
}
-@@ -815,7 +860,7 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
+@@ -806,7 +851,7 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
skb_add_rx_frag(skb, nr_frags, page, offset, len, q->buf_size);
} else {
@@ -279,7 +279,7 @@
}
if (more)
-@@ -888,7 +933,6 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
+@@ -879,7 +924,6 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
goto free_frag;
skb_reserve(skb, q->buf_offset);
@@ -287,7 +287,7 @@
*(u32 *)skb->cb = info;
-@@ -904,10 +948,10 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
+@@ -895,10 +939,10 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
continue;
free_frag:
@@ -300,7 +300,7 @@
return done;
}
-@@ -952,7 +996,7 @@ mt76_dma_init(struct mt76_dev *dev,
+@@ -943,7 +987,7 @@ mt76_dma_init(struct mt76_dev *dev,
mt76_for_each_q_rx(dev, i) {
netif_napi_add(&dev->napi_dev, &dev->napi[i], poll);
@@ -309,7 +309,7 @@
napi_enable(&dev->napi[i]);
}
-@@ -1003,8 +1047,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
+@@ -994,8 +1038,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
netif_napi_del(&dev->napi[i]);
mt76_dma_rx_cleanup(dev, q);
@@ -319,7 +319,7 @@
mt76_free_pending_txwi(dev);
diff --git a/mac80211.c b/mac80211.c
-index 95861d47..90447472 100644
+index 4655f814..4dc7627e 100644
--- a/mac80211.c
+++ b/mac80211.c
@@ -4,7 +4,6 @@
@@ -330,7 +330,7 @@
#include "mt76.h"
#define CHAN2G(_idx, _freq) { \
-@@ -569,47 +568,6 @@ void mt76_unregister_phy(struct mt76_phy *phy)
+@@ -573,47 +572,6 @@ void mt76_unregister_phy(struct mt76_phy *phy)
}
EXPORT_SYMBOL_GPL(mt76_unregister_phy);
@@ -378,7 +378,7 @@
struct mt76_dev *
mt76_alloc_device(struct device *pdev, unsigned int size,
const struct ieee80211_ops *ops,
-@@ -1745,21 +1703,6 @@ void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
+@@ -1753,21 +1711,6 @@ void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
}
EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
@@ -401,10 +401,10 @@
{
struct ieee80211_hw *hw = phy->hw;
diff --git a/mt76.h b/mt76.h
-index 22c6531a..19100d62 100644
+index bc0c9ae7..d17650d0 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -210,7 +210,7 @@ struct mt76_queue {
+@@ -209,7 +209,7 @@ struct mt76_queue {
dma_addr_t desc_dma;
struct sk_buff *rx_head;
@@ -633,7 +633,7 @@
return -ENOMEM;
}
diff --git a/mt7921/main.c b/mt7921/main.c
-index 75eaf86c..1434ca79 100644
+index a72964e7..4c400223 100644
--- a/mt7921/main.c
+++ b/mt7921/main.c
@@ -1090,34 +1090,17 @@ static void
@@ -699,7 +699,7 @@
static u64
diff --git a/usb.c b/usb.c
-index b88959ef..3e281715 100644
+index 5e5c7bf5..f0a50f57 100644
--- a/usb.c
+++ b/usb.c
@@ -319,27 +319,29 @@ mt76u_set_endpoints(struct usb_interface *intf,
@@ -816,12 +816,12 @@
int i;
for (i = 0; i < q->ndesc; i++) {
-@@ -705,7 +701,13 @@ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
+@@ -705,8 +701,12 @@ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
mt76u_urb_free(q->entry[i].urb);
q->entry[i].urb = NULL;
}
- page_pool_destroy(q->page_pool);
-+
+- q->page_pool = NULL;
+ if (!q->rx_page.va)
+ return;
+
diff --git a/recipes-wifi/linux-mt76/files/patches/4001-mt76-revert-get_of_mac_addr.patch b/recipes-wifi/linux-mt76/files/patches/4001-mt76-revert-get_of_mac_addr.patch
index 143f279..7a0aa12 100644
--- a/recipes-wifi/linux-mt76/files/patches/4001-mt76-revert-get_of_mac_addr.patch
+++ b/recipes-wifi/linux-mt76/files/patches/4001-mt76-revert-get_of_mac_addr.patch
@@ -1,4 +1,4 @@
-From d5719b44dcc2f6ef728a63f523dbbe9f089a2eaf Mon Sep 17 00:00:00 2001
+From 5b3d131191690db907ee5c0ba43a80cb0f23b3bc Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Tue, 13 Dec 2022 10:51:46 +0800
Subject: [PATCH 4001/4005] mt76: revert get_of_mac_addr
@@ -8,7 +8,7 @@
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/eeprom.c b/eeprom.c
-index d1612641..1f29cf99 100644
+index 6e6d84e3..b2df0f44 100644
--- a/eeprom.c
+++ b/eeprom.c
@@ -128,9 +128,15 @@ void
diff --git a/recipes-wifi/linux-mt76/files/patches/4002-mt76-include-header-files-for-module-param.patch b/recipes-wifi/linux-mt76/files/patches/4002-mt76-include-header-files-for-module-param.patch
index 509b828..e7661df 100644
--- a/recipes-wifi/linux-mt76/files/patches/4002-mt76-include-header-files-for-module-param.patch
+++ b/recipes-wifi/linux-mt76/files/patches/4002-mt76-include-header-files-for-module-param.patch
@@ -1,4 +1,4 @@
-From 83be679b14eb071b0eb1cedac9d004901322b2f3 Mon Sep 17 00:00:00 2001
+From 227f29f577dda88bda5c6213a655e89ff3b9203c Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Tue, 13 Dec 2022 10:38:13 +0800
Subject: [PATCH 4002/4005] mt76: include header files for module param
@@ -47,7 +47,7 @@
int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option)
{
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index b5a0967b..f4867ea7 100644
+index e1c08178..37291865 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -6,6 +6,7 @@
diff --git a/recipes-wifi/linux-mt76/files/patches/4003-mt76-revert-kernel-api-for-kernel-5.4.patch b/recipes-wifi/linux-mt76/files/patches/4003-mt76-revert-kernel-api-for-kernel-5.4.patch
index d7d40c2..a75825e 100644
--- a/recipes-wifi/linux-mt76/files/patches/4003-mt76-revert-kernel-api-for-kernel-5.4.patch
+++ b/recipes-wifi/linux-mt76/files/patches/4003-mt76-revert-kernel-api-for-kernel-5.4.patch
@@ -1,4 +1,4 @@
-From 1796376cd4aedff17a93f6a28c5b321d678ebf95 Mon Sep 17 00:00:00 2001
+From be0397f77f21cfbc5f865d89d9c4dcdc87f06233 Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Fri, 30 Dec 2022 11:11:59 +0800
Subject: [PATCH 4003/4005] mt76: revert kernel api for kernel 5.4
@@ -24,10 +24,10 @@
return 0;
}
diff --git a/dma.c b/dma.c
-index 79da538c..e6021369 100644
+index 3adb1136..1fc4bd2d 100644
--- a/dma.c
+++ b/dma.c
-@@ -928,7 +928,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
+@@ -919,7 +919,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
!(dev->drv->rx_check(dev, data, len)))
goto free_frag;
diff --git a/recipes-wifi/linux-mt76/files/patches/4004-mt76-revert-for-backports-5.15-wireless-stack.patch b/recipes-wifi/linux-mt76/files/patches/4004-mt76-revert-for-backports-5.15-wireless-stack.patch
index 1059763..652fa50 100644
--- a/recipes-wifi/linux-mt76/files/patches/4004-mt76-revert-for-backports-5.15-wireless-stack.patch
+++ b/recipes-wifi/linux-mt76/files/patches/4004-mt76-revert-for-backports-5.15-wireless-stack.patch
@@ -1,4 +1,4 @@
-From fb3205686d76d409b1cdd4a25c2dd526fda4b2e4 Mon Sep 17 00:00:00 2001
+From 1a40927274d316173f1aa460083eea54e2804a0a Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Fri, 30 Dec 2022 11:12:07 +0800
Subject: [PATCH 4004/4005] mt76: revert for backports-5.15 wireless stack
@@ -22,10 +22,10 @@
15 files changed, 168 insertions(+), 178 deletions(-)
diff --git a/dma.c b/dma.c
-index e6021369..c2125106 100644
+index 1fc4bd2d..e7d174b8 100644
--- a/dma.c
+++ b/dma.c
-@@ -995,7 +995,7 @@ mt76_dma_init(struct mt76_dev *dev,
+@@ -986,7 +986,7 @@ mt76_dma_init(struct mt76_dev *dev,
init_completion(&dev->mmio.wed_reset_complete);
mt76_for_each_q_rx(dev, i) {
@@ -35,10 +35,10 @@
napi_enable(&dev->napi[i]);
}
diff --git a/mac80211.c b/mac80211.c
-index 90447472..14a02c01 100644
+index 4dc7627e..4c88710f 100644
--- a/mac80211.c
+++ b/mac80211.c
-@@ -1509,7 +1509,7 @@ EXPORT_SYMBOL_GPL(mt76_get_sar_power);
+@@ -1517,7 +1517,7 @@ EXPORT_SYMBOL_GPL(mt76_get_sar_power);
static void
__mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
@@ -47,7 +47,7 @@
ieee80211_csa_finish(vif);
}
-@@ -1531,7 +1531,7 @@ __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
+@@ -1539,7 +1539,7 @@ __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
struct mt76_dev *dev = priv;
@@ -524,10 +524,10 @@
field = RATE_PARAM_FIXED;
diff --git a/mt7915/dma.c b/mt7915/dma.c
-index 4dd321ee..354d1e0e 100644
+index 6d9b2d15..08322453 100644
--- a/mt7915/dma.c
+++ b/mt7915/dma.c
-@@ -552,8 +552,8 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
+@@ -554,8 +554,8 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
if (ret < 0)
return ret;
@@ -539,10 +539,10 @@
mt7915_dma_enable(dev);
diff --git a/mt7915/init.c b/mt7915/init.c
-index a1be5b7d..9e8003d7 100644
+index 70563c9d..0b852286 100644
--- a/mt7915/init.c
+++ b/mt7915/init.c
-@@ -1139,8 +1139,7 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
+@@ -1160,8 +1160,7 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
mt7915_gen_ppe_thresh(he_cap->ppe_thres, nss);
} else {
he_cap_elem->phy_cap_info[9] |=
@@ -553,7 +553,7 @@
if (band == NL80211_BAND_6GHZ) {
diff --git a/mt7915/mac.c b/mt7915/mac.c
-index b7559182..26eb211a 100644
+index 180c1ae3..583b71b1 100644
--- a/mt7915/mac.c
+++ b/mt7915/mac.c
@@ -902,7 +902,7 @@ mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
@@ -610,7 +610,7 @@
mutex_lock(&dev->mt76.mutex);
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 003e33be..a7d3adc2 100644
+index 37291865..4f1bd1cd 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -64,7 +64,7 @@ mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs,
diff --git a/recipes-wifi/linux-mt76/files/patches/4005-wifi-mt76-revert-EHT-definitions.patch b/recipes-wifi/linux-mt76/files/patches/4005-wifi-mt76-revert-EHT-definitions.patch
index 8404f7b..479accf 100644
--- a/recipes-wifi/linux-mt76/files/patches/4005-wifi-mt76-revert-EHT-definitions.patch
+++ b/recipes-wifi/linux-mt76/files/patches/4005-wifi-mt76-revert-EHT-definitions.patch
@@ -1,4 +1,4 @@
-From b655964b1f68678a665f30a68c13a73feeffaa73 Mon Sep 17 00:00:00 2001
+From 21286ba6a27ae54885687c0f82a48e52cef638aa Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Fri, 3 Feb 2023 17:09:55 +0800
Subject: [PATCH 4005/4005] wifi: mt76: revert EHT definitions
@@ -99,10 +99,10 @@
#define DEFAULT_HE_DURATION_RTS_THRES 1023
static void
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 747ae7e9..3d4322d1 100644
+index 287cffcc..b80a1011 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1897,12 +1897,8 @@ void mt76_connac_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val);
+@@ -1894,12 +1894,8 @@ void mt76_connac_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val);
const struct ieee80211_sta_he_cap *
mt76_connac_get_he_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif);
diff --git a/recipes-wifi/linux-mt76/files/patches/patches.inc b/recipes-wifi/linux-mt76/files/patches/patches.inc
index c041c72..833a2b0 100644
--- a/recipes-wifi/linux-mt76/files/patches/patches.inc
+++ b/recipes-wifi/linux-mt76/files/patches/patches.inc
@@ -1,6 +1,5 @@
#patch patches (come from openwrt/lede/target/linux/mediatek)
SRC_URI_append = " \
- file://0001-wifi-mt76-mt7915-rework-mt7915_thermal_init.patch \
file://1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch \
file://1002-mt76-mt7915-csi-implement-csi-support.patch \
file://1003-mt76-mt7915-air-monitor-support.patch \
@@ -32,22 +31,20 @@
file://1130-mt76-mt7915-amsdu-set-and-get-control.patch \
file://1131-wifi-mt76-mt7915-add-support-for-he-ldpc-control-fro.patch \
file://1132-mt76-mt7915-Add-vendor-command-attribute-for-RTS-BW-.patch \
- file://1133-mt76-mt7915-Allow-AP-to-change-channel-width-for-40M.patch \
+ file://1134-mt76-mt7915-add-vendor-cmd-to-get-available-color-bi.patch \
file://3001-mt76-mt7915-wed-add-wed-tx-support.patch \
file://3002-mt76-mt7915-wed-add-wds-support-when-wed-is-enabled.patch \
file://3003-mt76-mt7915-wed-add-fill-receive-path-to-report-wed-.patch \
file://3004-mt76-mt7915-wed-find-rx-token-by-physical-address.patch \
- file://3005-mt76-mt7915-wed-drop-scatter-and-gather-frame.patch \
- file://3006-mt76-mt7915-wed-HW-ATF-support-for-mt7986.patch \
- file://3007-mt76-mt7915-wed-add-mt7916-2-pcie-support-when-wed-o.patch \
- file://3008-mt76-mt7915-wed-add-rxwi-for-further-in-chip-rro.patch \
- file://3009-mt76-mt7915-add-mt7915_net_setup_tc-to-support-wifi2.patch \
- file://3010-wifi-mt76-mt7915-add-wa-command-to-get-tx-msdu-count.patch \
- file://3011-wifi-mt76-get-tx-count-and-tx-failed-from-mcu-comman.patch \
- file://3012-wifi-mt76-mt7915-enable-PPDU-TxS-to-host-when-wed-en.patch \
- file://3013-wifi-mt76-mt7915-get-tx-retries-from-tx-free-done-ev.patch \
- file://3014-wifi-mt76-update-debugfs-knob-for-reset-counter-and-.patch \
- file://3015-mt76-connac-wed-add-wed-rx-copy-skb-and-revert-page_.patch \
+ file://3005-mt76-mt7915-wed-HW-ATF-support-for-mt7986.patch \
+ file://3006-mt76-mt7915-wed-add-rxwi-for-further-in-chip-rro.patch \
+ file://3007-mt76-mt7915-add-mt7915_net_setup_tc-to-support-wifi2.patch \
+ file://3008-wifi-mt76-mt7915-add-wa-command-to-get-tx-msdu-count.patch \
+ file://3009-wifi-mt76-get-tx-count-and-tx-failed-from-mcu-comman.patch \
+ file://3010-wifi-mt76-mt7915-enable-PPDU-TxS-to-host-when-wed-en.patch \
+ file://3011-wifi-mt76-mt7915-get-tx-retries-from-tx-free-done-ev.patch \
+ file://3012-wifi-mt76-update-debugfs-knob-for-reset-counter-and-.patch \
+ file://3013-mt76-connac-wed-add-wed-rx-copy-skb-and-revert-page_.patch \
file://4001-mt76-revert-get_of_mac_addr.patch \
file://4002-mt76-include-header-files-for-module-param.patch \
file://4003-mt76-revert-kernel-api-for-kernel-5.4.patch \
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_eeprom_tm.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_eeprom_tm.bin
new file mode 100755
index 0000000..0ff5567
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_eeprom_tm.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/mt76.inc b/recipes-wifi/linux-mt76/mt76.inc
index 4feb511..1739876 100644
--- a/recipes-wifi/linux-mt76/mt76.inc
+++ b/recipes-wifi/linux-mt76/mt76.inc
@@ -1 +1 @@
-SRCREV ?= "b2360d59747c6fed2b65bc1c3563c10593c83f3e"
+SRCREV ?= "c32d6d849c43792abd8007e13e468b12d6d6e0b7"
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0010-hostapd-mtk-Add-DFS-detection-mode.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0010-hostapd-mtk-Add-DFS-detection-mode.patch
index 2ceb639..7ec986a 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0010-hostapd-mtk-Add-DFS-detection-mode.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/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-2.10.3/mtk-0016-hostapd-mtk-Add-available-color-bitmap.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/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-2.10.3/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-2.10.3/mtk-0020-hostapd-mtk-Mark-DFS-channel-as-available-for-CSA.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/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-2.10.3/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-2.10.3/mtk-0020-hostapd-mtk-add-11v_mbss-and-ema-support.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/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-2.10.3/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-2.10.3/patches.inc b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc
index 78d5240..5e6bf88 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc
@@ -78,8 +78,11 @@
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 \
file://mtk-0100-hostapd-mtk-update-eht-operation-elem.patch \
"
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 \
"
diff --git a/recipes-wifi/wpa-supplicant/files/src/src/ap/ubus.c b/recipes-wifi/wpa-supplicant/files/src/src/ap/ubus.c
index 5001225..ddd8644 100644
--- a/recipes-wifi/wpa-supplicant/files/src/src/ap/ubus.c
+++ b/recipes-wifi/wpa-supplicant/files/src/src/ap/ubus.c
@@ -1084,6 +1084,8 @@
}
__hostapd_bss_mgmt_enable(hapd, flags);
+
+ return 0;
}