blob: 36092dd73bbb0880188d0bb902a89ca2dd62505c [file] [log] [blame]
From 801aa2e893945b44d2a10b73fcc2cff269e02497 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 915/917] Support new hostapd configuration, edcca_enable and
edcca_compensation
---
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(-)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index e57c78b..19a2fd5 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4741,6 +4741,26 @@ 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_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/src/ap/ap_config.c b/src/ap/ap_config.c
index f248281..427f16e 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -294,6 +294,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;
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 5dab8be..9bbe7eb 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -1150,8 +1150,18 @@ 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;
};
+enum edcca_mode {
+ EDCCA_MODE_FORCE_DISABLE = 0,
+ EDCCA_MODE_AUTO = 1,
+};
+
+#define EDCCA_DEFAULT_COMPENSATION -6
+#define EDCCA_MIN_COMPENSATION -126
+#define EDCCA_MAX_COMPENSATION 126
static inline u8 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 f7ad3ed..b8b98e4 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -1012,3 +1012,12 @@ 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)
+{
+ if (!hapd->driver || !hapd->driver->configure_edcca_threshold)
+ return 0;
+ return hapd->driver->configure_edcca_threshold(hapd->drv_priv,
+ hapd->iconf->edcca_enable,
+ hapd->iconf->edcca_compensation);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index b4fb766..f8fef19 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);
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);
#include "drivers/driver.h"
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index e61ac39..c1edaab 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -2295,6 +2295,9 @@ dfs_offload:
}
#endif /* CONFIG_MESH */
+ if (hostapd_drv_configure_edcca_threshold(hapd) < 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/drivers/driver.h b/src/drivers/driver.h
index 836c16b..fc96fef 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -4673,6 +4673,8 @@ 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,
+ const s8 edcca_compensation);
};
/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index cd4a853..4351e74 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -35,6 +35,7 @@
#include "radiotap_iter.h"
#include "rfkill.h"
#include "driver_nl80211.h"
+#include "common/mtk_vendor.h"
#ifndef NETLINK_CAP_ACK
@@ -12350,6 +12351,45 @@ 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)
+{
+ 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_ERROR,
+ "nl80211: Driver does not support setting EDCCA threshold");
+ return -1;
+ }
+
+ 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. ret=%d (%s) ",
+ ret, strerror(-ret));
+ }
+ return ret;
+}
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
@@ -12496,4 +12536,6 @@ 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_threshold = nl80211_configure_edcca_threshold,
};
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 80d4564..b677907 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -180,6 +180,7 @@ struct wpa_driver_nl80211_data {
unsigned int unsol_bcast_probe_resp:1;
unsigned int qca_do_acs:1;
unsigned int brcm_do_acs: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 a0803ba..6c743bf 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)
@@ -1044,6 +1045,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