[][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/iwpriv_compat.c b/feed/mwctl/src/iwpriv_compat.c
new file mode 100755
index 0000000..22a8dcc
--- /dev/null
+++ b/feed/mwctl/src/iwpriv_compat.c
@@ -0,0 +1,270 @@
+/* Copyright (C) 2021 Mediatek Inc. */
+#define _GNU_SOURCE
+
+#include "mtk_vendor_nl80211.h"
+#include "mt76-vendor.h"
+#include "mwctl.h"
+
+static unsigned char ascii2hex(char *in, unsigned int *out)
+{
+ unsigned int hex_val, val;
+ char *p, asc_val;
+
+ hex_val = 0;
+ p = (char *)in;
+
+ while ((*p) != 0) {
+ val = 0;
+ asc_val = *p;
+
+ if ((asc_val >= 'a') && (asc_val <= 'f'))
+ val = asc_val - 87;
+ else if ((*p >= 'A') && (asc_val <= 'F'))
+ val = asc_val - 55;
+ else if ((asc_val >= '0') && (asc_val <= '9'))
+ val = asc_val - 48;
+ else
+ return 0;
+
+ hex_val = (hex_val << 4) + val;
+ p++;
+ }
+
+ *out = hex_val;
+ return 1;
+}
+
+static int handle_common_command(struct nl_msg *msg,
+ int argc, char **argv, int attr)
+{
+ void *data;
+ size_t len = 0;
+ char *cmd_str;
+
+ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!data)
+ return -ENOMEM;
+
+ if (argc > 0) {
+ cmd_str = argv[0];
+
+ len = strlen(cmd_str);
+ if (len) {
+ if (nla_put(msg, attr, len, (unsigned char*)cmd_str))
+ return -EMSGSIZE;
+ }
+ }
+ nla_nest_end(msg, data);
+
+ return 0;
+}
+
+int handle_set_command(struct nl_msg *msg, int argc,
+ char **argv, void *ctx)
+{
+ return handle_common_command(msg, argc, argv, MTK_NL80211_VENDOR_ATTR_VENDOR_SET_CMD_STR);
+}
+
+TOPLEVEL(set, "[param]=[value]", MTK_NL80211_VENDOR_SUBCMD_VENDOR_SET, 0, CIB_NETDEV, handle_set_command,
+ "this command is used to be compatible with old iwpriv set command, e.g iwpriv ra0 set channel=36");
+
+int show_callback(struct nl_msg *msg, void *cb)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct nlattr *vndr_tb[MTK_NL80211_VENDOR_ATTR_VENDOR_SHOW_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ char *show_str = NULL;
+ int err = 0;
+
+ err = nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (err < 0)
+ return err;
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ err = nla_parse_nested(vndr_tb, MTK_NL80211_VENDOR_ATTR_VENDOR_SHOW_ATTR_MAX,
+ tb[NL80211_ATTR_VENDOR_DATA], NULL);
+ if (err < 0)
+ return err;
+
+ if (vndr_tb[MTK_NL80211_VENDOR_ATTR_VENDOR_SHOW_RSP_STR]) {
+ show_str = nla_data(vndr_tb[MTK_NL80211_VENDOR_ATTR_VENDOR_SHOW_RSP_STR]);
+ printf("%s\n", show_str);
+ }
+ } else
+ printf("no any show rsp string from driver\n");
+
+ return 0;
+}
+
+static int handle_show_command(struct nl_msg *msg, int argc,
+ char **argv, void *ctx)
+{
+ register_handler(show_callback, NULL);
+ return handle_common_command(msg, argc, argv, MTK_NL80211_VENDOR_ATTR_VENDOR_SHOW_CMD_STR);
+}
+
+TOPLEVEL(show, "param", MTK_NL80211_VENDOR_SUBCMD_VENDOR_SHOW, 0, CIB_NETDEV, handle_show_command,
+ "this command is used to be compatible with old iwpriv show command, e.g iwpriv ra0 show stainfo");
+
+int stat_callback(struct nl_msg *msg, void *cb)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct nlattr *vndr_tb[MTK_NL80211_VENDOR_ATTR_STATISTICS_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ char *show_str = NULL;
+ int err = 0;
+
+ err = nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (err < 0)
+ return err;
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ err = nla_parse_nested(vndr_tb, MTK_NL80211_VENDOR_ATTR_STATISTICS_ATTR_MAX,
+ tb[NL80211_ATTR_VENDOR_DATA], NULL);
+ if (err < 0)
+ return err;
+
+ if (vndr_tb[MTK_NL80211_VENDOR_ATTR_STATISTICS_STR]) {
+ show_str = nla_data(vndr_tb[MTK_NL80211_VENDOR_ATTR_STATISTICS_STR]);
+ printf("%s\n", show_str);
+ }
+ } else
+ printf("no any statistic string from driver\n");
+
+ return 0;
+}
+
+static int handle_stat_command(struct nl_msg *msg, int argc,
+ char **argv, void *ctx)
+{
+ register_handler(stat_callback, NULL);
+ return handle_common_command(msg, 0, NULL, 0);
+}
+
+TOPLEVEL(stat, NULL, MTK_NL80211_VENDOR_SUBCMD_STATISTICS, 0, CIB_NETDEV, handle_stat_command,
+ "this command is used to be compatible with old iwpriv stat command, e.g iwpriv ra0 stat");
+
+
+int mac_callback(struct nl_msg *msg, void *cb)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct nlattr *vndr_tb[MTK_NL80211_VENDOR_ATTR_MAC_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ char *show_str = NULL;
+ int err = 0;
+
+ err = nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (err < 0)
+ return err;
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ err = nla_parse_nested(vndr_tb, MTK_NL80211_VENDOR_ATTR_MAC_ATTR_MAX,
+ tb[NL80211_ATTR_VENDOR_DATA], NULL);
+ if (err < 0)
+ return err;
+
+ if (vndr_tb[MTK_NL80211_VENDOR_ATTR_MAC_RSP_STR]) {
+ show_str = nla_data(vndr_tb[MTK_NL80211_VENDOR_ATTR_MAC_RSP_STR]);
+ printf("%s\n", show_str);
+ }
+ } else
+ printf("no any statistic string from driver\n");
+
+ return 0;
+}
+
+
+static int handle_mac_command(struct nl_msg *msg, int argc,
+ char **argv, void *ctx)
+{
+ void *data;
+ char *ptr, *seg_str, *addr_str, *val_str, *range_str;
+ unsigned char is_write, is_range;
+ unsigned int mac_s = 0, mac_e = 0;
+ unsigned int macVal = 0;
+ struct mac_param param;
+
+ if (!argc)
+ return -EINVAL;
+
+ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!data)
+ return -ENOMEM;
+
+ ptr = argv[0];
+
+ while ((seg_str = strsep((char **)&ptr, ",")) != NULL) {
+ is_write = 0;
+ addr_str = seg_str;
+ val_str = NULL;
+ val_str = strchr(seg_str, '=');
+
+ if (val_str != NULL) {
+ *val_str++ = 0;
+ is_write = 1;
+ } else
+ is_write = 0;
+
+ if (addr_str) {
+ range_str = strchr(addr_str, '-');
+
+ if (range_str != NULL) {
+ *range_str++ = 0;
+ is_range = 1;
+ } else
+ is_range = 0;
+
+ if ((ascii2hex(addr_str, &mac_s) == 0)) {
+ printf("Invalid MAC CR Addr, str=%s\n", addr_str);
+ break;
+ }
+
+ if (is_range) {
+ if (ascii2hex(range_str, &mac_e) == 0) {
+ printf("Invalid Range End MAC CR Addr[0x%x], str=%s\n",
+ mac_e, range_str);
+ break;
+ }
+
+ if (mac_e < mac_s) {
+ printf("Invalid Range MAC Addr[%s - %s] => [0x%x - 0x%x]\n",
+ addr_str, range_str, mac_s, mac_e);
+ break;
+ }
+ } else
+ mac_e = mac_s;
+ }
+
+ if (val_str) {
+ if ((strlen(val_str) == 0) || ascii2hex(val_str, &macVal) == 0) {
+ printf("Invalid MAC value[0x%s]\n", val_str);
+ break;
+ }
+ }
+
+ memset(¶m, 0, sizeof(param));
+ param.start = mac_s;
+ param.value = macVal;
+ param.end = mac_e;
+ if (is_write) {
+ if (nla_put(msg, MTK_NL80211_VENDOR_ATTR_MAC_WRITE_PARAM, sizeof(param), ¶m))
+ return -EMSGSIZE;
+ } else {
+ if (nla_put(msg, MTK_NL80211_VENDOR_ATTR_MAC_SHOW_PARAM, sizeof(param), ¶m))
+ return -EMSGSIZE;
+ }
+ }
+
+ nla_nest_end(msg, data);
+ register_handler(mac_callback, NULL);
+ return 0;
+}
+
+
+TOPLEVEL(mac, "addr=hex/addr-addr/addr=hex,addr=hex", MTK_NL80211_VENDOR_SUBCMD_MAC, 0,
+ CIB_NETDEV, handle_mac_command,
+ "this command is used to be compatible with old iwpriv mac, e.g iwpriv ra0 mac 2345");
+