[][MAC80211][hostapd][Add vendor command for certification]
[Description]
Add vendor command for certification
[Release-log]
N/A
Change-Id: I839e8c486c0a7d389251fe940e89124c6a1b117f
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7262688
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/mtk-0026-hostapd-mtk-Add-vendor-for-CAPI-certification-comman.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/mtk-0026-hostapd-mtk-Add-vendor-for-CAPI-certification-comman.patch
new file mode 100644
index 0000000..5b9f4df
--- /dev/null
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/mtk-0026-hostapd-mtk-Add-vendor-for-CAPI-certification-comman.patch
@@ -0,0 +1,527 @@
+From 47b475634804175c77621d492ad6129a31dcda4d Mon Sep 17 00:00:00 2001
+From: Evelyn Tsai <evelyn.tsai@mediatek.com>
+Date: Fri, 17 Mar 2023 16:17:14 +0800
+Subject: [PATCH] hostapd: mtk: Add vendor for CAPI certification commands
+
+---
+ hostapd/ctrl_iface.c | 95 +++++++++++++++
+ src/ap/ap_drv_ops.c | 21 ++++
+ src/ap/ap_drv_ops.h | 3 +
+ src/common/mtk_vendor.h | 32 +-----
+ src/drivers/driver.h | 22 ++++
+ src/drivers/driver_nl80211.c | 185 ++++++++++++++++++++++++++++++
+ src/drivers/driver_nl80211.h | 1 +
+ src/drivers/driver_nl80211_capa.c | 3 +
+ 8 files changed, 332 insertions(+), 30 deletions(-)
+
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index e1e9270..58bb710 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -38,6 +38,7 @@
+ #endif /* CONFIG_DPP */
+ #include "common/wpa_ctrl.h"
+ #include "common/ptksa_cache.h"
++#include "common/mtk_vendor.h"
+ #include "crypto/tls.h"
+ #include "drivers/driver.h"
+ #include "eapol_auth/eapol_auth_sm.h"
+@@ -3715,6 +3716,96 @@ hostapd_ctrl_iface_get_aval_color_bmp(struct hostapd_data *hapd, char *buf,
+ return pos - buf;
+ }
+
++static int
++hostapd_ctrl_iface_ap_wireless(struct hostapd_data *hapd, char *cmd,
++ char *buf, size_t buflen)
++{
++ char *pos, *value, *config = cmd;
++ enum mtk_vendor_attr_wireless_ctrl sub_cmd;
++
++ pos = os_strchr(config, '=');
++ if (pos == NULL)
++ return -1;
++ *pos++ = '\0';
++
++ if(pos == NULL)
++ return -1;
++ value = pos;
++
++ if (os_strncmp(config, "fixed_mcs", 9) == 0)
++ sub_cmd = MTK_VENDOR_ATTR_WIRELESS_CTRL_FIXED_MCS;
++ else if (os_strncmp(config, "ofdma", 5) == 0)
++ sub_cmd = MTK_VENDOR_ATTR_WIRELESS_CTRL_FIXED_OFDMA;
++ else if (os_strncmp(config, "ppdu_type", 9) == 0)
++ sub_cmd = MTK_VENDOR_ATTR_WIRELESS_CTRL_PPDU_TX_TYPE;
++ else if (os_strncmp(config, "nusers_ofdma", 12) == 0)
++ sub_cmd = MTK_VENDOR_ATTR_WIRELESS_CTRL_NUSERS_OFDMA;
++ else if (os_strncmp(config, "add_ba_req_bufsize", 18) == 0)
++ sub_cmd = MTK_VENDOR_ATTR_WIRELESS_CTRL_BA_BUFFER_SIZE;
++ else if (os_strncmp(config, "mimo", 4) == 0)
++ sub_cmd = MTK_VENDOR_ATTR_WIRELESS_CTRL_MIMO;
++ else if (os_strncmp(config, "cert", 4) == 0)
++ sub_cmd = MTK_VENDOR_ATTR_WIRELESS_CTRL_CERT ;
++ else {
++ wpa_printf(MSG_ERROR,
++ "Unsupported parameter %s for ap_wireless", config);
++ return -1;
++ }
++
++ if (hostapd_drv_ap_wireless(hapd, (u8) sub_cmd, atoi(value)) != 0)
++ return -1;
++
++ return os_snprintf(buf, buflen, "OK\n");
++}
++
++static int
++hostapd_ctrl_iface_ap_rfeatures(struct hostapd_data *hapd, char *cmd,
++ char *buf, size_t buflen)
++{
++ char *pos, *value, *type, *config = cmd;
++ enum mtk_vendor_attr_rfeature_ctrl sub_cmd;
++
++ pos = os_strchr(config, '=');
++ if (pos == NULL)
++ return -1;
++ *pos++ = '\0';
++
++ if(pos == NULL)
++ return -1;
++ value = pos;
++
++ if (os_strncmp(config, "he_gi", 5) == 0)
++ sub_cmd = MTK_VENDOR_ATTR_RFEATURE_CTRL_HE_GI;
++ else if (os_strncmp(config, "he_ltf", 6) == 0)
++ sub_cmd = MTK_VENDOR_ATTR_RFEATURE_CTRL_HE_LTF;
++ else if (os_strncmp(config, "trig_type", 9) == 0) {
++ pos = os_strchr(value, ',');
++ if (pos == NULL)
++ return -1;
++ *pos++ = '\0';
++ if(pos == NULL)
++ return -1;
++ type = pos;
++ goto trigtype;
++ } else if (os_strcmp(config, "ack_policy") == 0)
++ sub_cmd = MTK_VENDOR_ATTR_RFEATURE_CTRL_ACK_PLCY;
++ else {
++ wpa_printf(MSG_ERROR,
++ "Unsupported parameter %s for ap_rfeatures", config);
++ return -1;
++ }
++
++ if (hostapd_drv_ap_rfeatures(hapd, (u8) sub_cmd, atoi(value)) != 0)
++ return -1;
++ goto exit;
++
++trigtype:
++ if (hostapd_drv_ap_trig_type(hapd, atoi(value), atoi(type)) != 0)
++ return -1;
++
++exit:
++ return os_snprintf(buf, buflen, "OK\n");
++}
+
+ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ char *buf, char *reply,
+@@ -4286,6 +4377,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ reply_len = hostapd_ctrl_iface_get_bss_color(hapd, reply, reply_size);
+ } else if (os_strncmp(buf, "AVAL_COLOR_BMP", 14) == 0) {
+ reply_len = hostapd_ctrl_iface_get_aval_color_bmp(hapd, reply, reply_size);
++ } else if (os_strncmp(buf, "ap_wireless ", 12) == 0) {
++ reply_len = hostapd_ctrl_iface_ap_wireless(hapd, buf + 12, reply, reply_size);
++ } else if (os_strncmp(buf, "ap_rfeatures ", 13) == 0) {
++ reply_len = hostapd_ctrl_iface_ap_rfeatures(hapd, buf + 13, reply, reply_size);
+ } else {
+ os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+ reply_len = 16;
+diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
+index 40b9a20..52d0fff 100644
+--- a/src/ap/ap_drv_ops.c
++++ b/src/ap/ap_drv_ops.c
+@@ -1100,3 +1100,24 @@ int hostapd_drv_get_aval_bss_color_bmp(struct hostapd_data *hapd, u64 *aval_colo
+ return 0;
+ return hapd->driver->get_aval_color_bmp(hapd->drv_priv, aval_color_bmp);
+ }
++
++int hostapd_drv_ap_wireless(struct hostapd_data *hapd, u8 sub_vendor_id, int value)
++{
++ if (!hapd->driver || !hapd->driver->ap_wireless)
++ return 0;
++ return hapd->driver->ap_wireless(hapd->drv_priv, sub_vendor_id, value);
++}
++
++int hostapd_drv_ap_rfeatures(struct hostapd_data *hapd, u8 sub_vendor_id, int value)
++{
++ if (!hapd->driver || !hapd->driver->ap_rfeatures)
++ return 0;
++ return hapd->driver->ap_rfeatures(hapd->drv_priv, sub_vendor_id, value);
++}
++
++int hostapd_drv_ap_trig_type(struct hostapd_data *hapd, u8 enable, u8 type)
++{
++ if (!hapd->driver || !hapd->driver->ap_trigtype)
++ return 0;
++ return hapd->driver->ap_trigtype(hapd->drv_priv, enable, type);
++}
+diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
+index 136a3ac..659c3f8 100644
+--- a/src/ap/ap_drv_ops.h
++++ b/src/ap/ap_drv_ops.h
+@@ -151,6 +151,9 @@ int hostapd_drv_amsdu_ctrl(struct hostapd_data *hapd);
+ int hostapd_drv_amsdu_dump(struct hostapd_data *hapd, u8 *amsdu);
+ int hostapd_drv_get_aval_bss_color_bmp(struct hostapd_data *hapd,
+ u64 *aval_color_bmp);
++int hostapd_drv_ap_wireless(struct hostapd_data *hapd, u8 sub_vendor_id, int value);
++int hostapd_drv_ap_rfeatures(struct hostapd_data *hapd, u8 sub_vendor_id, int value);
++int hostapd_drv_ap_trig_type(struct hostapd_data *hapd, u8 enable, u8 type);
+
+ #include "drivers/driver.h"
+
+diff --git a/src/common/mtk_vendor.h b/src/common/mtk_vendor.h
+index a99e6f2..32438af 100644
+--- a/src/common/mtk_vendor.h
++++ b/src/common/mtk_vendor.h
+@@ -48,16 +48,6 @@ enum mtk_vendor_attr_edcca_dump {
+ 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 },
+- [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC20_VAL] = { .type = NLA_U8 },
+- [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC40_VAL] = { .type = NLA_U8 },
+- [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC80_VAL] = { .type = NLA_U8 },
+- [MTK_VENDOR_ATTR_EDCCA_CTRL_COMPENSATE] = { .type = NLA_U8 },
+-};
+-
+ enum mtk_vendor_attr_3wire_ctrl {
+ MTK_VENDOR_ATTR_3WIRE_CTRL_UNSPEC,
+
+@@ -69,10 +59,6 @@ enum mtk_vendor_attr_3wire_ctrl {
+ NUM_MTK_VENDOR_ATTRS_3WIRE_CTRL - 1
+ };
+
+-static struct nla_policy three_wire_ctrl_policy[NUM_MTK_VENDOR_ATTRS_3WIRE_CTRL] = {
+- [MTK_VENDOR_ATTR_3WIRE_CTRL_MODE] = {.type = NLA_U8 },
+-};
+-
+ enum mtk_vendor_attr_csi_ctrl {
+ MTK_VENDOR_ATTR_CSI_CTRL_UNSPEC,
+
+@@ -169,7 +155,7 @@ enum mtk_vendor_attr_wireless_ctrl {
+ MTK_VENDOR_ATTR_WIRELESS_CTRL_BA_BUFFER_SIZE,
+ MTK_VENDOR_ATTR_WIRELESS_CTRL_MIMO,
+ MTK_VENDOR_ATTR_WIRELESS_CTRL_AMSDU,
+- MTK_VENDOR_ATTR_WIRELESS_CTRL_CERT,
++ MTK_VENDOR_ATTR_WIRELESS_CTRL_CERT = 9,
+ MTK_VENDOR_ATTR_WIRELESS_CTRL_RTS_SIGTA,
+
+ /* keep last */
+@@ -189,11 +175,6 @@ enum mtk_vendor_attr_wireless_dump {
+ NUM_MTK_VENDOR_ATTRS_WIRELESS_DUMP - 1
+ };
+
+-static const struct nla_policy
+-wireless_dump_policy[NUM_MTK_VENDOR_ATTRS_WIRELESS_DUMP] = {
+- [MTK_VENDOR_ATTR_WIRELESS_DUMP_AMSDU] = { .type = NLA_U8 },
+-};
+-
+ enum mtk_vendor_attr_rfeature_ctrl {
+ MTK_VENDOR_ATTR_RFEATURE_CTRL_UNSPEC,
+
+@@ -203,6 +184,7 @@ enum mtk_vendor_attr_rfeature_ctrl {
+ MTK_VENDOR_ATTR_RFEATURE_CTRL_TRIG_TYPE_EN,
+ MTK_VENDOR_ATTR_RFEATURE_CTRL_TRIG_TYPE,
+ MTK_VENDOR_ATTR_RFEATURE_CTRL_ACK_PLCY,
++ MTK_VENDOR_ATTR_RFEATURE_CTRL_TRIG_TXBF,
+
+ /* keep last */
+ NUM_MTK_VENDOR_ATTRS_RFEATURE_CTRL,
+@@ -244,16 +226,6 @@ enum mtk_vendor_attr_ibf_dump {
+ NUM_MTK_VENDOR_ATTRS_IBF_DUMP - 1
+ };
+
+-static struct nla_policy
+-ibf_ctrl_policy[NUM_MTK_VENDOR_ATTRS_IBF_CTRL] = {
+- [MTK_VENDOR_ATTR_IBF_CTRL_ENABLE] = { .type = NLA_U8 },
+-};
+-
+-static struct nla_policy
+-ibf_dump_policy[NUM_MTK_VENDOR_ATTRS_IBF_DUMP] = {
+- [MTK_VENDOR_ATTR_IBF_DUMP_ENABLE] = { .type = NLA_U8 },
+-};
+-
+ enum mtk_vendor_attr_bss_color_ctrl {
+ MTK_VENDOR_ATTR_BSS_COLOR_CTRL_UNSPEC,
+
+diff --git a/src/drivers/driver.h b/src/drivers/driver.h
+index 7f6392f..d4f34b6 100644
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -4779,6 +4779,28 @@ struct wpa_driver_ops {
+ *
+ */
+ int (*get_aval_color_bmp)(void *priv, u64 *aval_color_bmp);
++
++ /**
++ * ap_wireless - set wireless command
++ * @priv: Private driver interface data
++ * @value: value
++ */
++ int (*ap_wireless)(void *priv, u8 mode, int value);
++
++ /**
++ * ap_rfeatures - set ap rf features command
++ * @priv: Private driver interface data
++ * @value: value
++ */
++ int (*ap_rfeatures)(void *priv, u8 mode, int value);
++
++ /**
++ * ap_trigtype - set trigger type
++ * @priv: Private driver interface data
++ * @enable: enable or disable
++ * @type: trigger type
++ */
++ int (*ap_trigtype)(void *priv, u8 enable, u8 type);
+ };
+
+ /**
+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
+index f9a8763..9c1717f 100644
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -74,6 +74,57 @@ enum nlmsgerr_attrs {
+ #endif /* ANDROID */
+
+
++static struct nla_policy
++ibf_ctrl_policy[NUM_MTK_VENDOR_ATTRS_IBF_CTRL] = {
++ [MTK_VENDOR_ATTR_IBF_CTRL_ENABLE] = { .type = NLA_U8 },
++};
++
++static struct nla_policy
++ibf_dump_policy[NUM_MTK_VENDOR_ATTRS_IBF_DUMP] = {
++ [MTK_VENDOR_ATTR_IBF_DUMP_ENABLE] = { .type = NLA_U8 },
++};
++
++static struct nla_policy three_wire_ctrl_policy[NUM_MTK_VENDOR_ATTRS_3WIRE_CTRL] = {
++ [MTK_VENDOR_ATTR_3WIRE_CTRL_MODE] = {.type = NLA_U8 },
++};
++
++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 },
++ [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC20_VAL] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC40_VAL] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC80_VAL] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_EDCCA_CTRL_COMPENSATE] = { .type = NLA_U8 },
++};
++
++static const struct nla_policy
++wireless_dump_policy[NUM_MTK_VENDOR_ATTRS_WIRELESS_DUMP] = {
++ [MTK_VENDOR_ATTR_WIRELESS_DUMP_AMSDU] = { .type = NLA_U8 },
++};
++
++static const struct nla_policy
++rfeature_ctrl_policy[NUM_MTK_VENDOR_ATTRS_RFEATURE_CTRL] = {
++ [MTK_VENDOR_ATTR_RFEATURE_CTRL_HE_GI] = {.type = NLA_U8 },
++ [MTK_VENDOR_ATTR_RFEATURE_CTRL_HE_LTF] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_RFEATURE_CTRL_TRIG_TYPE_CFG] = { .type = NLA_NESTED },
++ [MTK_VENDOR_ATTR_RFEATURE_CTRL_TRIG_TYPE_EN] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_RFEATURE_CTRL_TRIG_TYPE] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_RFEATURE_CTRL_ACK_PLCY] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_RFEATURE_CTRL_TRIG_TXBF] = { .type = NLA_U8 },
++};
++
++static const struct nla_policy
++wireless_ctrl_policy[NUM_MTK_VENDOR_ATTRS_WIRELESS_CTRL] = {
++ [MTK_VENDOR_ATTR_WIRELESS_CTRL_FIXED_MCS] = {.type = NLA_U8 },
++ [MTK_VENDOR_ATTR_WIRELESS_CTRL_FIXED_OFDMA] = {.type = NLA_U8 },
++ [MTK_VENDOR_ATTR_WIRELESS_CTRL_PPDU_TX_TYPE] = {.type = NLA_U8 },
++ [MTK_VENDOR_ATTR_WIRELESS_CTRL_NUSERS_OFDMA] = {.type = NLA_U8 },
++ [MTK_VENDOR_ATTR_WIRELESS_CTRL_MIMO] = {.type = NLA_U8 },
++ [MTK_VENDOR_ATTR_WIRELESS_CTRL_BA_BUFFER_SIZE] = {.type = NLA_U16 },
++ [MTK_VENDOR_ATTR_WIRELESS_CTRL_AMSDU] = {.type = NLA_U8 },
++ [MTK_VENDOR_ATTR_WIRELESS_CTRL_CERT] = {.type = NLA_U8 },
++};
++
+ static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg)
+ {
+ struct nl_sock *handle;
+@@ -13005,6 +13056,137 @@ fail:
+ return -ENOBUFS;
+ }
+
++static int nl80211_ap_wireless(void *priv, u8 sub_vendor_id, int 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_wireless_vendor_cmd_avail) {
++ wpa_printf(MSG_INFO,
++ "nl80211: Driver does not support setting ap wireless control");
++ return 0;
++ }
++
++ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
++ if (!msg)
++ goto fail;
++
++ if (nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_MTK) ||
++ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_WIRELESS_CTRL))
++ goto fail;
++
++ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
++ if (!data)
++ goto fail;
++
++ if (sub_vendor_id == MTK_VENDOR_ATTR_WIRELESS_CTRL_BA_BUFFER_SIZE)
++ nla_put_u16(msg, sub_vendor_id, (u16) value);
++ else
++ nla_put_u8(msg, sub_vendor_id, (u8) value);
++
++ nla_nest_end(msg, data);
++ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
++ if (ret)
++ wpa_printf(MSG_ERROR, "Failed to set ap_wireless. ret=%d (%s)", ret, strerror(-ret));
++
++ return ret;
++
++fail:
++ nlmsg_free(msg);
++ return -ENOBUFS;
++}
++
++static int nl80211_ap_rfeatures(void *priv, u8 sub_vendor_id, int 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_rfeatures_vendor_cmd_avail) {
++ wpa_printf(MSG_INFO,
++ "nl80211: Driver does not support setting ap rfeatures control");
++ return 0;
++ }
++
++ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
++ if (!msg)
++ goto fail;
++
++ if (nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_MTK) ||
++ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_RFEATURE_CTRL))
++ goto fail;
++
++ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
++ if (!data)
++ goto fail;
++
++ nla_put_u8(msg, sub_vendor_id, (u8) value);
++
++ nla_nest_end(msg, data);
++
++ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
++ if (ret)
++ wpa_printf(MSG_ERROR, "Failed to set rf_features. ret=%d (%s)", ret, strerror(-ret));
++
++ return ret;
++
++fail:
++ nlmsg_free(msg);
++ return -ENOBUFS;
++}
++
++static int nl80211_ap_trigtype(void *priv, u8 enable, u8 type)
++{
++ struct i802_bss *bss = priv;
++ struct wpa_driver_nl80211_data *drv = bss->drv;
++ struct nl_msg *msg;
++ struct nlattr *data, *data2;
++ int ret;
++
++ if (!drv->mtk_rfeatures_vendor_cmd_avail) {
++ wpa_printf(MSG_INFO,
++ "nl80211: Driver does not support setting ap rfeatures control");
++ return 0;
++ }
++
++ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
++ if (!msg)
++ goto fail;
++
++ if (nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_MTK) ||
++ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_RFEATURE_CTRL))
++ goto fail;
++
++ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
++ if (!data)
++ goto fail;
++
++ data2 = nla_nest_start(msg, MTK_VENDOR_ATTR_RFEATURE_CTRL_TRIG_TYPE_CFG);
++ if (!data2)
++ goto fail;
++
++ nla_put_u8(msg, MTK_VENDOR_ATTR_RFEATURE_CTRL_TRIG_TYPE_EN, enable);
++ nla_put_u8(msg, MTK_VENDOR_ATTR_RFEATURE_CTRL_TRIG_TYPE, type);
++
++ nla_nest_end(msg, data2);
++ nla_nest_end(msg, data);
++
++ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
++ if (ret)
++ wpa_printf(MSG_ERROR, "Failed to set trig_type. ret=%d (%s)", ret, strerror(-ret));
++
++ return ret;
++
++fail:
++ nlmsg_free(msg);
++ return -ENOBUFS;
++}
++
+ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+ .name = "nl80211",
+ .desc = "Linux nl80211/cfg80211",
+@@ -13162,4 +13344,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+ .amsdu_ctrl = nl80211_enable_amsdu,
+ .amsdu_dump = nl80211_dump_amsdu,
+ .get_aval_color_bmp = nl80211_get_aval_color_bmp,
++ .ap_wireless = nl80211_ap_wireless,
++ .ap_rfeatures = nl80211_ap_rfeatures,
++ .ap_trigtype = nl80211_ap_trigtype,
+ };
+diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
+index 72c7abd..7a03446 100644
+--- a/src/drivers/driver_nl80211.h
++++ b/src/drivers/driver_nl80211.h
+@@ -187,6 +187,7 @@ struct wpa_driver_nl80211_data {
+ unsigned int mtk_ibf_vendor_cmd_avail:1;
+ unsigned int mtk_wireless_vendor_cmd_avail:1;
+ unsigned int mtk_bss_color_vendor_cmd_avail:1;
++ unsigned int mtk_rfeatures_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 e7c6f39..6f4d029 100644
+--- a/src/drivers/driver_nl80211_capa.c
++++ b/src/drivers/driver_nl80211_capa.c
+@@ -1095,6 +1095,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+ case MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL :
+ drv->mtk_bss_color_vendor_cmd_avail = 1;
+ break;
++ case MTK_NL80211_VENDOR_SUBCMD_RFEATURE_CTRL:
++ drv->mtk_rfeatures_vendor_cmd_avail = 1;
++ break;
+ }
+ }
+
+--
+2.18.0
+