blob: d99eb58313f04948f3f84b2ba5f7b9ad9d9ff251 [file] [log] [blame]
developer175704f2021-06-22 17:33:53 +08001/* Copyright (C) 2021 Mediatek Inc. */
2#define _GNU_SOURCE
3
4#include "mt76-vendor.h"
5
6struct csi_data *csi;
7int csi_idx;
8
9static struct nla_policy csi_ctrl_policy[NUM_MTK_VENDOR_ATTRS_CSI_CTRL] = {
10 [MTK_VENDOR_ATTR_CSI_CTRL_CFG] = { .type = NLA_NESTED },
11 [MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE] = { .type = NLA_U8 },
12 [MTK_VENDOR_ATTR_CSI_CTRL_CFG_TYPE] = { .type = NLA_U8 },
13 [MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL1] = { .type = NLA_U8 },
14 [MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL2] = { .type = NLA_U8 },
15 [MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR] = { .type = NLA_NESTED },
16 [MTK_VENDOR_ATTR_CSI_CTRL_INTERVAL] = { .type = NLA_U32 },
17 [MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM] = { .type = NLA_U16 },
18 [MTK_VENDOR_ATTR_CSI_CTRL_DATA] = { .type = NLA_NESTED },
19};
20
21static struct nla_policy csi_data_policy[NUM_MTK_VENDOR_ATTRS_CSI_DATA] = {
22 [MTK_VENDOR_ATTR_CSI_DATA_VER] = { .type = NLA_U8 },
23 [MTK_VENDOR_ATTR_CSI_DATA_TS] = { .type = NLA_U32 },
24 [MTK_VENDOR_ATTR_CSI_DATA_RSSI] = { .type = NLA_U8 },
25 [MTK_VENDOR_ATTR_CSI_DATA_SNR] = { .type = NLA_U8 },
26 [MTK_VENDOR_ATTR_CSI_DATA_BW] = { .type = NLA_U8 },
27 [MTK_VENDOR_ATTR_CSI_DATA_CH_IDX] = { .type = NLA_U8 },
28 [MTK_VENDOR_ATTR_CSI_DATA_TA] = { .type = NLA_NESTED },
29 [MTK_VENDOR_ATTR_CSI_DATA_I] = { .type = NLA_NESTED },
30 [MTK_VENDOR_ATTR_CSI_DATA_Q] = { .type = NLA_NESTED },
31 [MTK_VENDOR_ATTR_CSI_DATA_INFO] = { .type = NLA_U32 },
32 [MTK_VENDOR_ATTR_CSI_DATA_TX_ANT] = { .type = NLA_U8 },
33 [MTK_VENDOR_ATTR_CSI_DATA_RX_ANT] = { .type = NLA_U8 },
34 [MTK_VENDOR_ATTR_CSI_DATA_MODE] = { .type = NLA_U8 },
35 [MTK_VENDOR_ATTR_CSI_DATA_H_IDX] = { .type = NLA_U32 },
36};
37
38static int mt76_csi_dump_cb(struct nl_msg *msg, void *arg)
39{
40 struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_CSI_CTRL];
41 struct nlattr *tb_data[NUM_MTK_VENDOR_ATTRS_CSI_DATA];
42 struct nlattr *attr;
43 struct nlattr *cur;
developer0497a7b2021-10-04 10:00:27 +080044 size_t idx;
45 int rem;
developer175704f2021-06-22 17:33:53 +080046 struct csi_data *c = &csi[csi_idx];
47
48 attr = unl_find_attr(&unl, msg, NL80211_ATTR_VENDOR_DATA);
49 if (!attr) {
50 fprintf(stderr, "Testdata attribute not found\n");
51 return NL_SKIP;
52 }
53
54 nla_parse_nested(tb, MTK_VENDOR_ATTR_CSI_CTRL_MAX,
55 attr, csi_ctrl_policy);
56
57 if (!tb[MTK_VENDOR_ATTR_CSI_CTRL_DATA])
58 return NL_SKIP;
59
60 nla_parse_nested(tb_data, MTK_VENDOR_ATTR_CSI_DATA_MAX,
61 tb[MTK_VENDOR_ATTR_CSI_CTRL_DATA], csi_data_policy);
62
63 if (!(tb_data[MTK_VENDOR_ATTR_CSI_DATA_VER] &&
64 tb_data[MTK_VENDOR_ATTR_CSI_DATA_TS] &&
65 tb_data[MTK_VENDOR_ATTR_CSI_DATA_RSSI] &&
66 tb_data[MTK_VENDOR_ATTR_CSI_DATA_SNR] &&
67 tb_data[MTK_VENDOR_ATTR_CSI_DATA_BW] &&
68 tb_data[MTK_VENDOR_ATTR_CSI_DATA_CH_IDX] &&
69 tb_data[MTK_VENDOR_ATTR_CSI_DATA_TA] &&
70 tb_data[MTK_VENDOR_ATTR_CSI_DATA_I] &&
71 tb_data[MTK_VENDOR_ATTR_CSI_DATA_Q] &&
72 tb_data[MTK_VENDOR_ATTR_CSI_DATA_INFO] &&
73 tb_data[MTK_VENDOR_ATTR_CSI_DATA_MODE] &&
74 tb_data[MTK_VENDOR_ATTR_CSI_DATA_H_IDX])) {
75 fprintf(stderr, "Attributes error for CSI data\n");
76 return NL_SKIP;
77 }
78
79 c->rssi = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_RSSI]);
80 c->snr = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_SNR]);
81 c->data_bw = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_BW]);
82 c->pri_ch_idx = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_CH_IDX]);
83 c->rx_mode = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_MODE]);
84
85 c->tx_idx = nla_get_u16(tb_data[MTK_VENDOR_ATTR_CSI_DATA_TX_ANT]);
86 c->rx_idx = nla_get_u16(tb_data[MTK_VENDOR_ATTR_CSI_DATA_RX_ANT]);
87
88 c->info = nla_get_u32(tb_data[MTK_VENDOR_ATTR_CSI_DATA_INFO]);
89 c->h_idx = nla_get_u32(tb_data[MTK_VENDOR_ATTR_CSI_DATA_H_IDX]);
90
91 c->ts = nla_get_u32(tb_data[MTK_VENDOR_ATTR_CSI_DATA_TS]);
92
93 idx = 0;
94 nla_for_each_nested(cur, tb_data[MTK_VENDOR_ATTR_CSI_DATA_TA], rem) {
developer0497a7b2021-10-04 10:00:27 +080095 if (idx < ETH_ALEN)
96 c->ta[idx++] = nla_get_u8(cur);
developer175704f2021-06-22 17:33:53 +080097 }
98
99 idx = 0;
100 nla_for_each_nested(cur, tb_data[MTK_VENDOR_ATTR_CSI_DATA_I], rem) {
developer0497a7b2021-10-04 10:00:27 +0800101 if (idx < CSI_MAX_COUNT)
102 c->data_i[idx++] = nla_get_u16(cur);
developer175704f2021-06-22 17:33:53 +0800103 }
104
105 idx = 0;
106 nla_for_each_nested(cur, tb_data[MTK_VENDOR_ATTR_CSI_DATA_Q], rem) {
developer0497a7b2021-10-04 10:00:27 +0800107 if (idx < CSI_MAX_COUNT)
108 c->data_q[idx++] = nla_get_u16(cur);
developer175704f2021-06-22 17:33:53 +0800109 }
110
111 csi_idx++;
112
113 return NL_SKIP;
114}
115
116static int mt76_csi_to_json(const char *name)
117{
118#define MAX_BUF_SIZE 6000
119 FILE *f;
developer0497a7b2021-10-04 10:00:27 +0800120 int i, ret = -ENOMEM;
developer175704f2021-06-22 17:33:53 +0800121
122 f = fopen(name, "a+");
123 if (!f) {
124 printf("open failure");
125 return 1;
126 }
127
developer0497a7b2021-10-04 10:00:27 +0800128 if (fwrite("[", 1, 1, f) != 1) {
129 perror("fwrite");
130 goto out;
131 }
developer175704f2021-06-22 17:33:53 +0800132
133 for (i = 0; i < csi_idx; i++) {
developer175704f2021-06-22 17:33:53 +0800134 struct csi_data *c = &csi[i];
developer0497a7b2021-10-04 10:00:27 +0800135 char *pos, *buf;
developer175704f2021-06-22 17:33:53 +0800136 int j;
137
developer0497a7b2021-10-04 10:00:27 +0800138 buf = malloc(MAX_BUF_SIZE);
139 if (!buf)
140 goto out;
developer175704f2021-06-22 17:33:53 +0800141
developer0497a7b2021-10-04 10:00:27 +0800142 pos = buf;
developer175704f2021-06-22 17:33:53 +0800143 pos += snprintf(pos, MAX_BUF_SIZE, "%c", '[');
144
developer6f8cffd2021-09-29 19:48:25 +0800145 pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->ts);
developer175704f2021-06-22 17:33:53 +0800146 pos += snprintf(pos, MAX_BUF_SIZE, "\"%02x%02x%02x%02x%02x%02x\",", c->ta[0], c->ta[1], c->ta[2], c->ta[3], c->ta[4], c->ta[5]);
147
148 pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->rssi);
149 pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->snr);
150 pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->data_bw);
151 pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->pri_ch_idx);
152 pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->rx_mode);
153 pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->tx_idx);
154 pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->rx_idx);
155 pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->h_idx);
156 pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->info);
157
158 pos += snprintf(pos, MAX_BUF_SIZE, "%c", '[');
159 for (j = 0; j < 256; j++) {
160 pos += snprintf(pos, MAX_BUF_SIZE, "%d", c->data_i[j]);
161 if (j != 255)
162 pos += snprintf(pos, MAX_BUF_SIZE, ",");
163 }
164 pos += snprintf(pos, MAX_BUF_SIZE, "%c,", ']');
165
166 pos += snprintf(pos, MAX_BUF_SIZE, "%c", '[');
167 for (j = 0; j < 256; j++) {
168 pos += snprintf(pos, MAX_BUF_SIZE, "%d", c->data_q[j]);
169 if (j != 255)
170 pos += snprintf(pos, MAX_BUF_SIZE, ",");
171 }
172 pos += snprintf(pos, MAX_BUF_SIZE, "%c", ']');
173
174 pos += snprintf(pos, MAX_BUF_SIZE, "%c", ']');
175 if (i != csi_idx - 1)
176 pos += snprintf(pos, MAX_BUF_SIZE, ",");
177
developer0497a7b2021-10-04 10:00:27 +0800178 if (fwrite(buf, 1, pos - buf, f) != (pos - buf)) {
179 perror("fwrite");
180 free(buf);
181 goto out;
182 }
183
developer175704f2021-06-22 17:33:53 +0800184 free(buf);
185 }
186
developer0497a7b2021-10-04 10:00:27 +0800187 if (fwrite("]", 1, 1, f) != 1) {
188 perror("fwrite");
189 goto out;
190 }
developer6f8cffd2021-09-29 19:48:25 +0800191
developer0497a7b2021-10-04 10:00:27 +0800192 ret = 0;
193out:
194 if (fclose(f))
195 perror("fclose");
196
197 return ret;
developer175704f2021-06-22 17:33:53 +0800198}
199
200int mt76_csi_dump(int idx, int argc, char **argv)
201{
developer6f8cffd2021-09-29 19:48:25 +0800202 int pkt_num, ret = 0, i;
developer175704f2021-06-22 17:33:53 +0800203 struct nl_msg *msg;
204 void *data;
205
206 if (argc < 2)
207 return 1;
developer0497a7b2021-10-04 10:00:27 +0800208
developer175704f2021-06-22 17:33:53 +0800209 pkt_num = strtol(argv[0], NULL, 10);
developer0497a7b2021-10-04 10:00:27 +0800210 if (pkt_num < 0 || pkt_num > 30000)
211 return -EINVAL;
developer175704f2021-06-22 17:33:53 +0800212
213#define CSI_DUMP_PER_NUM 3
214 csi_idx = 0;
215 csi = (struct csi_data *)calloc(pkt_num, sizeof(*csi));
216
217 for (i = 0; i < pkt_num / CSI_DUMP_PER_NUM; i++) {
218 if (unl_genl_init(&unl, "nl80211") < 0) {
219 fprintf(stderr, "Failed to connect to nl80211\n");
220 return 2;
221 }
222
223 msg = unl_genl_msg(&unl, NL80211_CMD_VENDOR, true);
224
225 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, idx) ||
226 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
227 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL))
228 return false;
229
230 data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
developer0497a7b2021-10-04 10:00:27 +0800231 if (!data)
232 return -ENOMEM;
developer175704f2021-06-22 17:33:53 +0800233
234 if (nla_put_u16(msg, MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM, CSI_DUMP_PER_NUM))
235 return false;
236
237 nla_nest_end(msg, data);
238
239 ret = unl_genl_request(&unl, msg, mt76_csi_dump_cb, NULL);
240 if (ret)
241 fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
242
243 unl_free(&unl);
244 }
245
246 mt76_csi_to_json(argv[1]);
247 free(csi);
248
249 return ret;
250}
251
252static int mt76_csi_set_attr(struct nl_msg *msg, int argc, char **argv)
253{
254 int idx = MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE;
255 char *val, *s1, *s2, *cur;
256 void *data;
257
258 val = strchr(argv[0], '=');
developer6f8cffd2021-09-29 19:48:25 +0800259 if (!val)
260 return -EINVAL;
261
262 *(val++) = 0;
developer175704f2021-06-22 17:33:53 +0800263
264 if (!strncmp(argv[0], "ctrl", 4)) {
developer175704f2021-06-22 17:33:53 +0800265 data = nla_nest_start(msg, MTK_VENDOR_ATTR_CSI_CTRL_CFG | NLA_F_NESTED);
developer0497a7b2021-10-04 10:00:27 +0800266 if (!data)
267 return -ENOMEM;
developer175704f2021-06-22 17:33:53 +0800268
developer0497a7b2021-10-04 10:00:27 +0800269 s1 = s2 = strdup(val);
270
271 while ((cur = strsep(&s1, ",")) != NULL) {
272 u8 param = strtoul(cur, NULL, 0);
273
274 nla_put_u8(msg, idx++, param);
275 }
developer175704f2021-06-22 17:33:53 +0800276
277 nla_nest_end(msg, data);
278
279 free(s2);
280
281 if (argc == 2 &&
282 !strncmp(argv[1], "mac_addr", strlen("mac_addr"))) {
283 u8 a[ETH_ALEN];
284 int matches, i;
285
286 val = strchr(argv[1], '=');
developer0497a7b2021-10-04 10:00:27 +0800287 if (!val)
288 return -EINVAL;
developer175704f2021-06-22 17:33:53 +0800289
developer0497a7b2021-10-04 10:00:27 +0800290 *(val++) = 0;
developer175704f2021-06-22 17:33:53 +0800291 matches = sscanf(val, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
292 a, a+1, a+2, a+3, a+4, a+5);
293
294 if (matches != ETH_ALEN)
295 return -EINVAL;
296
297 data = nla_nest_start(msg, MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR | NLA_F_NESTED);
developer0497a7b2021-10-04 10:00:27 +0800298 if (!data)
299 return -ENOMEM;
300
developer175704f2021-06-22 17:33:53 +0800301 for (i = 0; i < ETH_ALEN; i++)
302 nla_put_u8(msg, i, a[i]);
303
304 nla_nest_end(msg, data);
305 }
306 } else if (!strncmp(argv[0], "interval", 8)) {
developer0497a7b2021-10-04 10:00:27 +0800307 u32 interval = strtoul(val, NULL, 0);
308
309 nla_put_u32(msg, MTK_VENDOR_ATTR_CSI_CTRL_INTERVAL, interval);
developer175704f2021-06-22 17:33:53 +0800310 }
311
312 return 0;
313}
314
315int mt76_csi_set(int idx, int argc, char **argv)
316{
317 struct nl_msg *msg;
318 void *data;
319 int ret;
320
321 if (argc < 1)
322 return 1;
323
324 if (unl_genl_init(&unl, "nl80211") < 0) {
325 fprintf(stderr, "Failed to connect to nl80211\n");
326 return 2;
327 }
328
329 msg = unl_genl_msg(&unl, NL80211_CMD_VENDOR, false);
330
331 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, idx) ||
332 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
333 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL))
334 return false;
335
336 data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
developer0497a7b2021-10-04 10:00:27 +0800337 if (!data)
338 return -ENOMEM;
developer175704f2021-06-22 17:33:53 +0800339
340 mt76_csi_set_attr(msg, argc, argv);
341
342 nla_nest_end(msg, data);
343
344 ret = unl_genl_request(&unl, msg, NULL, NULL);
345 if (ret)
346 fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
347
348 unl_free(&unl);
349
350 return ret;
351}