blob: 37f517201fb9a385c95d4d94aaa170e105169934 [file] [log] [blame]
From 7e1b6b0dc2167af5b9d58466ce693b67e6b5dbf2 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 05/54] 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 | 125 +++++++++++++++++++++
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, 428 insertions(+), 6 deletions(-)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 4b0f99fd2..d281026e8 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4809,6 +4809,40 @@ static int hostapd_config_fill(struct hostapd_config *conf,
return 1;
}
#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 ee6d492f8..cad3f863c 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -542,6 +542,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)
{
@@ -3369,6 +3382,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_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;
+ }
+}
+
+
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
char *buf, char *reply,
int reply_size,
@@ -3922,6 +4041,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 73b33b42a..8e56d1082 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -295,6 +295,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;
+
return conf;
}
@@ -1008,6 +1011,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 82338e213..24d540dbf 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -1193,8 +1193,38 @@ struct hostapd_config {
MBSSID_ENABLED = 1,
ENHANCED_MBSSID_ENABLED = 2,
} mbssid;
+
+ 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 75ddfa15c..99ba973aa 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -1137,3 +1137,27 @@ int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
return hapd->driver->set_secure_ranging_ctx(hapd->drv_priv, &params);
}
#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 96c8c4e2c..6ca693b0b 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -144,6 +144,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 a203546b6..f7c80c73b 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -2511,6 +2511,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 c5cc26737..7d71aa783 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -5105,6 +5105,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 a3e436e95..1a2f52b77 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -37,6 +37,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
@@ -13768,6 +13770,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_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) ||
+ 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_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);
+
+ 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_msgs(drv, msg, edcca_info_handler, value, NULL, NULL);
+ 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",
@@ -13924,4 +14094,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 aee8c4512..51b3fbec8 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -202,6 +202,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;
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 f01a526a0..47654f65b 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)
@@ -1111,6 +1112,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.18.0