[][MAC80211][hostapd][Add mtk vendor subcmd EDCCA control]
[Description]
Add vendor command to control EDCCA enable/threshold/compensation.
Support three configuration into hostapd configuration file.
1. edcca_enable=0
2. edcca_compensation=5
3. edcca_threhols=xx yy zz
The config "edcca_enable" is used to config the opeation mode of EDCCA.
The value 0 means force disable and 1 means auto mode.
The config "edcca_compensation" is used to adjust the EDCCA threshold.
Please noted that compensate value is only applied for 6g band
interface.
The config "edcca_threshold" is used to config EDCCA threhsold when
interface up.
hostapd_cli command usage:
hostapd_cli -i <interface> raw SET_EDCCA [mode|compensation|threshold]
[value]
* This command is used to configure EDCCA mode, compensatation or
* threshold.
hostapd_cli -i <interface> raw GET_EDCCA [mode|compensation|threshold]
* This command is used to check current EDCCA configuration in hostapd.
[Release-log]
N/A
Change-Id: Iefe6e82a35fb22ad8c1a87bf50bc6ad60d61fa32
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/6756359
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/99912-hostapd-mtk-Support-new-hostapd-configuration-edcca_enable-and-.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/99912-hostapd-mtk-Support-new-hostapd-configuration-edcca_enable-and-.patch
index be54e06..be526be 100644
--- a/autobuild_mac80211_release/package/network/services/hostapd/patches/99912-hostapd-mtk-Support-new-hostapd-configuration-edcca_enable-and-.patch
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/99912-hostapd-mtk-Support-new-hostapd-configuration-edcca_enable-and-.patch
@@ -1,30 +1,44 @@
-From 166ba374624b2aed360427f087c20b8f511fb2e0 Mon Sep 17 00:00:00 2001
+From 17051f7a8b2193e24556e357f3f1665d67a79330 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 99912/99916] Support new hostapd configuration, edcca_enable
- and edcca_compensation
+Subject: [PATCH] Support new hostapd configuration, edcca_enable and
+ edcca_compensation and implement edcca related handlers.
---
- hostapd/config_file.c | 20 +++++++++++++++
- src/ap/ap_config.c | 3 +++
- src/ap/ap_config.h | 10 ++++++++
- src/ap/ap_drv_ops.c | 9 +++++++
- src/ap/ap_drv_ops.h | 2 +-
- src/ap/hostapd.c | 3 +++
- src/drivers/driver.h | 2 ++
- src/drivers/driver_nl80211.c | 42 +++++++++++++++++++++++++++++++
- src/drivers/driver_nl80211.h | 1 +
- src/drivers/driver_nl80211_capa.c | 7 ++++++
- 10 files changed, 98 insertions(+), 1 deletion(-)
+ hostapd/config_file.c | 32 ++++++
+ hostapd/ctrl_iface.c | 125 ++++++++++++++++++++++
+ src/ap/ap_config.c | 4 +
+ src/ap/ap_config.h | 29 ++++++
+ src/ap/ap_drv_ops.c | 24 +++++
+ src/ap/ap_drv_ops.h | 5 +-
+ src/ap/hostapd.c | 7 ++
+ src/common/mtk_vendor.h | 19 ++--
+ src/drivers/driver.h | 4 +
+ src/drivers/driver_nl80211.c | 165 ++++++++++++++++++++++++++++++
+ src/drivers/driver_nl80211.h | 1 +
+ src/drivers/driver_nl80211_capa.c | 7 ++
+ 12 files changed, 415 insertions(+), 7 deletions(-)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
-index eda9db021..8a21c9698 100644
+index eda9db0..0ee8952 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
-@@ -4753,6 +4753,26 @@ static int hostapd_config_fill(struct hostapd_config *conf,
+@@ -4753,6 +4753,38 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "eht_mu_beamformer") == 0) {
conf->eht_phy_capab.mu_beamformer = atoi(pos);
#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) {
++ 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) {
@@ -37,7 +51,7 @@
+ } else if (os_strcmp(buf, "edcca_compensation") == 0) {
+ int val = atoi(pos);
+ if (val < EDCCA_MIN_COMPENSATION ||
-+ val > EDCCA_MAX_COMPENSATION) {
++ val > EDCCA_MAX_COMPENSATION) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid compensation"
+ " value %d; allowed value %d ~ %d.",
+ line, val, EDCCA_MIN_COMPENSATION,
@@ -48,8 +62,158 @@
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index bb8c74f..9c70d54 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -598,6 +598,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)
+ {
+@@ -3322,6 +3335,112 @@ static int hostapd_ctrl_iface_driver_cmd(struct hostapd_data *hapd, char *cmd,
+ #endif /* ANDROID */
+
+
++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_80) {
++ 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\n",
++ value[0], value[1], value[2]);
++ } else {
++ wpa_printf(MSG_ERROR,
++ "Unsupported parameter %s for GET_EDCCA", cmd);
++ return -1;
++ }
++}
++
++
+ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ char *buf, char *reply,
+ int reply_size,
+@@ -3868,6 +3987,12 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ reply_len = hostapd_ctrl_iface_driver_cmd(hapd, buf + 7, reply,
+ reply_size);
+ #endif /* ANDROID */
++ } 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 4a20eb4e1..373879f79 100644
+index 4a20eb4..344585a 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -294,6 +294,9 @@ struct hostapd_config * hostapd_config_defaults(void)
@@ -62,16 +226,25 @@
return conf;
}
+@@ -1007,6 +1010,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);
+
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
-index 3f68e76d5..3ac2ae070 100644
+index 3f68e76..775c567 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
-@@ -1153,8 +1153,18 @@ struct hostapd_config {
+@@ -1153,8 +1153,37 @@ struct hostapd_config {
#define CH_SWITCH_EHT_ENABLED BIT(0)
#define CH_SWITCH_EHT_DISABLED BIT(1)
unsigned int ch_switch_eht_config;
+ u8 edcca_enable;
+ s8 edcca_compensation;
++ int *edcca_threshold;
};
+enum edcca_mode {
@@ -79,99 +252,173 @@
+ EDCCA_MODE_AUTO = 1,
+};
+
++enum edcca_bw_id {
++ EDCCA_BW_20 = 0,
++ EDCCA_BW_40,
++ EDCCA_BW_80,
++ 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 0c7aee276..5d2d79c38 100644
+index 0c7aee2..25e967d 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
-@@ -1015,3 +1015,12 @@ int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable)
+@@ -1015,3 +1015,27 @@ int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable)
return 0;
return hapd->driver->dpp_listen(hapd->drv_priv, enable);
}
+
-+int hostapd_drv_configure_edcca_threshold(struct hostapd_data *hapd)
++int hostapd_drv_configure_edcca_enable(struct hostapd_data *hapd)
+{
-+ if (!hapd->driver || !hapd->driver->configure_edcca_threshold)
++ if (!hapd->driver || !hapd->driver->configure_edcca_enable)
+ return 0;
-+ return hapd->driver->configure_edcca_threshold(hapd->drv_priv,
++ 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 b4fb766ee..f8fef1929 100644
+index b4fb766..70a99f4 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
-@@ -138,7 +138,7 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd);
+@@ -138,7 +138,10 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd);
int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
u16 reason_code, const u8 *ie, size_t ielen);
int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable);
-
-+int hostapd_drv_configure_edcca_threshold(struct hostapd_data *hapd);
++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 0dd8c13b7..6babb036a 100644
+index 0dd8c13..d05f948 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
-@@ -2295,6 +2295,9 @@ dfs_offload:
+@@ -2295,6 +2295,13 @@ dfs_offload:
}
#endif /* CONFIG_MESH */
-+ if (hostapd_drv_configure_edcca_threshold(hapd) < 0)
++ 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 528387f..7056126 100644
+--- a/src/common/mtk_vendor.h
++++ b/src/common/mtk_vendor.h
+@@ -29,14 +29,21 @@ 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,
++
++ /* 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 1d2b1b265..575448a93 100644
+index 1d2b1b2..3559974 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
-@@ -4676,6 +4676,8 @@ struct wpa_driver_ops {
+@@ -4676,6 +4676,10 @@ struct wpa_driver_ops {
const u8 *match, size_t match_len,
bool multicast);
#endif /* CONFIG_TESTING_OPTIONS */
-+ int (*configure_edcca_threshold)(void *priv, const u8 edcca_enable,
++ 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 5eba0ea1b..76680dfd3 100644
+index 5eba0ea..9c2782c 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
-@@ -35,6 +35,7 @@
+@@ -35,6 +35,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
-@@ -12368,6 +12369,45 @@ static int testing_nl80211_radio_disable(void *priv, int disabled)
+@@ -12368,6 +12370,165 @@ static int testing_nl80211_radio_disable(void *priv, int disabled)
#endif /* CONFIG_TESTING_OPTIONS */
-+static int nl80211_configure_edcca_threshold(void *priv,
-+ const u8 edcca_enable,
-+ const s8 edcca_compensation)
++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;
-+ /* Prepare nl80211 cmd */
+ 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");
++ "nl80211: Driver does not support setting EDCCA enable");
+ return 0;
+ }
+
@@ -191,7 +438,128 @@
+ nla_nest_end(msg, data);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ 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)) {
++ wpa_printf (MSG_ERROR, "Prepare nl80211 msg fail");
++ nlmsg_free(msg);
++ return -ENOBUFS;
++ }
++ nla_nest_end(msg, data);
++ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
++ 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);
++ 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_msgs(drv, msg, edcca_info_handler, value, NULL, NULL);
++ if (ret) {
-+ wpa_printf(MSG_ERROR, "Failed to configure EDCCA. ret=%d (%s) ",
++ wpa_printf(MSG_ERROR, "Failed to get EDCCA configuration. ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+ return ret;
@@ -200,15 +568,17 @@
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
-@@ -12514,4 +12554,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+@@ -12514,4 +12675,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 6e40d5556..13e5d248c 100644
+index 6e40d55..13e5d24 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -181,6 +181,7 @@ struct wpa_driver_nl80211_data {
@@ -220,7 +590,7 @@
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 7ede0d030..732ae292d 100644
+index 7ede0d0..732ae29 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -18,6 +18,7 @@
@@ -245,5 +615,5 @@
wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
--
-2.25.1
+2.18.0