blob: 55eb071fa137e440f52e75588e5882e22339face [file] [log] [blame]
developere53f0872021-07-23 11:13:49 +08001/* Copyright (C) 2021 Mediatek Inc. */
2#define _GNU_SOURCE
3
4#include "mt76-vendor.h"
5
6static const struct nla_policy
7amnt_ctrl_policy[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL] = {
8 [MTK_VENDOR_ATTR_AMNT_CTRL_SET] = {.type = NLA_NESTED },
9 [MTK_VENDOR_ATTR_AMNT_CTRL_DUMP] = { .type = NLA_NESTED },
10};
11
12static const struct nla_policy
13amnt_dump_policy[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP] = {
14 [MTK_VENDOR_ATTR_AMNT_DUMP_INDEX] = {.type = NLA_U8 },
15 [MTK_VENDOR_ATTR_AMNT_DUMP_LEN] = { .type = NLA_U8 },
16 [MTK_VENDOR_ATTR_AMNT_DUMP_RESULT] = { .type = NLA_NESTED },
17};
18
19static int mt76_amnt_set_attr(struct nl_msg *msg, int argc, char **argv)
20{
21 void *tb1, *tb2;
22 u8 a[ETH_ALEN], idx;
23 int i = 0, matches;
24
25 idx = strtoul(argv[0], NULL, 0);
26 matches = sscanf(argv[1], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
27 a, a+1, a+2, a+3, a+4, a+5);
28
29 if (matches != ETH_ALEN)
30 return -EINVAL;
31
32 tb1 = nla_nest_start(msg, MTK_VENDOR_ATTR_AMNT_CTRL_SET | NLA_F_NESTED);
33 nla_put_u8(msg, MTK_VENDOR_ATTR_AMNT_SET_INDEX, idx);
34
35 tb2 = nla_nest_start(msg, MTK_VENDOR_ATTR_AMNT_SET_MACADDR | NLA_F_NESTED);
36 for (i = 0; i < ETH_ALEN; i++)
37 nla_put_u8(msg, i, a[i]);
38
39 nla_nest_end(msg, tb2);
40 nla_nest_end(msg, tb1);
41 return 0;
42}
43
44int mt76_amnt_set(int idx, int argc, char **argv)
45{
46 struct nl_msg *msg;
47 void *data;
48 int ret;
49
50 if (argc < 1)
51 return 1;
52
53 if (unl_genl_init(&unl, "nl80211") < 0) {
54 fprintf(stderr, "Failed to connect to nl80211\n");
55 return 2;
56 }
57
58 msg = unl_genl_msg(&unl, NL80211_CMD_VENDOR, false);
59
60 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, idx) ||
61 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
62 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL))
63 return false;
64
65 data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
66
67 mt76_amnt_set_attr(msg, argc, argv);
68
69 nla_nest_end(msg, data);
70
71 ret = unl_genl_request(&unl, msg, NULL, NULL);
72 if (ret)
73 fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
74
75 unl_free(&unl);
76
77 return ret;
78}
79
80static int mt76_amnt_dump_cb(struct nl_msg *msg, void *arg)
81{
82 struct nlattr *tb1[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL];
83 struct nlattr *tb2[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP];
84 struct nlattr *attr;
85 struct nlattr *data;
86 struct nlattr *cur;
87 struct amnt_data *res;
88 int len = 0, rem;
89
90 attr = unl_find_attr(&unl, msg, NL80211_ATTR_VENDOR_DATA);
91 if (!attr) {
92 fprintf(stderr, "Testdata attribute not found\n");
93 return NL_SKIP;
94 }
95
96 nla_parse_nested(tb1, MTK_VENDOR_ATTR_AMNT_CTRL_MAX,
97 attr, amnt_ctrl_policy);
98
99 if (!tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP])
100 return NL_SKIP;
101
102 nla_parse_nested(tb2, NUM_MTK_VENDOR_ATTRS_AMNT_DUMP,
103 tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP], amnt_dump_policy);
104
105 if (!tb2[MTK_VENDOR_ATTR_AMNT_DUMP_LEN])
106 return NL_SKIP;
107
108 len = nla_get_u8(tb2[MTK_VENDOR_ATTR_AMNT_DUMP_LEN]);
109 if (!len)
110 return 0;
111
112 if (!tb2[MTK_VENDOR_ATTR_AMNT_DUMP_RESULT])
113 return NL_SKIP;
114
115 data = tb2[MTK_VENDOR_ATTR_AMNT_DUMP_RESULT];
116 nla_for_each_nested(cur,data, rem) {
117 res = (struct amnt_data *) nla_data(cur);
118 printf("[vendor] amnt_idx: %d, addr=%x:%x:%x:%x:%x:%x, rssi=%d/%d/%d/%d, last_seen=%u\n",
119 res->idx,
120 res->addr[0], res->addr[1], res->addr[2],
121 res->addr[3], res->addr[4], res->addr[5],
122 res->rssi[0], res->rssi[1], res->rssi[2],
123 res->rssi[3], res->last_seen);
124 }
125 return 0;
126}
127
128int mt76_amnt_dump(int idx, int argc, char **argv)
129{
130 struct nl_msg *msg, *tb1;
131 void *data;
132 int ret;
133 u8 amnt_idx = 0;
134
135 if (argc < 1)
136 return 1;
137
138 if (unl_genl_init(&unl, "nl80211") < 0) {
139 fprintf(stderr, "Failed to connect to nl80211\n");
140 return 2;
141 }
142
143 msg = unl_genl_msg(&unl, NL80211_CMD_VENDOR, true);
144
145 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, idx) ||
146 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
147 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL))
148 return false;
149
150 data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
151
152 tb1 = nla_nest_start(msg, MTK_VENDOR_ATTR_AMNT_CTRL_DUMP | NLA_F_NESTED);
153
154 amnt_idx = strtoul(argv[0], NULL, 0);
155 nla_put_u8(msg, MTK_VENDOR_ATTR_AMNT_DUMP_INDEX, amnt_idx);
156
157 nla_nest_end(msg, tb1);
158
159 nla_nest_end(msg, data);
160
161 ret = unl_genl_request(&unl, msg, mt76_amnt_dump_cb, NULL);
162 if (ret)
163 fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
164
165 unl_free(&unl);
166
167 return ret;
168}