| /* Copyright (C) 2021 Mediatek Inc. */ |
| #define _GNU_SOURCE |
| |
| #include "mtk_vendor_nl80211.h" |
| #include "mt76-vendor.h" |
| #include "mwctl.h" |
| |
| static struct nla_policy |
| amnt_ctrl_policy[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL] = { |
| [MTK_VENDOR_ATTR_AMNT_CTRL_SET] = {.type = NLA_NESTED }, |
| [MTK_VENDOR_ATTR_AMNT_CTRL_DUMP] = { .type = NLA_NESTED }, |
| }; |
| |
| static struct nla_policy |
| amnt_dump_policy[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP] = { |
| [MTK_VENDOR_ATTR_AMNT_DUMP_INDEX] = {.type = NLA_U8 }, |
| [MTK_VENDOR_ATTR_AMNT_DUMP_LEN] = { .type = NLA_U8 }, |
| [MTK_VENDOR_ATTR_AMNT_DUMP_RESULT] = { .type = NLA_NESTED }, |
| }; |
| |
| static int mt76_amnt_set_attr(struct nl_msg *msg, int argc, char **argv) |
| { |
| void *tb1, *tb2; |
| u8 a[ETH_ALEN], idx; |
| int i = 0, matches; |
| |
| idx = strtoul(argv[0], NULL, 0); |
| matches = sscanf(argv[1], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", |
| a, a+1, a+2, a+3, a+4, a+5); |
| |
| if (matches != ETH_ALEN) |
| return -EINVAL; |
| |
| tb1 = nla_nest_start(msg, MTK_VENDOR_ATTR_AMNT_CTRL_SET | NLA_F_NESTED); |
| if (!tb1) |
| return -ENOMEM; |
| |
| nla_put_u8(msg, MTK_VENDOR_ATTR_AMNT_SET_INDEX, idx); |
| |
| tb2 = nla_nest_start(msg, MTK_VENDOR_ATTR_AMNT_SET_MACADDR | NLA_F_NESTED); |
| if (!tb2) { |
| nla_nest_end(msg, tb1); |
| return -ENOMEM; |
| } |
| |
| for (i = 0; i < ETH_ALEN; i++) |
| nla_put_u8(msg, i, a[i]); |
| |
| nla_nest_end(msg, tb2); |
| nla_nest_end(msg, tb1); |
| |
| return 0; |
| } |
| |
| int mt76_amnt_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_amnt_set_attr(msg, argc, argv); |
| |
| nla_nest_end(msg, data); |
| |
| return ret; |
| } |
| |
| static int mt76_amnt_dump_cb(struct nl_msg *msg, void *arg) |
| { |
| struct nlattr *tb1[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL]; |
| struct nlattr *tb2[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP]; |
| struct nlattr *attr; |
| struct nlattr *data; |
| struct nlattr *cur; |
| struct amnt_data *res; |
| int len = 0, rem; |
| |
| attr = unl_find_attr(&unl, msg, NL80211_ATTR_VENDOR_DATA); |
| if (!attr) { |
| fprintf(stderr, "Testdata attribute not found\n"); |
| return NL_SKIP; |
| } |
| |
| nla_parse_nested(tb1, MTK_VENDOR_ATTR_AMNT_CTRL_MAX, |
| attr, amnt_ctrl_policy); |
| |
| if (!tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP]) |
| return NL_SKIP; |
| |
| nla_parse_nested(tb2, NUM_MTK_VENDOR_ATTRS_AMNT_DUMP, |
| tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP], amnt_dump_policy); |
| |
| if (!tb2[MTK_VENDOR_ATTR_AMNT_DUMP_LEN]) |
| return NL_SKIP; |
| |
| len = nla_get_u8(tb2[MTK_VENDOR_ATTR_AMNT_DUMP_LEN]); |
| if (!len) |
| return 0; |
| |
| if (!tb2[MTK_VENDOR_ATTR_AMNT_DUMP_RESULT]) |
| return NL_SKIP; |
| |
| data = tb2[MTK_VENDOR_ATTR_AMNT_DUMP_RESULT]; |
| nla_for_each_nested(cur,data, rem) { |
| res = (struct amnt_data *) nla_data(cur); |
| printf("[vendor] amnt_idx: %d, addr=%x:%x:%x:%x:%x:%x, rssi=%d/%d/%d/%d, last_seen=%u\n", |
| res->idx, |
| res->addr[0], res->addr[1], res->addr[2], |
| res->addr[3], res->addr[4], res->addr[5], |
| res->rssi[0], res->rssi[1], res->rssi[2], |
| res->rssi[3], res->last_seen); |
| } |
| return 0; |
| } |
| |
| int mt76_amnt_dump (struct nl_msg *msg, int argc, |
| char **argv, void *ctx) |
| { |
| void *data, *tb1; |
| u8 amnt_idx; |
| |
| if (argc < 1) |
| return 1; |
| |
| register_handler(mt76_amnt_dump_cb, NULL); |
| |
| data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED); |
| if (!data) |
| return -EINVAL; |
| |
| tb1 = nla_nest_start(msg, MTK_VENDOR_ATTR_AMNT_CTRL_DUMP | NLA_F_NESTED); |
| if (!tb1) |
| return -EINVAL; |
| |
| amnt_idx = strtoul(argv[0], NULL, 0); |
| nla_put_u8(msg, MTK_VENDOR_ATTR_AMNT_DUMP_INDEX, amnt_idx); |
| |
| nla_nest_end(msg, tb1); |
| |
| nla_nest_end(msg, data); |
| |
| return 0; |
| } |
| |
| DECLARE_SECTION(dump); |
| |
| COMMAND(dump, amnt, "", |
| MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL, 0, CIB_NETDEV, mt76_amnt_dump, |
| "dump amnt <index> (0x0~0xf or 0xff)"); |
| |
| DECLARE_SECTION(set); |
| |
| COMMAND(set, amnt, "<index>(0x0~0xf) <mac addr>(xx:xx:xx:xx:xx:xx)", |
| MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL, 0, CIB_NETDEV, mt76_amnt_set, |
| "set amnt <index>(0x0~0xf) <mac addr>(xx:xx:xx:xx:xx:xx)"); |
| |
| |