blob: 76da857a5ba23e9597f5ce5383425a4414f62136 [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
135 pos += snprintf(pos, MAX_BUF_SIZE, "%ld,", c->ts);
136 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);
174}
175
176int mt76_csi_dump(int idx, int argc, char **argv)
177{
178 int pkt_num, ret, i;
179 struct nl_msg *msg;
180 void *data;
181
182 if (argc < 2)
183 return 1;
184 pkt_num = strtol(argv[0], NULL, 10);
185
186#define CSI_DUMP_PER_NUM 3
187 csi_idx = 0;
188 csi = (struct csi_data *)calloc(pkt_num, sizeof(*csi));
189
190 for (i = 0; i < pkt_num / CSI_DUMP_PER_NUM; i++) {
191 if (unl_genl_init(&unl, "nl80211") < 0) {
192 fprintf(stderr, "Failed to connect to nl80211\n");
193 return 2;
194 }
195
196 msg = unl_genl_msg(&unl, NL80211_CMD_VENDOR, true);
197
198 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, idx) ||
199 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
200 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL))
201 return false;
202
203 data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
204
205 if (nla_put_u16(msg, MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM, CSI_DUMP_PER_NUM))
206 return false;
207
208 nla_nest_end(msg, data);
209
210 ret = unl_genl_request(&unl, msg, mt76_csi_dump_cb, NULL);
211 if (ret)
212 fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
213
214 unl_free(&unl);
215 }
216
217 mt76_csi_to_json(argv[1]);
218 free(csi);
219
220 return ret;
221}
222
223static int mt76_csi_set_attr(struct nl_msg *msg, int argc, char **argv)
224{
225 int idx = MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE;
226 char *val, *s1, *s2, *cur;
227 void *data;
228
229 val = strchr(argv[0], '=');
230 if (val)
231 *(val++) = 0;
232
233 if (!strncmp(argv[0], "ctrl", 4)) {
234 s1 = s2 = strdup(val);
235 data = nla_nest_start(msg, MTK_VENDOR_ATTR_CSI_CTRL_CFG | NLA_F_NESTED);
236
237 while ((cur = strsep(&s1, ",")) != NULL)
238 nla_put_u8(msg, idx++, strtoul(cur, NULL, 0));
239
240 nla_nest_end(msg, data);
241
242 free(s2);
243
244 if (argc == 2 &&
245 !strncmp(argv[1], "mac_addr", strlen("mac_addr"))) {
246 u8 a[ETH_ALEN];
247 int matches, i;
248
249 val = strchr(argv[1], '=');
250 if (val)
251 *(val++) = 0;
252
253 matches = sscanf(val, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
254 a, a+1, a+2, a+3, a+4, a+5);
255
256 if (matches != ETH_ALEN)
257 return -EINVAL;
258
259 data = nla_nest_start(msg, MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR | NLA_F_NESTED);
260 for (i = 0; i < ETH_ALEN; i++)
261 nla_put_u8(msg, i, a[i]);
262
263 nla_nest_end(msg, data);
264 }
265 } else if (!strncmp(argv[0], "interval", 8)) {
266 nla_put_u32(msg, MTK_VENDOR_ATTR_CSI_CTRL_INTERVAL, strtoul(val, NULL, 0));
267 }
268
269 return 0;
270}
271
272int mt76_csi_set(int idx, int argc, char **argv)
273{
274 struct nl_msg *msg;
275 void *data;
276 int ret;
277
278 if (argc < 1)
279 return 1;
280
281 if (unl_genl_init(&unl, "nl80211") < 0) {
282 fprintf(stderr, "Failed to connect to nl80211\n");
283 return 2;
284 }
285
286 msg = unl_genl_msg(&unl, NL80211_CMD_VENDOR, false);
287
288 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, idx) ||
289 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
290 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL))
291 return false;
292
293 data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
294
295 mt76_csi_set_attr(msg, argc, argv);
296
297 nla_nest_end(msg, data);
298
299 ret = unl_genl_request(&unl, msg, NULL, NULL);
300 if (ret)
301 fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
302
303 unl_free(&unl);
304
305 return ret;
306}