blob: 485b882bbd9ea4b23787e41fcfe81fe9118fb710 [file] [log] [blame]
/* 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)");