blob: 3c4c6b22f9af1b485d60ee6320da3ebf2b3d9442 [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;
44 int rem, idx;
45 struct csi_data *c = &csi[csi_idx];
46
47 attr = unl_find_attr(&unl, msg, NL80211_ATTR_VENDOR_DATA);
48 if (!attr) {
49 fprintf(stderr, "Testdata attribute not found\n");
50 return NL_SKIP;
51 }
52
53 nla_parse_nested(tb, MTK_VENDOR_ATTR_CSI_CTRL_MAX,
54 attr, csi_ctrl_policy);
55
56 if (!tb[MTK_VENDOR_ATTR_CSI_CTRL_DATA])
57 return NL_SKIP;
58
59 nla_parse_nested(tb_data, MTK_VENDOR_ATTR_CSI_DATA_MAX,
60 tb[MTK_VENDOR_ATTR_CSI_CTRL_DATA], csi_data_policy);
61
62 if (!(tb_data[MTK_VENDOR_ATTR_CSI_DATA_VER] &&
63 tb_data[MTK_VENDOR_ATTR_CSI_DATA_TS] &&
64 tb_data[MTK_VENDOR_ATTR_CSI_DATA_RSSI] &&
65 tb_data[MTK_VENDOR_ATTR_CSI_DATA_SNR] &&
66 tb_data[MTK_VENDOR_ATTR_CSI_DATA_BW] &&
67 tb_data[MTK_VENDOR_ATTR_CSI_DATA_CH_IDX] &&
68 tb_data[MTK_VENDOR_ATTR_CSI_DATA_TA] &&
69 tb_data[MTK_VENDOR_ATTR_CSI_DATA_I] &&
70 tb_data[MTK_VENDOR_ATTR_CSI_DATA_Q] &&
71 tb_data[MTK_VENDOR_ATTR_CSI_DATA_INFO] &&
72 tb_data[MTK_VENDOR_ATTR_CSI_DATA_MODE] &&
73 tb_data[MTK_VENDOR_ATTR_CSI_DATA_H_IDX])) {
74 fprintf(stderr, "Attributes error for CSI data\n");
75 return NL_SKIP;
76 }
77
78 c->rssi = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_RSSI]);
79 c->snr = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_SNR]);
80 c->data_bw = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_BW]);
81 c->pri_ch_idx = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_CH_IDX]);
82 c->rx_mode = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_MODE]);
83
84 c->tx_idx = nla_get_u16(tb_data[MTK_VENDOR_ATTR_CSI_DATA_TX_ANT]);
85 c->rx_idx = nla_get_u16(tb_data[MTK_VENDOR_ATTR_CSI_DATA_RX_ANT]);
86
87 c->info = nla_get_u32(tb_data[MTK_VENDOR_ATTR_CSI_DATA_INFO]);
88 c->h_idx = nla_get_u32(tb_data[MTK_VENDOR_ATTR_CSI_DATA_H_IDX]);
89
90 c->ts = nla_get_u32(tb_data[MTK_VENDOR_ATTR_CSI_DATA_TS]);
91
92 idx = 0;
93 nla_for_each_nested(cur, tb_data[MTK_VENDOR_ATTR_CSI_DATA_TA], rem) {
94 c->ta[idx++] = nla_get_u8(cur);
95 }
96
97 idx = 0;
98 nla_for_each_nested(cur, tb_data[MTK_VENDOR_ATTR_CSI_DATA_I], rem) {
99 c->data_i[idx++] = nla_get_u16(cur);
100 }
101
102 idx = 0;
103 nla_for_each_nested(cur, tb_data[MTK_VENDOR_ATTR_CSI_DATA_Q], rem) {
104 c->data_q[idx++] = nla_get_u16(cur);
105 }
106
107 csi_idx++;
108
109 return NL_SKIP;
110}
111
112static int mt76_csi_to_json(const char *name)
113{
114#define MAX_BUF_SIZE 6000
115 FILE *f;
116 int i;
117
118 f = fopen(name, "a+");
119 if (!f) {
120 printf("open failure");
121 return 1;
122 }
123
124 fwrite("[", 1, 1, f);
125
126 for (i = 0; i < csi_idx; i++) {
127 char *pos, *buf = malloc(MAX_BUF_SIZE);
128 struct csi_data *c = &csi[i];
129 int j;
130
131 pos = buf;
132
133 pos += snprintf(pos, MAX_BUF_SIZE, "%c", '[');
134
developer6f8cffd2021-09-29 19:48:25 +0800135 pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->ts);
developer175704f2021-06-22 17:33:53 +0800136 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]);
137
138 pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->rssi);
139 pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->snr);
140 pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->data_bw);
141 pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->pri_ch_idx);
142 pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->rx_mode);
143 pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->tx_idx);
144 pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->rx_idx);
145 pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->h_idx);
146 pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->info);
147
148 pos += snprintf(pos, MAX_BUF_SIZE, "%c", '[');
149 for (j = 0; j < 256; j++) {
150 pos += snprintf(pos, MAX_BUF_SIZE, "%d", c->data_i[j]);
151 if (j != 255)
152 pos += snprintf(pos, MAX_BUF_SIZE, ",");
153 }
154 pos += snprintf(pos, MAX_BUF_SIZE, "%c,", ']');
155
156 pos += snprintf(pos, MAX_BUF_SIZE, "%c", '[');
157 for (j = 0; j < 256; j++) {
158 pos += snprintf(pos, MAX_BUF_SIZE, "%d", c->data_q[j]);
159 if (j != 255)
160 pos += snprintf(pos, MAX_BUF_SIZE, ",");
161 }
162 pos += snprintf(pos, MAX_BUF_SIZE, "%c", ']');
163
164 pos += snprintf(pos, MAX_BUF_SIZE, "%c", ']');
165 if (i != csi_idx - 1)
166 pos += snprintf(pos, MAX_BUF_SIZE, ",");
167
168 fwrite(buf, 1, pos - buf, f);
169 free(buf);
170 }
171
172 fwrite("]", 1, 1, f);
173 fclose(f);
developer6f8cffd2021-09-29 19:48:25 +0800174
175 return 0;
developer175704f2021-06-22 17:33:53 +0800176}
177
178int mt76_csi_dump(int idx, int argc, char **argv)
179{
developer6f8cffd2021-09-29 19:48:25 +0800180 int pkt_num, ret = 0, i;
developer175704f2021-06-22 17:33:53 +0800181 struct nl_msg *msg;
182 void *data;
183
184 if (argc < 2)
185 return 1;
186 pkt_num = strtol(argv[0], NULL, 10);
187
188#define CSI_DUMP_PER_NUM 3
189 csi_idx = 0;
190 csi = (struct csi_data *)calloc(pkt_num, sizeof(*csi));
191
192 for (i = 0; i < pkt_num / CSI_DUMP_PER_NUM; i++) {
193 if (unl_genl_init(&unl, "nl80211") < 0) {
194 fprintf(stderr, "Failed to connect to nl80211\n");
195 return 2;
196 }
197
198 msg = unl_genl_msg(&unl, NL80211_CMD_VENDOR, true);
199
200 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, idx) ||
201 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
202 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL))
203 return false;
204
205 data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
206
207 if (nla_put_u16(msg, MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM, CSI_DUMP_PER_NUM))
208 return false;
209
210 nla_nest_end(msg, data);
211
212 ret = unl_genl_request(&unl, msg, mt76_csi_dump_cb, NULL);
213 if (ret)
214 fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
215
216 unl_free(&unl);
217 }
218
219 mt76_csi_to_json(argv[1]);
220 free(csi);
221
222 return ret;
223}
224
225static int mt76_csi_set_attr(struct nl_msg *msg, int argc, char **argv)
226{
227 int idx = MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE;
228 char *val, *s1, *s2, *cur;
229 void *data;
230
231 val = strchr(argv[0], '=');
developer6f8cffd2021-09-29 19:48:25 +0800232 if (!val)
233 return -EINVAL;
234
235 *(val++) = 0;
developer175704f2021-06-22 17:33:53 +0800236
237 if (!strncmp(argv[0], "ctrl", 4)) {
238 s1 = s2 = strdup(val);
239 data = nla_nest_start(msg, MTK_VENDOR_ATTR_CSI_CTRL_CFG | NLA_F_NESTED);
240
241 while ((cur = strsep(&s1, ",")) != NULL)
242 nla_put_u8(msg, idx++, strtoul(cur, NULL, 0));
243
244 nla_nest_end(msg, data);
245
246 free(s2);
247
248 if (argc == 2 &&
249 !strncmp(argv[1], "mac_addr", strlen("mac_addr"))) {
250 u8 a[ETH_ALEN];
251 int matches, i;
252
253 val = strchr(argv[1], '=');
254 if (val)
255 *(val++) = 0;
256
257 matches = sscanf(val, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
258 a, a+1, a+2, a+3, a+4, a+5);
259
260 if (matches != ETH_ALEN)
261 return -EINVAL;
262
263 data = nla_nest_start(msg, MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR | NLA_F_NESTED);
264 for (i = 0; i < ETH_ALEN; i++)
265 nla_put_u8(msg, i, a[i]);
266
267 nla_nest_end(msg, data);
268 }
269 } else if (!strncmp(argv[0], "interval", 8)) {
270 nla_put_u32(msg, MTK_VENDOR_ATTR_CSI_CTRL_INTERVAL, strtoul(val, NULL, 0));
271 }
272
273 return 0;
274}
275
276int mt76_csi_set(int idx, int argc, char **argv)
277{
278 struct nl_msg *msg;
279 void *data;
280 int ret;
281
282 if (argc < 1)
283 return 1;
284
285 if (unl_genl_init(&unl, "nl80211") < 0) {
286 fprintf(stderr, "Failed to connect to nl80211\n");
287 return 2;
288 }
289
290 msg = unl_genl_msg(&unl, NL80211_CMD_VENDOR, false);
291
292 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, idx) ||
293 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
294 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL))
295 return false;
296
297 data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
298
299 mt76_csi_set_attr(msg, argc, argv);
300
301 nla_nest_end(msg, data);
302
303 ret = unl_genl_request(&unl, msg, NULL, NULL);
304 if (ret)
305 fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
306
307 unl_free(&unl);
308
309 return ret;
310}