[rdkb][common][bsp][Refactor and sync wifi from openwrt]
[Description]
3a2eef0b [MAC80211][Release][Update release note for Filogic 880/860 MLO Beta release]
cfbd2411 [MAC80211][Release][Filogic 880/860 MLO Beta release]
6c180e3f [MAC80211][WiFi7][misc][Add Eagle BE14000 efem default bin]
a55f34db [MAC80211][Release][Prepare for Filogic 880/860 release]
5b45ebca [MAC80211][WiFi7][hostapd][Add puncture bitmap to ucode]
95bbea73 [MAC80211][WiFi6][mt76][Add PID to only report data-frame TX rate]
b15ced26 [MAC80211][WiFi6][hostapd][Fix DFS channel selection issue]
d59133cb [MAC80211][WiFi6][mt76][Fix pse info not correct information]
3921b4b2 [MAC80211][WiFi6][mt76][Fix incomplete QoS-map setting to FW]
4e7690c7 [MAC80211][WiFi6/7][app][Change ATECHANNEL mapping cmd]
eb37af90 [MAC80211][WiFi7][app][Add support for per-packet bw & primary selection]
0ea82adf [MAC80211][WiFi6][core][Fix DFS CAC issue after CSA]
[Release-log]
Change-Id: I9bec97ec1b2e1c49ed43a812a07a5b21fcbb70a6
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/0034-mtk-hostapd-add-connac3-PHY-MURU-manual-mode-config-.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/0034-mtk-hostapd-add-connac3-PHY-MURU-manual-mode-config-.patch
new file mode 100644
index 0000000..69615ec
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/0034-mtk-hostapd-add-connac3-PHY-MURU-manual-mode-config-.patch
@@ -0,0 +1,656 @@
+From f7ffccc3487fbc51786d4063b03e0e4a090253b0 Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Sat, 3 Jun 2023 17:12:15 +0800
+Subject: [PATCH 034/126] mtk: hostapd: add connac3 PHY MURU manual mode config
+ support
+
+This commit supports read the following two formats to set MU/RU manual
+mode:
+1. hostapd_cli -i <intf> raw set_muru_manual_config=<field>:<value>
+2. hostapd_cli -i <intf> set_mu <field> <value>
+
+For the <field>, we support the following field:
+1. ul_comm_user_cnt/dl_comm_user_cnt: set the number of user
+2. ul_comm_bw/dl_comm_bw: set the bandwith
+3. ul_user_ru_alloc/dl_user_ru_alloc: set the RU band idx and RU
+allocate idx
+4. ul_user_mcs/dl_user_mcs: set the mcs for each user
+5. ul_user_ssAlloc_raru: set the number of ss for each user
+6. ul_comm_gi_ltf: set the combinations of gi and ltf for UL only.
+7. dl_comm_toneplan: fix ru toneplan allocation
+8. dl_comm_ack_policy: fix station ack policy
+9. update : trigger driver to send mcu command to set muru manual mode.
+
+For the value of each field, please check wiki to learn the details:
+https://wiki.mediatek.inc/display/GWKB/muru_mancfg_user_guide
+
+For the fields that mt76 support to use, we will update in this wiki:
+https://wiki.mediatek.inc/pages/viewpage.action?pageId=1271741116
+
+Please noted that this commit is only for connac 3 gen chips. If this
+feature is to be used in other generations, the following actions must
+be taken:
+1. Different data structue needs to be defined for different
+generations, e.g. connac4_muru_comm, connac4_muru_dl.
+2. hostapd_ctrl_iface_set_mu() shall be modified.
+3. A new code level configuration shall be defined to differentiate the
+code flow that different generations will go through.
+
+Add support new argument global_comm_band for muru manual config
+command. This argument can be used to specify the band to apply manual
+config.
+
+Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
+---
+ hostapd/ctrl_iface.c | 240 +++++++++++++++++++++++++++++++----
+ src/ap/ap_config.h | 1 +
+ src/ap/ap_drv_ops.c | 4 +-
+ src/ap/ap_drv_ops.h | 2 +-
+ src/ap/hostapd.c | 2 +-
+ src/common/mtk_vendor.h | 166 +++++++++++++++++++++++-
+ src/drivers/driver.h | 2 +-
+ src/drivers/driver_nl80211.c | 21 ++-
+ 8 files changed, 394 insertions(+), 44 deletions(-)
+
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index b78ee24c0..68b83bf6e 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -3905,7 +3905,6 @@ hostapd_ctrl_iface_get_edcca(struct hostapd_data *hapd, char *cmd, char *buf,
+ }
+ }
+
+-
+ #ifdef CONFIG_NAN_USD
+
+ static int hostapd_ctrl_nan_publish(struct hostapd_data *hapd, char *cmd,
+@@ -4192,21 +4191,61 @@ fail:
+ #endif /* CONFIG_NAN_USD */
+
+
++static int
++hostapd_parse_argument_helper(char *value, u16 **ptr_input)
++{
++#define MAX_MU_CTRL_NUM 17
++ u16 *input;
++ char *endptr;
++ int cnt = 0;
++
++ input = os_zalloc(MAX_MU_CTRL_NUM * sizeof(u16));
++ if (input == NULL) {
++ wpa_printf(MSG_ERROR, "Failed to allocate memory.\n");
++ return -1;
++ }
++ while (value) {
++ u8 val = strtol(value, &endptr, 10);
++
++ if (value != endptr) {
++ input[cnt++] = val;
++ value = os_strchr(endptr, ':');
++ if (value)
++ value++;
++ } else {
++ break;
++ }
++ }
++
++ *ptr_input = input;
++ return cnt;
++}
++
++#define MURU_CFG_DEPENDENCE_CHECK(_val, _mask) do { \
++ if ((le_to_host32(_val) & (_mask)) != _mask) { \
++ wpa_printf(MSG_ERROR, "Set %s first\n", #_mask); \
++ goto fail; \
++ } \
++ } while(0)
++
+ static int
+ hostapd_ctrl_iface_set_mu(struct hostapd_data *hapd, char *cmd,
+- char *buf, size_t buflen)
++ char *buf, size_t buflen)
+ {
+ char *pos, *config, *value;
+- u8 mode;
++ u8 i;
++ int cnt = 0, ret;
++ u16 *val;
++ struct connac3_muru *muru;
++ struct connac3_muru_dl *dl;
++ struct connac3_muru_ul *ul;
++ struct connac3_muru_comm *comm;
+
+ config = cmd;
+ pos = os_strchr(config, ' ');
+- if (pos == NULL)
+- return -1;
+- *pos++ = '\0';
++ if (pos != NULL)
++ *pos++ = '\0';
+
+- if(pos == NULL)
+- return -1;
+ value = pos;
+
+ if (os_strcmp(config, "onoff") == 0) {
+@@ -4216,24 +4255,170 @@ hostapd_ctrl_iface_set_mu(struct hostapd_data *hapd, char *cmd,
+ return -1;
+ }
+ hapd->iconf->mu_onoff = (u8) mu;
+- mode = MU_CTRL_ONOFF;
+- } else if (os_strcmp(config, "ul_user_cnt") == 0) {
+- mode = MU_CTRL_UL_USER_CNT;
+- wpa_printf(MSG_ERROR, "ul_user_cnt:%d\n", (u8)atoi(value));
+- } else if (os_strcmp(config, "dl_user_cnt") == 0) {
+- mode = MU_CTRL_DL_USER_CNT;
+- wpa_printf(MSG_ERROR, "dl_user_cnt:%d\n", (u8)atoi(value));
+- } else {
+- wpa_printf(MSG_ERROR,
+- "Unsupported parameter %s for SET_MU", config);
+- return -1;
++
++ if (hostapd_drv_mu_ctrl(hapd, MU_CTRL_ONOFF) == 0)
++ return os_snprintf(buf, buflen, "OK\n");
++ else
++ goto fail;
+ }
+
+- if(hostapd_drv_mu_ctrl(hapd, mode, (u8)atoi(value)) == 0) {
+- return os_snprintf(buf, buflen, "OK\n");
++ if (hapd->iconf->muru_config == NULL)
++ hapd->iconf->muru_config = os_zalloc(sizeof(struct connac3_muru));
++
++ muru = hapd->iconf->muru_config;
++ dl = &muru->dl;
++ ul = &muru->ul;
++ comm = &muru->comm;
++
++ if (os_strncmp(config, "update", 6) == 0) {
++ ret = hostapd_drv_mu_ctrl(hapd, MU_CTRL_UPDATE);
++
++ os_free(hapd->iconf->muru_config);
++ hapd->iconf->muru_config = NULL;
++
++ if (ret)
++ goto fail;
++ } else if (os_strcmp(config, "ul_comm_user_cnt") == 0) {
++ ul->user_num = (u8)atoi(value);
++ comm->ppdu_format |= MURU_PPDU_HE_TRIG;
++ comm->sch_type |= MURU_OFDMA_SCH_TYPE_UL;
++ muru->cfg_comm |= host_to_le32(MURU_COMM_SET);
++ muru->cfg_ul |= host_to_le32(MURU_FIXED_UL_TOTAL_USER_CNT);
++ } else if (os_strcmp(config, "dl_comm_user_cnt") == 0) {
++ dl->user_num = (u8)atoi(value);
++ comm->ppdu_format |= MURU_PPDU_HE_MU;
++ comm->sch_type |= MURU_OFDMA_SCH_TYPE_DL;
++ muru->cfg_comm |= host_to_le32(MURU_COMM_SET);
++ muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_TOTAL_USER_CNT);
++ } else if (os_strcmp(config, "dl_comm_bw") == 0) {
++ dl->bw = (u8)atoi(value);
++ muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_BW);
++ } else if (os_strcmp(config, "ul_comm_bw") == 0) {
++ ul->bw = (u8)atoi(value);
++ muru->cfg_ul |= host_to_le32(MURU_FIXED_UL_BW);
++ } else if (os_strcmp(config, "dl_user_ru_alloc") == 0) {
++ MURU_CFG_DEPENDENCE_CHECK(muru->cfg_dl, MURU_FIXED_DL_TOTAL_USER_CNT);
++ cnt = hostapd_parse_argument_helper(value, &val);
++ if (cnt == -1)
++ goto fail;
++ if (cnt != (dl->user_num * 2))
++ goto para_fail;
++ for (i = 0; i < dl->user_num; i++) {
++ dl->usr[i].ru_alloc_seg = (val[2 * i] & 0x1);
++ dl->usr[i].ru_allo_ps160 = ((val[2 * i] & 0x2) >> 1);
++ dl->usr[i].ru_idx = val[(2 * i) + 1];
++ }
++ os_free(val);
++ muru->cfg_dl |= host_to_le32(MURU_FIXED_USER_DL_RU_ALLOC);
++ } else if (os_strcmp(config, "ul_user_ru_alloc") == 0) {
++ MURU_CFG_DEPENDENCE_CHECK(muru->cfg_ul, MURU_FIXED_UL_TOTAL_USER_CNT);
++ cnt = hostapd_parse_argument_helper(value, &val);
++ if (cnt == -1)
++ goto fail;
++ if (cnt != (ul->user_num * 2))
++ goto para_fail;
++ for (i = 0; i < ul->user_num; i++) {
++ ul->usr[i].ru_alloc_seg = (val[2 * i] & 0x1);
++ ul->usr[i].ru_allo_ps160 = ((val[2 * i] & 0x2) >> 1);
++ ul->usr[i].ru_idx = val[(2 * i) + 1];
++ }
++ os_free(val);
++ muru->cfg_ul |= host_to_le32(MURU_FIXED_USER_UL_RU_ALLOC);
++ } else if (os_strcmp(config, "dl_user_mcs") == 0) {
++ MURU_CFG_DEPENDENCE_CHECK(muru->cfg_dl, MURU_FIXED_DL_TOTAL_USER_CNT);
++ cnt = hostapd_parse_argument_helper(value, &val);
++ if (cnt == -1)
++ goto fail;
++ if (cnt != dl->user_num)
++ goto para_fail;
++ for (i = 0; i < cnt; i++)
++ dl->usr[i].mcs = (u8) val[i];
++ os_free(val);
++ muru->cfg_dl |= host_to_le32(MURU_FIXED_USER_DL_MCS);
++ } else if (os_strcmp(config, "ul_user_mcs") == 0) {
++ MURU_CFG_DEPENDENCE_CHECK(muru->cfg_ul, MURU_FIXED_UL_TOTAL_USER_CNT);
++ cnt = hostapd_parse_argument_helper(value, &val);
++ if (cnt == -1)
++ goto fail;
++ if (cnt != ul->user_num)
++ goto para_fail;
++ for (i = 0; i < cnt; i++)
++ ul->usr[i].mcs = (u8) val[i];
++ os_free(val);
++ muru->cfg_ul |= host_to_le32(MURU_FIXED_USER_UL_MCS);
++ } else if (os_strcmp(config, "dl_user_cod") == 0) {
++ MURU_CFG_DEPENDENCE_CHECK(muru->cfg_dl, MURU_FIXED_DL_TOTAL_USER_CNT);
++ cnt = hostapd_parse_argument_helper(value, &val);
++ if (cnt == -1)
++ goto fail;
++ if (cnt != dl->user_num)
++ goto para_fail;
++ for (i = 0; i < cnt; i++)
++ dl->usr[i].ldpc = (u8) val[i];
++ os_free(val);
++ muru->cfg_dl |= host_to_le32(MURU_FIXED_USER_DL_COD);
++ } else if (os_strcmp(config, "ul_user_cod") == 0) {
++ MURU_CFG_DEPENDENCE_CHECK(muru->cfg_ul, MURU_FIXED_UL_TOTAL_USER_CNT);
++ cnt = hostapd_parse_argument_helper(value, &val);
++ if (cnt == -1)
++ goto fail;
++ if (cnt != ul->user_num)
++ goto para_fail;
++ for (i = 0; i < cnt; i++)
++ ul->usr[i].ldpc = (u8) val[i];
++ os_free(val);
++ muru->cfg_ul |= host_to_le32(MURU_FIXED_USER_UL_COD);
++ } else if (os_strcmp(config, "ul_user_ssAlloc_raru") == 0) {
++ MURU_CFG_DEPENDENCE_CHECK(muru->cfg_ul, MURU_FIXED_UL_TOTAL_USER_CNT);
++ cnt = hostapd_parse_argument_helper(value, &val);
++ if (cnt == -1)
++ goto fail;
++ if (cnt != ul->user_num)
++ goto para_fail;
++ for (i = 0; i < cnt; i++)
++ ul->usr[i].nss = (u8) val[i];
++ os_free(val);
++ muru->cfg_ul |= host_to_le32(MURU_FIXED_USER_UL_NSS);
++ } else if (os_strcmp(config, "dl_comm_gi") == 0) {
++ dl->gi = (u8)atoi(value);
++ muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_GI);
++ } else if (os_strcmp(config, "dl_comm_ltf") == 0) {
++ dl->ltf = (u8)atoi(value);
++ muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_LTF);
++ } else if (os_strcmp(config, "ul_comm_gi_ltf") == 0) {
++ ul->gi_ltf = (u8)atoi(value);
++ muru->cfg_ul |= host_to_le32(MURU_FIXED_UL_GILTF);
++ } else if (os_strcmp(config, "dl_comm_ack_policy") == 0) {
++ dl->ack_policy = (u8)atoi(value);
++ muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_ACK_PLY);
++ } else if (os_strcmp(config, "dl_comm_toneplan") == 0) {
++ MURU_CFG_DEPENDENCE_CHECK(muru->cfg_dl, MURU_FIXED_DL_BW);
++ cnt = hostapd_parse_argument_helper(value, &val);
++ if (cnt == -1)
++ goto fail;
++ i = pow(2, dl->bw);
++ if (cnt != i)
++ goto para_fail;
++ for (i = 0; i < cnt; i++)
++ dl->ru[i] = host_to_le16(val[i]);
++ os_free(val);
++ muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_TONE_PLAN);
++ } else if (os_strcmp(config, "global_comm_band") == 0) {
++ comm->band = (u8)atoi(value);
++ muru->cfg_comm |= host_to_le32(MURU_COMM_BAND);
+ } else {
+- return -1;
++ wpa_printf(MSG_ERROR,
++ "Unsupported parameter %s for SET_MU", config);
++ goto fail;
+ }
++
++ return os_snprintf(buf, buflen, "OK\n");
++
++para_fail:
++ os_free(val);
++ wpa_printf(MSG_ERROR, "Incorrect input number\n");
++fail:
++ return os_snprintf(buf, buflen, "FAIL\n");
+ }
+
+
+@@ -5290,8 +5475,7 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ reply_len = hostapd_ctrl_iface_get_edcca(hapd, buf+10, reply,
+ reply_size);
+ } else if (os_strncmp(buf, "SET_MU ", 7) == 0) {
+- reply_len = hostapd_ctrl_iface_set_mu(hapd, buf + 7, reply,
+- reply_size);
++ reply_len = hostapd_ctrl_iface_set_mu(hapd, buf + 7, reply, reply_size);
+ } else if (os_strncmp(buf, "GET_MU", 6) == 0) {
+ reply_len = hostapd_ctrl_iface_get_mu(hapd, reply, reply_size);
+ } else if (os_strncmp(buf, "GET_IBF", 7) == 0) {
+@@ -5317,6 +5501,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ } else if (os_strncmp(buf, "DUMP_AMNT", 9) == 0) {
+ reply_len = hostapd_ctrl_iface_dump_amnt(hapd, buf+10,
+ reply, reply_size);
++ } else if (os_strncmp(buf, "set_muru_manual_config=", 23) == 0) {
++ // Replace first ':' with a single space ' '
++ char *pos = buf + 23;
++
++ pos = os_strchr(pos, ':');
++ if (pos)
++ *pos = ' ';
++ reply_len = hostapd_ctrl_iface_set_mu(hapd, buf + 23, reply, reply_size);
+ } else {
+ os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+ reply_len = 16;
+diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
+index f90f4d554..0c51d2ab9 100644
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
+@@ -1344,6 +1344,7 @@ struct hostapd_config {
+ u8 ibf_enable;
+ u8 dfs_detect_mode;
+ u8 amsdu;
++ void *muru_config;
+ };
+
+ enum three_wire_mode {
+diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
+index 496fd4263..ccd0cb939 100644
+--- a/src/ap/ap_drv_ops.c
++++ b/src/ap/ap_drv_ops.c
+@@ -1299,11 +1299,11 @@ int hostapd_drv_get_edcca(struct hostapd_data *hapd, const u8 mode, u8 *value)
+ return hapd->driver->get_edcca(hapd->drv_priv, mode, value);
+ }
+
+-int hostapd_drv_mu_ctrl(struct hostapd_data *hapd, u8 mode, u8 val)
++int hostapd_drv_mu_ctrl(struct hostapd_data *hapd, u8 mode)
+ {
+ if (!hapd->driver || !hapd->driver->mu_ctrl)
+ return 0;
+- return hapd->driver->mu_ctrl(hapd->drv_priv, mode, val);
++ return hapd->driver->mu_ctrl(hapd->drv_priv, mode, hapd->iconf);
+ }
+
+ int hostapd_drv_mu_dump(struct hostapd_data *hapd, u8 *mu_onoff)
+diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
+index a949e168d..659154f56 100644
+--- a/src/ap/ap_drv_ops.h
++++ b/src/ap/ap_drv_ops.h
+@@ -156,7 +156,7 @@ int hostapd_drv_configure_edcca_enable(struct hostapd_data *hapd);
+ int hostapd_drv_configure_edcca_threshold(struct hostapd_data *hapd,
+ const int *threshold);
+ int hostapd_drv_get_edcca(struct hostapd_data *hapd, const u8 mode, u8 *value);
+-int hostapd_drv_mu_ctrl(struct hostapd_data *hapd, u8 mode, u8 val);
++int hostapd_drv_mu_ctrl(struct hostapd_data *hapd, u8 mode);
+ int hostapd_drv_mu_dump(struct hostapd_data *hapd, u8 *mu_onoff);
+ int hostapd_drv_three_wire_ctrl(struct hostapd_data *hapd);
+ int hostapd_drv_ibf_ctrl(struct hostapd_data *hapd);
+diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
+index 9e1ba6a21..f06687064 100644
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -2763,7 +2763,7 @@ dfs_offload:
+ if (hostapd_drv_configure_edcca_threshold(hapd,
+ hapd->iconf->edcca_threshold) < 0)
+ goto fail;
+- if (hostapd_drv_mu_ctrl(hapd, MU_CTRL_ONOFF, hapd->iconf->mu_onoff) < 0)
++ if (hostapd_drv_mu_ctrl(hapd, MU_CTRL_ONOFF) < 0)
+ goto fail;
+ if (hostapd_drv_three_wire_ctrl(hapd) < 0)
+ goto fail;
+diff --git a/src/common/mtk_vendor.h b/src/common/mtk_vendor.h
+index 34238f098..f0abcb6b1 100644
+--- a/src/common/mtk_vendor.h
++++ b/src/common/mtk_vendor.h
+@@ -202,8 +202,11 @@ enum mtk_vendor_attr_mu_ctrl {
+
+ MTK_VENDOR_ATTR_MU_CTRL_ONOFF,
+ MTK_VENDOR_ATTR_MU_CTRL_DUMP,
+- MTK_VENDOR_ATTR_MU_CTRL_OFDMA_MODE,
+- MTK_VENDOR_ATTR_MU_CTRL_OFDMA_VAL,
++ /**
++ * The above attrs are also used by connac 2. It is best not to modify the
++ * above data structure.
++ */
++ MTK_VENDOR_ATTR_MU_CTRL_STRUCT,
+
+ /* keep last */
+ NUM_MTK_VENDOR_ATTRS_MU_CTRL,
+@@ -278,8 +281,163 @@ struct amnt_resp_data {
+ };
+
+ enum {
++ MU_CTRL_UPDATE,
+ MU_CTRL_ONOFF,
+- MU_CTRL_DL_USER_CNT,
+- MU_CTRL_UL_USER_CNT,
+ };
++
++struct connac3_muru_comm {
++ u8 pda_pol;
++ u8 band;
++ u8 spe_idx;
++ u8 proc_type;
++
++ le16 mlo_ctrl;
++ u8 sch_type;
++ u8 ppdu_format;
++ u8 ac;
++ u8 _rsv[3];
++};
++
++struct connac3_muru_dl {
++ u8 user_num;
++ u8 tx_mode;
++ u8 bw;
++ u8 gi;
++
++ u8 ltf;
++ u8 mcs;
++ u8 dcm;
++ u8 cmprs;
++
++ le16 ru[16];
++
++ u8 c26[2];
++ u8 ack_policy;
++ u8 tx_power;
++
++ le16 mu_ppdu_duration;
++ u8 agc_disp_order;
++ u8 _rsv1;
++
++ u8 agc_disp_pol;
++ u8 agc_disp_ratio;
++ le16 agc_disp_linkMFG;
++
++ le16 prmbl_punc_bmp;
++ u8 _rsv2[2];
++
++ struct {
++ le16 wlan_idx;
++ u8 ru_alloc_seg;
++ u8 ru_idx;
++ u8 ldpc;
++ u8 nss;
++ u8 mcs;
++ u8 mu_group_idx;
++ u8 vht_groud_id;
++ u8 vht_up;
++ u8 he_start_stream;
++ u8 he_mu_spatial;
++ le16 tx_power_alpha;
++ u8 ack_policy;
++ u8 ru_allo_ps160;
++ } usr[16];
++};
++
++struct connac3_muru_ul {
++ u8 user_num;
++ u8 tx_mode;
++
++ u8 ba_type;
++ u8 _rsv;
++
++ u8 bw;
++ u8 gi_ltf;
++ le16 ul_len;
++
++ le16 trig_cnt;
++ u8 pad;
++ u8 trig_type;
++
++ le16 trig_intv;
++ u8 trig_ta[ETH_ALEN];
++ le16 ul_ru[16];
++
++ u8 c26[2];
++ le16 agc_disp_linkMFG;
++
++ u8 agc_disp_mu_len;
++ u8 agc_disp_pol;
++ u8 agc_disp_ratio;
++ u8 agc_disp_pu_idx;
++
++ struct {
++ le16 wlan_idx;
++ u8 ru_alloc_seg;
++ u8 ru_idx;
++ u8 ldpc;
++ u8 nss;
++ u8 mcs;
++ u8 target_rssi;
++ le32 trig_pkt_size;
++ u8 ru_allo_ps160;
++ u8 _rsv2[3];
++ } usr[16];
++};
++
++struct connac3_muru_dbg {
++ /* HE TB RX Debug */
++ le32 rx_hetb_nonsf_en_bitmap;
++ le32 rx_hetb_cfg[2];
++};
++
++struct connac3_muru {
++ le32 cfg_comm;
++ le32 cfg_dl;
++ le32 cfg_ul;
++ le32 cfg_dbg;
++
++ struct connac3_muru_comm comm;
++ struct connac3_muru_dl dl;
++ struct connac3_muru_ul ul;
++ struct connac3_muru_dbg dbg;
++};
++
++#define MURU_OFDMA_SCH_TYPE_DL BIT(0)
++#define MURU_OFDMA_SCH_TYPE_UL BIT(1)
++#define MURU_PPDU_HE_TRIG BIT(2)
++#define MURU_PPDU_HE_MU BIT(3)
++
++/* Common Config */
++#define MURU_COMM_PPDU_FMT BIT(0)
++#define MURU_COMM_BAND BIT(2)
++#define MURU_COMM_WMM BIT(3)
++#define MURU_COMM_SPE_IDX BIT(4)
++#define MURU_COMM_SET (MURU_COMM_PPDU_FMT | MURU_COMM_BAND | \
++ MURU_COMM_WMM | MURU_COMM_SPE_IDX)
++
++/* DL Common config */
++#define MURU_FIXED_DL_BW BIT(0)
++#define MURU_FIXED_DL_GI BIT(1)
++#define MURU_FIXED_DL_TONE_PLAN BIT(3)
++#define MURU_FIXED_DL_TOTAL_USER_CNT BIT(4)
++#define MURU_FIXED_DL_LTF BIT(5)
++#define MURU_FIXED_DL_ACK_PLY BIT(9)
++
++/* DL Per User Config */
++#define MURU_FIXED_USER_DL_COD BIT(17)
++#define MURU_FIXED_USER_DL_MCS BIT(18)
++#define MURU_FIXED_USER_DL_RU_ALLOC BIT(20)
++
++/* UL Common Config */
++#define MURU_FIXED_UL_TOTAL_USER_CNT BIT(4)
++#define MURU_FIXED_UL_BW BIT(5)
++#define MURU_FIXED_UL_GILTF BIT(6)
++
++/* UL Per User Config */
++#define MURU_FIXED_USER_UL_COD BIT(18)
++#define MURU_FIXED_USER_UL_MCS BIT(19)
++#define MURU_FIXED_USER_UL_NSS BIT(20)
++#define MURU_FIXED_USER_UL_RU_ALLOC BIT(21)
++
+ #endif /* MTK_VENDOR_H */
+diff --git a/src/drivers/driver.h b/src/drivers/driver.h
+index c8910739e..6fc79f659 100644
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -5266,7 +5266,7 @@ struct wpa_driver_ops {
+ * @priv: Private driver interface data
+ *
+ */
+- int (*mu_ctrl)(void *priv, u8 mode, u8 val);
++ int (*mu_ctrl)(void *priv, u8 mode, void *config);
+ int (*mu_dump)(void *priv, u8 *mu_onoff);
+
+ /**
+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
+index da1e6a8ed..8a8f8abe8 100644
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -14007,12 +14007,13 @@ fail:
+
+
+ #ifdef CONFIG_IEEE80211AX
+-static int nl80211_mu_ctrl(void *priv, u8 mode, u8 val)
++static int nl80211_mu_ctrl(void *priv, u8 mode, void *config)
+ {
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *data;
++ struct hostapd_config *cfg = config;
+ int ret = -ENOBUFS;
+
+ if (!drv->mtk_mu_vendor_cmd_avail) {
+@@ -14029,17 +14030,16 @@ static int nl80211_mu_ctrl(void *priv, u8 mode, u8 val)
+
+ switch (mode) {
+ case MU_CTRL_ONOFF:
+- if (nla_put_u8(msg, MTK_VENDOR_ATTR_MU_CTRL_ONOFF, val))
+- goto fail;
++ if (nla_put_u8(msg, MTK_VENDOR_ATTR_MU_CTRL_ONOFF, cfg->mu_onoff))
++ goto fail;
+ break;
+- case MU_CTRL_UL_USER_CNT:
+- case MU_CTRL_DL_USER_CNT:
+- if (nla_put_u8(msg, MTK_VENDOR_ATTR_MU_CTRL_OFDMA_MODE, mode) ||
+- nla_put_u8(msg, MTK_VENDOR_ATTR_MU_CTRL_OFDMA_VAL, val))
+- goto fail;
++ case MU_CTRL_UPDATE:
++ if (nla_put(msg, MTK_VENDOR_ATTR_MU_CTRL_STRUCT,
++ sizeof(struct connac3_muru), cfg->muru_config))
++ goto fail;
+ break;
+ default:
+- wpa_printf(MSG_ERROR, "nl80211: Wrong mu mode !");
++ wpa_printf(MSG_ERROR, "nl80211: Wrong mu mode %u!", mode);
+ ret = -EINVAL;
+ goto fail;
+ }
+@@ -14047,9 +14047,8 @@ static int nl80211_mu_ctrl(void *priv, u8 mode, u8 val)
+ nla_nest_end(msg, data);
+
+ ret = send_and_recv_cmd(drv, msg);
+- if(ret){
++ if (ret)
+ wpa_printf(MSG_ERROR, "Failed to set mu_ctrl. ret=%d (%s)", ret, strerror(-ret));
+- }
+ return ret;
+
+ fail:
+--
+2.18.0
+