[][Add mwctl support for mtk opensource/proprietary driver]

[Description]
Add mwctl support for mtk opensource/proprietary driver, mwctl is used
to replace iwpriv and mt76-vendor tools, mwctl uses nl80211 to
communicate with driver.

[Release-log]

Change-Id: If6deb6bfb9582212fa6ea8e5e589b478d206a383
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/5648065
diff --git a/feed/mwctl/src/capi.c b/feed/mwctl/src/capi.c
new file mode 100755
index 0000000..45a50a1
--- /dev/null
+++ b/feed/mwctl/src/capi.c
@@ -0,0 +1,139 @@
+/* Copyright (C) 2021 Mediatek Inc. */
+#define _GNU_SOURCE
+
+#include "mtk_vendor_nl80211.h"
+#include "mt76-vendor.h"
+#include "mwctl.h"
+
+static int mt76_ap_rfeatures_set_attr(struct nl_msg *msg, int argc, char **argv)
+{
+	char *val, *s1, *s2, *cur;
+	void *data;
+	int idx = MTK_VENDOR_ATTR_RFEATURE_CTRL_TRIG_TYPE_EN;
+
+	val = strchr(argv[0], '=');
+	if (!val)
+		return -EINVAL;
+
+	*(val++) = 0;
+
+	if (!strncmp(argv[0], "he_gi", 5)) {
+		nla_put_u8(msg, MTK_VENDOR_ATTR_RFEATURE_CTRL_HE_GI, strtoul(val, NULL, 0));
+	} else if (!strncmp(argv[0], "he_ltf", 6)) {
+		nla_put_u8(msg, MTK_VENDOR_ATTR_RFEATURE_CTRL_HE_LTF, strtoul(val, NULL, 0));
+	} else if (!strncmp(argv[0], "trig_type", 9)) {
+		data = nla_nest_start(msg,
+				      MTK_VENDOR_ATTR_RFEATURE_CTRL_TRIG_TYPE_CFG | NLA_F_NESTED);
+		if (!data)
+			return -ENOMEM;
+
+		s1 = s2 = strdup(val);
+		while ((cur = strsep(&s1, ",")) != NULL)
+			nla_put_u8(msg, idx++, strtoul(cur, NULL, 0));
+
+		nla_nest_end(msg, data);
+
+		free(s2);
+	} else if (!strncmp(argv[0], "ack_policy", 10)) {
+		nla_put_u8(msg, MTK_VENDOR_ATTR_RFEATURE_CTRL_ACK_PLCY, strtoul(val, NULL, 0));
+	}
+
+	return 0;
+}
+
+int mt76_ap_rfeatures_set(struct nl_msg *msg, int argc,
+	char **argv, void *ctx)
+{
+	void *data;
+	int ret = 0;
+
+	if (argc < 1)
+		return 1;
+
+	data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
+	if (!data)
+		return -ENOMEM;
+
+	mt76_ap_rfeatures_set_attr(msg, argc, argv);
+
+	nla_nest_end(msg, data);
+
+	return ret;
+}
+
+static int mt76_ap_wireless_set_attr(struct nl_msg *msg, int argc, char **argv)
+{
+	char *val;
+
+	val = strchr(argv[0], '=');
+	if (!val)
+		return -EINVAL;
+
+	*(val++) = 0;
+
+	if (!strncmp(argv[0], "fixed_mcs", 9)) {
+		nla_put_u8(msg, MTK_VENDOR_ATTR_WIRELESS_CTRL_FIXED_MCS, strtoul(val, NULL, 0));
+	} else if (!strncmp(argv[0], "ofdma", 5)) {
+		nla_put_u8(msg, MTK_VENDOR_ATTR_WIRELESS_CTRL_FIXED_OFDMA, strtoul(val, NULL, 0));
+	} else if (!strncmp(argv[0], "ppdu_type", 9)) {
+		nla_put_u8(msg, MTK_VENDOR_ATTR_WIRELESS_CTRL_PPDU_TX_TYPE, strtoul(val, NULL, 0));
+	} else if (!strncmp(argv[0], "nusers_ofdma", 12)) {
+		nla_put_u8(msg, MTK_VENDOR_ATTR_WIRELESS_CTRL_NUSERS_OFDMA, strtoul(val, NULL, 0));
+	} else if (!strncmp(argv[0], "add_ba_req_bufsize", 18)) {
+		nla_put_u16(msg, MTK_VENDOR_ATTR_WIRELESS_CTRL_BA_BUFFER_SIZE,
+			    strtoul(val, NULL, 0));
+	} else if (!strncmp(argv[0], "mimo", 4)) {
+		nla_put_u8(msg, MTK_VENDOR_ATTR_WIRELESS_CTRL_MIMO, strtoul(val, NULL, 0));
+	} else if (!strncmp(argv[0], "ampdu", 5)) {
+		nla_put_u8(msg, MTK_VENDOR_ATTR_WIRELESS_CTRL_AMPDU, strtoul(val, NULL, 0));
+	} else if (!strncmp(argv[0], "amsdu", 5)) {
+		nla_put_u8(msg, MTK_VENDOR_ATTR_WIRELESS_CTRL_AMSDU, strtoul(val, NULL, 0));
+	} else if (!strncmp(argv[0], "cert", 4)) {
+		nla_put_u8(msg, MTK_VENDOR_ATTR_WIRELESS_CTRL_CERT, strtoul(val, NULL, 0));
+	}
+
+	return 0;
+}
+
+int mt76_ap_wireless_set(struct nl_msg *msg, int argc,
+	char **argv, void *ctx)
+{
+	void *data;
+	int ret = 0;
+
+	if (argc < 1)
+		return 1;
+
+	data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
+	if (!data)
+		return -ENOMEM;
+
+	mt76_ap_wireless_set_attr(msg, argc, argv);
+
+	nla_nest_end(msg, data);
+
+	return ret;
+}
+
+DECLARE_SECTION(set);
+
+COMMAND(set, ap_rfeatures, "he_gi=<val>",
+	MTK_NL80211_VENDOR_SUBCMD_RFEATURE_CTRL, 0, CIB_NETDEV, mt76_ap_rfeatures_set,
+	"set ap_rfeatures he_gi=<val>"
+	"set ap_rfeatures he_ltf=<val>"
+	"set ap_rfeatures trig_type=<enable>,<val> (val: 0-7)"
+	"set ap_rfeatures ack_policy=<val> (val: 0-4)");
+
+DECLARE_SECTION(set);
+
+COMMAND(set, ap_wireless, "he_gi=<val>",
+	MTK_NL80211_VENDOR_SUBCMD_WIRELESS_CTRL, 0, CIB_NETDEV, mt76_ap_wireless_set,
+	"set ap_wireless fixed_mcs=<val>"
+	"set ap_wireless ofdma=<val> (0: disable, 1: DL, 2: UL)"
+	"set ap_wireless nusers_ofdma=<val>"
+	"set ap_wireless ppdu_type=<val> (0: SU, 1: MU, 4: LEGACY)"
+	"set ap_wireless add_ba_req_bufsize=<val>"
+	"set ap_wireless mimo=<val> (0: DL, 1: UL)"
+	"set ap_wireless ampdu=<enable>"
+	"set ap_wireless amsdu=<enable>"
+	"set ap_wireless cert=<enable>");