[rdkb][common][bsp][Refactor and sync wifi from openwrt]
[Description]
ac60b1ff [MAC80211][misc][Add Filogic 880/860/830/820/630 Release Information]
7eb946a0 [MAC80211][WiFi7][hostapd][sync hostapd patches]
91638fc9 [MAC80211][WiFi7][mac80211][sync backports code]
8e45746b [MAC80211][WiFi7][mt76][sync mt76 patches]
1c564afa [MAC80211][WiFi7][mt76][Add Eagle BE19000 ifem default bin]
[Release-log]
Change-Id: I1d4218d3b1211700acb5937fe310cbd0bf219968
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/0033-mtk-hostapd-Support-EDCCA-hostapd-configuration.patch b/recipes-wifi/hostapd/files/patches-2.10.3/0033-mtk-hostapd-Support-EDCCA-hostapd-configuration.patch
new file mode 100644
index 0000000..d7544bc
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/0033-mtk-hostapd-Support-EDCCA-hostapd-configuration.patch
@@ -0,0 +1,630 @@
+From 7b735e95647fe46cc5dcf7d859c8f9abbed5ae0d Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Mon, 30 May 2022 16:31:34 +0800
+Subject: [PATCH 033/104] mtk: hostapd: Support EDCCA hostapd configuration
+
+edcca_enable and edcca_compensation and implement edcca related handlers.
+---
+ hostapd/config_file.c | 34 ++++++
+ hostapd/ctrl_iface.c | 124 +++++++++++++++++++++
+ src/ap/ap_config.c | 4 +
+ src/ap/ap_config.h | 30 ++++++
+ src/ap/ap_drv_ops.c | 24 +++++
+ src/ap/ap_drv_ops.h | 4 +
+ src/ap/hostapd.c | 7 ++
+ src/common/mtk_vendor.h | 20 ++--
+ src/drivers/driver.h | 4 +
+ src/drivers/driver_nl80211.c | 174 ++++++++++++++++++++++++++++++
+ src/drivers/driver_nl80211.h | 1 +
+ src/drivers/driver_nl80211_capa.c | 7 ++
+ 12 files changed, 427 insertions(+), 6 deletions(-)
+
+diff --git a/hostapd/config_file.c b/hostapd/config_file.c
+index 0094db279..f8c1eec0a 100644
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -5348,6 +5348,40 @@ static int hostapd_config_fill(struct hostapd_config *conf,
+ bss->mld_indicate_disabled = atoi(pos);
+ #endif /* CONFIG_TESTING_OPTIONS */
+ #endif /* CONFIG_IEEE80211BE */
++ } else if (os_strcmp(buf, "edcca_threshold") == 0) {
++ if (hostapd_parse_intlist(&conf->edcca_threshold, pos) ||
++ conf->edcca_threshold[0] < EDCCA_MIN_CONFIG_THRES ||
++ conf->edcca_threshold[0] > EDCCA_MAX_CONFIG_THRES ||
++ conf->edcca_threshold[1] < EDCCA_MIN_CONFIG_THRES ||
++ conf->edcca_threshold[1] > EDCCA_MAX_CONFIG_THRES ||
++ conf->edcca_threshold[2] < EDCCA_MIN_CONFIG_THRES ||
++ conf->edcca_threshold[2] > EDCCA_MAX_CONFIG_THRES ||
++ conf->edcca_threshold[3] < EDCCA_MIN_CONFIG_THRES ||
++ conf->edcca_threshold[3] > EDCCA_MAX_CONFIG_THRES) {
++ wpa_printf(MSG_ERROR, "Line %d: invalid edcca threshold",
++ line);
++ return 1;
++ }
++ } else if (os_strcmp(buf, "edcca_enable") == 0) {
++ int mode = atoi(pos);
++ if (mode < EDCCA_MODE_FORCE_DISABLE || mode > EDCCA_MODE_AUTO) {
++ wpa_printf(MSG_ERROR, "Line %d: Invalid edcca_enable %d;"
++ " allowed value 0 (Force Disable) or 1(Auto) ",
++ line, mode);
++ return 1;
++ }
++ conf->edcca_enable = (u8) mode;
++ } else if (os_strcmp(buf, "edcca_compensation") == 0) {
++ int val = atoi(pos);
++ if (val < EDCCA_MIN_COMPENSATION ||
++ val > EDCCA_MAX_COMPENSATION) {
++ wpa_printf(MSG_ERROR, "Line %d: Invalid compensation"
++ " value %d; allowed value %d ~ %d.",
++ line, val, EDCCA_MIN_COMPENSATION,
++ EDCCA_MAX_COMPENSATION);
++ return 1;
++ }
++ conf->edcca_compensation = (s8) val;
+ } else {
+ wpa_printf(MSG_ERROR,
+ "Line %d: unknown configuration item '%s'",
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index fb9f09bb1..78a3380f2 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -544,6 +544,19 @@ static const char * pbc_status_str(enum pbc_status status)
+ }
+
+
++static const char *edcca_mode_str(enum edcca_mode status)
++{
++ switch (status) {
++ case EDCCA_MODE_FORCE_DISABLE:
++ return "Force Disable";
++ case EDCCA_MODE_AUTO:
++ return "Auto";
++ default:
++ return "Unknown";
++ }
++}
++
++
+ static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+ {
+@@ -3644,6 +3657,111 @@ static int hostapd_ctrl_iface_link_remove(struct hostapd_data *hapd, char *cmd,
+ #endif /* CONFIG_TESTING_OPTIONS */
+ #endif /* CONFIG_IEEE80211BE */
+
++static int
++hostapd_ctrl_iface_set_edcca(struct hostapd_data *hapd, char *cmd,
++ char *buf, size_t buflen)
++{
++ char *pos, *config, *value;
++ config = cmd;
++ pos = os_strchr(config, ' ');
++ if (pos == NULL)
++ return -1;
++ *pos++ = '\0';
++
++ if (pos == NULL)
++ return -1;
++ value = pos;
++
++ if (os_strcmp(config, "enable") == 0) {
++ int mode = atoi(value);
++ if (mode < EDCCA_MODE_FORCE_DISABLE || mode > EDCCA_MODE_AUTO) {
++ wpa_printf(MSG_ERROR, "Invalid value for edcca enable");
++ return -1;
++ }
++ hapd->iconf->edcca_enable = (u8) mode;
++ if (hostapd_drv_configure_edcca_enable(hapd) != 0)
++ return -1;
++ } else if (os_strcmp(config, "compensation") == 0) {
++ int compensation = atoi(value);
++ if (compensation < EDCCA_MIN_COMPENSATION ||
++ compensation > EDCCA_MAX_COMPENSATION) {
++ wpa_printf(MSG_ERROR, "Invalid value for edcca compensation");
++ return -1;
++ }
++ hapd->iconf->edcca_compensation = (s8) compensation;
++ if (hostapd_drv_configure_edcca_enable(hapd) != 0)
++ return -1;
++ } else if (os_strcmp(config, "threshold") == 0) {
++ char *thres_value;
++ thres_value = os_strchr(value, ':');
++ if (thres_value == NULL)
++ return -1;
++ *thres_value++ = '\0';
++
++ if (thres_value == NULL)
++ return -1;
++ int bw_idx = atoi(value);
++ int threshold = atoi(thres_value);
++
++ if (bw_idx < EDCCA_BW_20 || bw_idx > EDCCA_BW_160) {
++ wpa_printf(MSG_ERROR,
++ "Unsupported Bandwidth idx %d for SET_EDCCA",
++ bw_idx);
++ return -1;
++ }
++ if (threshold < EDCCA_MIN_CONFIG_THRES ||
++ threshold > EDCCA_MAX_CONFIG_THRES) {
++ wpa_printf(MSG_ERROR,
++ "Unsupported threshold %d for SET_EDCCA",
++ threshold);
++ return -1;
++ }
++
++ int threshold_arr[EDCCA_MAX_BW_NUM];
++ /* 0x7f means keep the origival value in firmware */
++ os_memset(threshold_arr, 0x7f, sizeof(threshold_arr));
++ threshold_arr[bw_idx] = threshold;
++
++ if (hostapd_drv_configure_edcca_threshold(hapd, threshold_arr) != 0)
++ return -1;
++ } else {
++ wpa_printf(MSG_ERROR,
++ "Unsupported parameter %s for SET_EDCCA", config);
++ return -1;
++ }
++ return os_snprintf(buf, buflen, "OK\n");
++}
++
++
++static int
++hostapd_ctrl_iface_get_edcca(struct hostapd_data *hapd, char *cmd, char *buf,
++ size_t buflen)
++{
++ char *pos, *end;
++
++ pos = buf;
++ end = buf + buflen;
++ u8 value[EDCCA_MAX_BW_NUM] = {0};
++
++ if (os_strcmp(cmd, "enable") == 0) {
++ return os_snprintf(pos, end - pos, "Enable: %s\n",
++ edcca_mode_str(hapd->iconf->edcca_enable));
++ } else if (os_strcmp(cmd, "compensation") == 0) {
++ return os_snprintf(pos, end - pos, "Compensation: %d\n",
++ hapd->iconf->edcca_compensation);
++ } else if (os_strcmp(cmd, "threshold") == 0) {
++ if (hostapd_drv_get_edcca(hapd, EDCCA_CTRL_GET_THRES, &value) != 0)
++ return -1;
++ return os_snprintf(pos, end - pos,
++ "Threshold BW20: 0x%x, BW40: 0x%x, BW80: 0x%x, BW160: 0x%x\n",
++ value[0], value[1], value[2], value[3]);
++ } else {
++ wpa_printf(MSG_ERROR,
++ "Unsupported parameter %s for GET_EDCCA", cmd);
++ return -1;
++ }
++}
++
+
+ #ifdef CONFIG_NAN_USD
+
+@@ -4531,6 +4649,12 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ reply_len = -1;
+ #endif /* CONFIG_TESTING_OPTIONS */
+ #endif /* CONFIG_IEEE80211BE */
++ } else if (os_strncmp(buf, "SET_EDCCA ", 10) == 0) {
++ reply_len = hostapd_ctrl_iface_set_edcca(hapd, buf+10, reply,
++ reply_size);
++ } else if (os_strncmp(buf, "GET_EDCCA ", 10) == 0) {
++ reply_len = hostapd_ctrl_iface_get_edcca(hapd, buf+10, reply,
++ reply_size);
+ } else {
+ os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+ reply_len = 16;
+diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
+index 6c8b10291..965600577 100644
+--- a/src/ap/ap_config.c
++++ b/src/ap/ap_config.c
+@@ -303,6 +303,9 @@ struct hostapd_config * hostapd_config_defaults(void)
+ conf->airtime_update_interval = AIRTIME_DEFAULT_UPDATE_INTERVAL;
+ #endif /* CONFIG_AIRTIME_POLICY */
+
++ conf->edcca_enable = EDCCA_MODE_AUTO;
++ conf->edcca_compensation = EDCCA_DEFAULT_COMPENSATION;
++
+ hostapd_set_and_check_bw320_offset(conf, 0);
+
+ return conf;
+@@ -1034,6 +1037,7 @@ void hostapd_config_free(struct hostapd_config *conf)
+ #ifdef CONFIG_ACS
+ os_free(conf->acs_chan_bias);
+ #endif /* CONFIG_ACS */
++ os_free(conf->edcca_threshold);
+ wpabuf_free(conf->lci);
+ wpabuf_free(conf->civic);
+ #ifdef CONFIG_AFC
+diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
+index 379dc22cf..09718fada 100644
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
+@@ -1281,8 +1281,38 @@ struct hostapd_config {
+ int min_power;
+ } afc;
+ #endif /* CONFIG_AFC */
++
++ u8 edcca_enable;
++ s8 edcca_compensation;
++ int *edcca_threshold;
++};
++
++enum edcca_mode {
++ EDCCA_MODE_FORCE_DISABLE = 0,
++ EDCCA_MODE_AUTO = 1,
++};
++
++enum edcca_bw_id {
++ EDCCA_BW_20 = 0,
++ EDCCA_BW_40,
++ EDCCA_BW_80,
++ EDCCA_BW_160,
++ EDCCA_MAX_BW_NUM,
++};
++
++enum mtk_vendor_attr_edcca_ctrl_mode {
++ EDCCA_CTRL_SET_EN = 0,
++ EDCCA_CTRL_SET_THRES,
++ EDCCA_CTRL_GET_EN,
++ EDCCA_CTRL_GET_THRES,
++ EDCCA_CTRL_NUM,
+ };
+
++#define EDCCA_DEFAULT_COMPENSATION -6
++#define EDCCA_MIN_COMPENSATION -126
++#define EDCCA_MAX_COMPENSATION 126
++#define EDCCA_MIN_CONFIG_THRES -126
++#define EDCCA_MAX_CONFIG_THRES 0
+
+ static inline enum oper_chan_width
+ hostapd_get_oper_chwidth(struct hostapd_config *conf)
+diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
+index 527b2c984..a6caf6a73 100644
+--- a/src/ap/ap_drv_ops.c
++++ b/src/ap/ap_drv_ops.c
+@@ -1245,3 +1245,27 @@ int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
+ return hapd->driver->set_secure_ranging_ctx(hapd->drv_priv, ¶ms);
+ }
+ #endif /* CONFIG_PASN */
++
++int hostapd_drv_configure_edcca_enable(struct hostapd_data *hapd)
++{
++ if (!hapd->driver || !hapd->driver->configure_edcca_enable)
++ return 0;
++ return hapd->driver->configure_edcca_enable(hapd->drv_priv,
++ hapd->iconf->edcca_enable,
++ hapd->iconf->edcca_compensation);
++}
++
++int hostapd_drv_configure_edcca_threshold(struct hostapd_data *hapd,
++ const int *threshold)
++{
++ if (!hapd->driver || !hapd->driver->configure_edcca_threshold)
++ return 0;
++ return hapd->driver->configure_edcca_threshold(hapd->drv_priv, threshold);
++}
++
++int hostapd_drv_get_edcca(struct hostapd_data *hapd, const u8 mode, u8 *value)
++{
++ if (!hapd->driver || !hapd->driver->get_edcca)
++ return 0;
++ return hapd->driver->get_edcca(hapd->drv_priv, mode, value);
++}
+diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
+index f8a8725be..98836153f 100644
+--- a/src/ap/ap_drv_ops.h
++++ b/src/ap/ap_drv_ops.h
+@@ -149,6 +149,10 @@ int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
+ u8 ltf_keyseed_len,
+ const u8 *ltf_keyseed, u32 action);
+
++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);
+
+ #include "drivers/driver.h"
+
+diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
+index 7959859b0..6af31179e 100644
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -2693,6 +2693,13 @@ dfs_offload:
+ }
+ #endif /* CONFIG_MESH */
+
++ if (hostapd_drv_configure_edcca_enable(hapd) < 0)
++ goto fail;
++
++ if (hostapd_drv_configure_edcca_threshold(hapd,
++ hapd->iconf->edcca_threshold) < 0)
++ goto fail;
++
+ wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
+ iface->bss[0]->conf->iface);
+ if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
+diff --git a/src/common/mtk_vendor.h b/src/common/mtk_vendor.h
+index 4a19d2fc9..6121857dd 100644
+--- a/src/common/mtk_vendor.h
++++ b/src/common/mtk_vendor.h
+@@ -30,14 +30,22 @@ enum mtk_vendor_attr_edcca_ctrl {
+ NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL - 1
+ };
+
+-enum mtk_vendor_attr_edcca_ctrl_mode {
+- EDCCA_CTRL_SET_EN = 0,
+- EDCCA_CTRL_SET_THERS,
+- EDCCA_CTRL_GET_EN,
+- EDCCA_CTRL_GET_THERS,
+- EDCCA_CTRL_NUM,
++enum mtk_vendor_attr_edcca_dump {
++ MTK_VENDOR_ATTR_EDCCA_DUMP_UNSPEC = 0,
++
++ MTK_VENDOR_ATTR_EDCCA_DUMP_MODE,
++ MTK_VENDOR_ATTR_EDCCA_DUMP_PRI20_VAL,
++ MTK_VENDOR_ATTR_EDCCA_DUMP_SEC40_VAL,
++ MTK_VENDOR_ATTR_EDCCA_DUMP_SEC80_VAL,
++ MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL,
++
++ /* keep last */
++ NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP,
++ MTK_VENDOR_ATTR_EDCCA_DUMP_MAX =
++ NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP - 1
+ };
+
++
+ static struct nla_policy edcca_ctrl_policy[NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL] = {
+ [MTK_VENDOR_ATTR_EDCCA_CTRL_MODE] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL] = { .type = NLA_U8 },
+diff --git a/src/drivers/driver.h b/src/drivers/driver.h
+index 3e3e309f4..ed5f5c013 100644
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -5220,6 +5220,10 @@ struct wpa_driver_ops {
+ const u8 *match, size_t match_len,
+ bool multicast);
+ #endif /* CONFIG_TESTING_OPTIONS */
++ int (*configure_edcca_enable)(void *priv, const u8 edcca_enable,
++ const s8 edcca_compensation);
++ int (*configure_edcca_threshold)(void *priv, const int *threshold);
++ int (*get_edcca)(void *priv, const u8 mode, u8 *value);
+ };
+
+ /**
+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
+index 501d0e42e..d59efe8b6 100644
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -42,6 +42,8 @@
+ #include "radiotap_iter.h"
+ #include "rfkill.h"
+ #include "driver_nl80211.h"
++#include "common/mtk_vendor.h"
++#include "ap/ap_config.h"
+
+
+ #ifndef NETLINK_CAP_ACK
+@@ -14079,6 +14081,174 @@ static int testing_nl80211_radio_disable(void *priv, int disabled)
+
+ #endif /* CONFIG_TESTING_OPTIONS */
+
++static int nl80211_configure_edcca_enable(void *priv,
++ const u8 edcca_enable,
++ const s8 edcca_compensation)
++{
++ struct i802_bss *bss = priv;
++ struct wpa_driver_nl80211_data *drv = bss->drv;
++ struct nl_msg *msg;
++ struct nlattr *data;
++ int ret;
++
++ if (!drv->mtk_edcca_vendor_cmd_avail) {
++ wpa_printf(MSG_INFO,
++ "nl80211: Driver does not support setting EDCCA enable");
++ return 0;
++ }
++
++ if (!(msg = nl80211_drv_msg(drv, 0, 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_EDCCA_CTRL) ||
++ !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
++ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_MODE, EDCCA_CTRL_SET_EN) ||
++ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL, edcca_enable) ||
++ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_COMPENSATE,
++ edcca_compensation)) {
++ wpa_printf (MSG_ERROR, "Prepare nl80211 msg fail");
++ nlmsg_free(msg);
++ return -ENOBUFS;
++ }
++ nla_nest_end(msg, data);
++ ret = send_and_recv_cmd(drv, msg);
++ if (ret) {
++ wpa_printf(MSG_ERROR, "Failed to configure EDCCA enable. ret=%d (%s) ",
++ ret, strerror(-ret));
++ }
++ return ret;
++}
++
++static int nl80211_configure_edcca_threshold(void *priv, const int *threshold)
++{
++ struct i802_bss *bss = priv;
++ struct wpa_driver_nl80211_data *drv = bss->drv;
++ struct nl_msg *msg;
++ struct nlattr *data;
++ int ret;
++
++ if (!drv->mtk_edcca_vendor_cmd_avail) {
++ wpa_printf(MSG_INFO,
++ "nl80211: Driver does not support setting EDCCA threshold");
++ return 0;
++ }
++
++ if (!threshold) {
++ wpa_printf(MSG_INFO,
++ "nl80211: Input EDCCA threshold is empty!");
++ return 0;
++ }
++
++ if (!(msg = nl80211_drv_msg(drv, 0, 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_EDCCA_CTRL) ||
++ !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
++ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_MODE, EDCCA_CTRL_SET_THRES) ||
++ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL, threshold[0] & 0xff) ||
++ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_SEC40_VAL, threshold[1] & 0xff) ||
++ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_SEC80_VAL, threshold[2] & 0xff) ||
++ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_SEC160_VAL, threshold[3] & 0xff)) {
++ wpa_printf (MSG_ERROR, "Prepare nl80211 msg fail");
++ nlmsg_free(msg);
++ return -ENOBUFS;
++ }
++ nla_nest_end(msg, data);
++ ret = send_and_recv_cmd(drv, msg);
++ if (ret) {
++ wpa_printf(MSG_ERROR, "Failed to configure EDCCA threshold. ret=%d (%s) ",
++ ret, strerror(-ret));
++ }
++ return ret;
++}
++
++
++static int edcca_info_handler(struct nl_msg *msg, void *arg)
++{
++ u8 *info = (u8 *) arg;
++ struct nlattr *tb[NL80211_ATTR_MAX + 1];
++ struct nlattr *tb_vendor[MTK_VENDOR_ATTR_EDCCA_DUMP_MAX + 1];
++ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
++ struct nlattr *nl_vend, *attr;
++
++ 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_EDCCA_DUMP_MAX,
++ nla_data(nl_vend), nla_len(nl_vend), NULL);
++
++ attr = tb_vendor[MTK_VENDOR_ATTR_EDCCA_DUMP_PRI20_VAL];
++ if (!attr) {
++ wpa_printf(MSG_ERROR, "nl80211: MTK_VENDOR_ATTR_EDCCA_DUMP_PRI20_VAL");
++ return NL_SKIP;
++ }
++
++ *info++ = nla_get_u8(attr);
++
++ attr = tb_vendor[MTK_VENDOR_ATTR_EDCCA_DUMP_SEC40_VAL];
++ if (!attr) {
++ wpa_printf(MSG_ERROR, "nl80211: MTK_VENDOR_ATTR_EDCCA_DUMP_SEC40_VAL");
++ return NL_SKIP;
++ }
++
++ *info++ = nla_get_u8(attr);
++
++ attr = tb_vendor[MTK_VENDOR_ATTR_EDCCA_DUMP_SEC80_VAL];
++ if (!attr) {
++ wpa_printf(MSG_ERROR, "nl80211: MTK_VENDOR_ATTR_EDCCA_DUMP_SEC80_VAL");
++ return NL_SKIP;
++ }
++
++ *info++ = nla_get_u8(attr);
++
++ attr = tb_vendor[MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL];
++ if (!attr) {
++ wpa_printf(MSG_ERROR, "nl80211: MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL");
++ return NL_SKIP;
++ }
++
++ *info = nla_get_u8(attr);
++ return NL_SKIP;
++}
++
++
++static int nl80211_get_edcca(void *priv, const u8 mode, u8 *value)
++{
++ struct i802_bss *bss = priv;
++ struct wpa_driver_nl80211_data *drv = bss->drv;
++ struct nl_msg *msg;
++ struct nlattr *data;
++ int ret;
++
++ if (!drv->mtk_edcca_vendor_cmd_avail) {
++ wpa_printf(MSG_INFO,
++ "nl80211: Driver does not support setting EDCCA threshold");
++ 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_EDCCA_CTRL) ||
++ !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED)) ||
++ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_MODE, mode)) {
++ wpa_printf (MSG_ERROR, "Prepare nl80211 msg fail");
++ nlmsg_free(msg);
++ return -ENOBUFS;
++ }
++ nla_nest_end(msg, data);
++ ret = send_and_recv_resp(drv, msg, edcca_info_handler, value);
++ if (ret) {
++ wpa_printf(MSG_ERROR, "Failed to get EDCCA configuration. ret=%d (%s)",
++ ret, strerror(-ret));
++ }
++ return ret;
++}
++
+
+ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+ .name = "nl80211",
+@@ -14240,4 +14410,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+ .register_frame = testing_nl80211_register_frame,
+ .radio_disable = testing_nl80211_radio_disable,
+ #endif /* CONFIG_TESTING_OPTIONS */
++/* Need ifdef CONFIG_DRIVER_NL80211_MTK */
++ .configure_edcca_enable = nl80211_configure_edcca_enable,
++ .configure_edcca_threshold = nl80211_configure_edcca_threshold,
++ .get_edcca = nl80211_get_edcca,
+ };
+diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
+index 618746e67..62c47efbd 100644
+--- a/src/drivers/driver_nl80211.h
++++ b/src/drivers/driver_nl80211.h
+@@ -200,6 +200,7 @@ struct wpa_driver_nl80211_data {
+ unsigned int secure_ranging_ctx_vendor_cmd_avail:1;
+ unsigned int puncturing:1;
+ unsigned int qca_ap_allowed_freqs:1;
++ unsigned int mtk_edcca_vendor_cmd_avail:1;
+
+ u32 ignore_next_local_disconnect;
+ u32 ignore_next_local_deauth;
+diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
+index d6a887cef..cd4d799a1 100644
+--- a/src/drivers/driver_nl80211_capa.c
++++ b/src/drivers/driver_nl80211_capa.c
+@@ -18,6 +18,7 @@
+ #include "common/qca-vendor-attr.h"
+ #include "common/brcm_vendor.h"
+ #include "driver_nl80211.h"
++#include "common/mtk_vendor.h"
+
+
+ static int protocol_feature_handler(struct nl_msg *msg, void *arg)
+@@ -1138,6 +1139,12 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+ break;
+ }
+ #endif /* CONFIG_DRIVER_NL80211_BRCM */
++ } else if (vinfo->vendor_id == OUI_MTK) {
++ switch (vinfo->subcmd) {
++ case MTK_NL80211_VENDOR_SUBCMD_EDCCA_CTRL:
++ drv->mtk_edcca_vendor_cmd_avail = 1;
++ break;
++ }
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
+--
+2.39.2
+