blob: 9c4c4e562fef4488ed120b2538e4b486d5017fa6 [file] [log] [blame]
developer66e89bc2024-04-23 14:50:01 +08001From c125d2615df25bd9a5a4801abfbcc91f21482e02 Mon Sep 17 00:00:00 2001
2From: mtk20656 <chank.chen@mediatek.com>
3Date: Tue, 6 Feb 2024 15:46:05 +0800
4Subject: [PATCH 098/104] mtk: hostapd: add connac3 csi control interface
5
61. add hostapd_cli interface
72. add csi set/dump flow
83. add csi raw data to json
9
developer66e89bc2024-04-23 14:50:01 +080010Signed-off-by: mtk20656 <chank.chen@mediatek.com>
11---
12 hostapd/ctrl_iface.c | 193 ++++++++++++++++++++++++
13 hostapd/hostapd_cli.c | 16 ++
14 src/ap/ap_drv_ops.c | 13 ++
15 src/ap/ap_drv_ops.h | 2 +
16 src/common/mtk_vendor.h | 31 +++-
17 src/drivers/driver.h | 16 ++
18 src/drivers/driver_nl80211.c | 235 ++++++++++++++++++++++++++++++
19 src/drivers/driver_nl80211.h | 1 +
20 src/drivers/driver_nl80211_capa.c | 3 +
21 9 files changed, 503 insertions(+), 7 deletions(-)
22
23diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
24index f0c990314..b5f6431bf 100644
25--- a/hostapd/ctrl_iface.c
26+++ b/hostapd/ctrl_iface.c
27@@ -4925,6 +4925,193 @@ hostapd_ctrl_iface_disable_beacon(struct hostapd_data *hapd, char *value,
28
29 }
30
31+static int
32+hostapd_ctrl_iface_set_csi(struct hostapd_data *hapd, char *cmd,
33+ char *buf, size_t buflen)
34+{
35+ char *tmp;
36+ u8 sta_mac[ETH_ALEN] = {0};
37+ u32 csi_para[4] = {0};
38+ char mac_str[18] = {0};
39+ u8 csi_para_cnt = 0;
40+
41+ tmp = strtok_r(cmd, ",", &cmd);
42+
43+ while (tmp) {
44+ csi_para_cnt++;
45+
46+ if (csi_para_cnt <= 4)
47+ csi_para[csi_para_cnt - 1] = strtol(tmp, &tmp, 10);
48+ else if (csi_para_cnt == 5) {
49+ memcpy(mac_str, tmp, sizeof(mac_str) - 1);
50+ break;
51+ }
52+
53+ tmp = strtok_r(NULL, ",", &cmd);
54+ }
55+
56+ if (strlen(mac_str)) { /* user input mac string */
57+ if (hwaddr_aton(mac_str, sta_mac) < 0) {
58+ wpa_printf(MSG_ERROR, "station mac is not right.\n");
59+ return -1;
60+ }
61+
62+ if (hostapd_drv_csi_set(hapd, csi_para[0], csi_para[1], csi_para[2], csi_para[3], sta_mac)) {
63+ wpa_printf(MSG_ERROR, "Not able to set csi, %d,%d,%d,%d,%s\n",
64+ csi_para[0], csi_para[1], csi_para[2], csi_para[3], mac_str);
65+ return -1;
66+ }
67+ } else {
68+ if (hostapd_drv_csi_set(hapd, csi_para[0], csi_para[1], csi_para[2], csi_para[3], NULL)) {
69+ wpa_printf(MSG_ERROR, "Not able to set csi, %d,%d,%d,%d\n",
70+ csi_para[0], csi_para[1], csi_para[2], csi_para[3]);
71+ return -1;
72+ }
73+ }
74+
75+ return os_snprintf(buf, buflen, "OK\n");
76+}
77+
78+static int mt76_csi_to_json(char *fname, struct csi_resp_data *resp_buf)
79+{
80+#define MAX_BUF_SIZE 10000
81+ FILE *f;
82+ int i;
83+
84+ if (!fname) {
85+ wpa_printf(MSG_ERROR, "csi dump file name is null!\n");
86+ return -1;
87+ }
88+
89+ f = fopen(fname, "a+");
90+ if (!f) {
91+ wpa_printf(MSG_ERROR, "open csi dump file %s failed\n", fname);
92+ return -1;
93+ }
94+
95+ if (fwrite("[", 1, 1, f) != 1) {
96+ fclose(f);
97+ return -1;
98+ }
99+
100+ for (i = 0; i < resp_buf->buf_cnt; i++) {
101+ struct csi_data *c = &resp_buf->csi_buf[i];
102+ char *pos, *buf;
103+ int j;
104+
105+ buf = malloc(MAX_BUF_SIZE);
106+ if (!buf) {
107+ fclose(f);
108+ return -1;
109+ }
110+
111+ pos = buf;
112+ pos += snprintf(pos, MAX_BUF_SIZE, "%c", '[');
113+
114+ pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->ts);
115+ 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]);
116+
117+ pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->rssi);
118+ pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->snr);
119+ pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->data_bw);
120+ pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->pri_ch_idx);
121+ pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->rx_mode);
122+ pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->tx_idx);
123+ pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->rx_idx);
124+ pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->chain_info);
125+ pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->ext_info);
126+
127+ pos += snprintf(pos, MAX_BUF_SIZE, "%c", '[');
128+ for (j = 0; j < c->data_num; j++) {
129+ pos += snprintf(pos, MAX_BUF_SIZE, "%d", c->data_i[j]);
130+ if (j != (c->data_num - 1))
131+ pos += snprintf(pos, MAX_BUF_SIZE, ",");
132+ }
133+ pos += snprintf(pos, MAX_BUF_SIZE, "%c,", ']');
134+
135+ pos += snprintf(pos, MAX_BUF_SIZE, "%c", '[');
136+ for (j = 0; j < c->data_num; j++) {
137+ pos += snprintf(pos, MAX_BUF_SIZE, "%d", c->data_q[j]);
138+ if (j != (c->data_num - 1))
139+ pos += snprintf(pos, MAX_BUF_SIZE, ",");
140+ }
141+ pos += snprintf(pos, MAX_BUF_SIZE, "%c", ']');
142+
143+ pos += snprintf(pos, MAX_BUF_SIZE, "%c", ']');
144+ if (i != resp_buf->buf_cnt - 1)
145+ pos += snprintf(pos, MAX_BUF_SIZE, ",");
146+
147+ if (fwrite(buf, 1, pos - buf, f) != (pos - buf)) {
148+ perror("fwrite");
149+ free(buf);
150+ fclose(f);
151+ return -1;
152+ }
153+
154+ free(buf);
155+ }
156+
157+ if (fwrite("]", 1, 1, f) != 1) {
158+ fclose(f);
159+ return -1;
160+ }
161+
162+ fclose(f);
163+
164+ return 0;
165+}
166+
167+static int
168+hostapd_ctrl_iface_dump_csi(struct hostapd_data *hapd, char *cmd,
169+ char *buf, size_t buflen)
170+{
171+ char *tmp, *fname;
172+ int data_cnt = 0, ret = 0;
173+ struct csi_resp_data resp_buf;
174+
175+ tmp = strtok_r(cmd, ",", &cmd);
176+
177+ if (!tmp) {
178+ wpa_printf(MSG_ERROR, "Error in command format\n");
179+ return -1;
180+ }
181+
182+ data_cnt = strtoul(tmp, &tmp, 0);
183+
184+ if (data_cnt > 3000) {
185+ wpa_printf(MSG_ERROR, "Wrong input csi data cnt\n");
186+ return -1;
187+ }
188+
189+ fname = strtok_r(NULL, ",", &cmd);
190+
191+ if (!fname) {
192+ wpa_printf(MSG_ERROR, "Error in command format, csi_filename.\n");
193+ return -1;
194+ }
195+
196+ resp_buf.csi_buf = (struct csi_data *)os_zalloc(sizeof(struct csi_data) * data_cnt);
197+
198+ if (resp_buf.csi_buf == NULL) {
199+ wpa_printf(MSG_ERROR, "Error in memory allocation\n");
200+ return -1;
201+ }
202+
203+ resp_buf.usr_need_cnt = data_cnt;
204+ resp_buf.buf_cnt = 0;
205+
206+ if (hostapd_drv_csi_dump(hapd, (void *)&resp_buf)) {
207+ wpa_printf(MSG_ERROR, "Not able to set csi dump\n");
208+ os_free(resp_buf.csi_buf);
209+ return -1;
210+ }
211+
212+ mt76_csi_to_json(fname, &resp_buf);
213+
214+ os_free(resp_buf.csi_buf);
215+ return 0;
216+}
217+
218 static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
219 char *buf, char *reply,
220 int reply_size,
221@@ -5578,6 +5765,12 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
222 } else if (os_strncmp(buf, "NO_BEACON ", 10) == 0) {
223 reply_len = hostapd_ctrl_iface_disable_beacon(hapd, buf + 10, reply,
224 reply_size);
225+ } else if (os_strncmp(buf, "SET_CSI ", 7) == 0) {
226+ reply_len = hostapd_ctrl_iface_set_csi(hapd, buf + 8,
227+ reply, reply_size);
228+ } else if (os_strncmp(buf, "DUMP_CSI ", 8) == 0) {
229+ reply_len = hostapd_ctrl_iface_dump_csi(hapd, buf + 9,
230+ reply, reply_size);
231 } else {
232 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
233 reply_len = 16;
234diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
235index acfa3b1d1..81b74d6de 100644
236--- a/hostapd/hostapd_cli.c
237+++ b/hostapd/hostapd_cli.c
238@@ -1719,6 +1719,18 @@ static int hostapd_cli_cmd_dump_amnt(struct wpa_ctrl *ctrl, int argc,
239 return hostapd_cli_cmd(ctrl, "DUMP_AMNT", 1, argc, argv);
240 }
241
242+static int hostapd_cli_cmd_set_csi(struct wpa_ctrl *ctrl, int argc,
243+ char *argv[])
244+{
245+ return hostapd_cli_cmd(ctrl, "SET_CSI", 1, argc, argv);
246+}
247+
248+static int hostapd_cli_cmd_dump_csi(struct wpa_ctrl *ctrl, int argc,
249+ char *argv[])
250+{
251+ return hostapd_cli_cmd(ctrl, "DUMP_CSI", 1, argc, argv);
252+}
253+
254 struct hostapd_cli_cmd {
255 const char *cmd;
256 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
257@@ -1960,6 +1972,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
258 " = Set Station index and mac to monitor"},
259 { "dump_amnt", hostapd_cli_cmd_dump_amnt, NULL,
260 " = Dump RSSI of monitoring Station"},
261+ { "set_csi", hostapd_cli_cmd_set_csi, NULL,
262+ " = Set csi configuaration"},
263+ { "dump_csi", hostapd_cli_cmd_dump_csi, NULL,
264+ " = Dump csi data to a json file"},
265 { NULL, NULL, NULL, NULL }
266 };
267
268diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
269index 3c1609656..cb782fa31 100644
270--- a/src/ap/ap_drv_ops.c
271+++ b/src/ap/ap_drv_ops.c
272@@ -1409,3 +1409,16 @@ int hostapd_drv_beacon_ctrl(struct hostapd_data *hapd, u8 beacon_mode)
273 return hapd->driver->beacon_ctrl(hapd->drv_priv, beacon_mode);
274 }
275
276+int hostapd_drv_csi_set(struct hostapd_data *hapd, u8 mode, u8 cfg, u8 v1, u32 v2, u8 *mac)
277+{
278+ if (!hapd->driver || !hapd->driver->csi_set)
279+ return 0;
280+ return hapd->driver->csi_set(hapd->drv_priv, mode, cfg, v1, v2, mac);
281+}
282+
283+int hostapd_drv_csi_dump(struct hostapd_data *hapd, void *dump_buf)
284+{
285+ if (!hapd->driver || !hapd->driver->csi_dump)
286+ return 0;
287+ return hapd->driver->csi_dump(hapd->drv_priv, dump_buf);
288+}
289diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
290index 5830705a3..7abc58377 100644
291--- a/src/ap/ap_drv_ops.h
292+++ b/src/ap/ap_drv_ops.h
293@@ -171,6 +171,8 @@ int hostapd_drv_amnt_dump(struct hostapd_data *hapd, u8 amnt_idx, u8 *amnt_dump_
294 int hostapd_drv_background_radar_mode(struct hostapd_data *hapd);
295 int hostapd_drv_pp_mode_set(struct hostapd_data *hapd);
296 int hostapd_drv_beacon_ctrl(struct hostapd_data *hapd, u8 beacon_mode);
297+int hostapd_drv_csi_set(struct hostapd_data *hapd, u8 mode, u8 cfg, u8 v1, u32 v2, u8 *mac);
298+int hostapd_drv_csi_dump(struct hostapd_data *hapd, void *dump_buf);
299
300 #include "drivers/driver.h"
301
302diff --git a/src/common/mtk_vendor.h b/src/common/mtk_vendor.h
303index 1e4c3670e..c290e72a7 100644
304--- a/src/common/mtk_vendor.h
305+++ b/src/common/mtk_vendor.h
306@@ -73,7 +73,6 @@ enum mtk_vendor_attr_csi_ctrl {
307 MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL1,
308 MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL2,
309 MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR,
310- MTK_VENDOR_ATTR_CSI_CTRL_INTERVAL,
311
312 MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM,
313
314@@ -96,6 +95,7 @@ enum mtk_vendor_attr_csi_data {
315 MTK_VENDOR_ATTR_CSI_DATA_BW,
316 MTK_VENDOR_ATTR_CSI_DATA_CH_IDX,
317 MTK_VENDOR_ATTR_CSI_DATA_TA,
318+ MTK_VENDOR_ATTR_CSI_DATA_NUM,
319 MTK_VENDOR_ATTR_CSI_DATA_I,
320 MTK_VENDOR_ATTR_CSI_DATA_Q,
321 MTK_VENDOR_ATTR_CSI_DATA_INFO,
322@@ -106,7 +106,7 @@ enum mtk_vendor_attr_csi_data {
323 MTK_VENDOR_ATTR_CSI_DATA_TX_ANT,
324 MTK_VENDOR_ATTR_CSI_DATA_RX_ANT,
325 MTK_VENDOR_ATTR_CSI_DATA_MODE,
326- MTK_VENDOR_ATTR_CSI_DATA_H_IDX,
327+ MTK_VENDOR_ATTR_CSI_DATA_CHAIN_INFO,
328
329 /* keep last */
330 NUM_MTK_VENDOR_ATTRS_CSI_DATA,
331@@ -281,23 +281,40 @@ enum mtk_vendor_attr_beacon_ctrl {
332 NUM_MTK_VENDOR_ATTRS_BEACON_CTRL - 1
333 };
334
335-#define CSI_MAX_COUNT 256
336+#define CSI_BW20_DATA_COUNT 64
337+#define CSI_BW40_DATA_COUNT 128
338+#define CSI_BW80_DATA_COUNT 256
339+#define CSI_BW160_DATA_COUNT 512
340+#define CSI_BW320_DATA_COUNT 1024
341 #define ETH_ALEN 6
342
343 struct csi_data {
344- s16 data_i[CSI_MAX_COUNT];
345- s16 data_q[CSI_MAX_COUNT];
346+ u8 ch_bw;
347+ u16 data_num;
348+ s16 data_i[CSI_BW320_DATA_COUNT];
349+ s16 data_q[CSI_BW320_DATA_COUNT];
350+ u8 band;
351 s8 rssi;
352 u8 snr;
353 u32 ts;
354 u8 data_bw;
355 u8 pri_ch_idx;
356 u8 ta[ETH_ALEN];
357- u32 info;
358+ u32 ext_info;
359 u8 rx_mode;
360- u32 h_idx;
361+ u32 chain_info;
362 u16 tx_idx;
363 u16 rx_idx;
364+ u32 segment_num;
365+ u8 remain_last;
366+ u16 pkt_sn;
367+ u8 tr_stream;
368+};
369+
370+struct csi_resp_data {
371+ u16 usr_need_cnt;
372+ u16 buf_cnt;
373+ struct csi_data *csi_buf;
374 };
375
376 #define AIR_MONITOR_MAX_ENTRY 16
377diff --git a/src/drivers/driver.h b/src/drivers/driver.h
378index ba61f5842..7efb5e342 100644
379--- a/src/drivers/driver.h
380+++ b/src/drivers/driver.h
381@@ -5342,6 +5342,22 @@ struct wpa_driver_ops {
382 #ifdef CONFIG_IEEE80211BE
383 int (*get_mld_addr)(void *priv, u8 *addr);
384 #endif
385+ /**
386+ * csi_set - Set csi related mode and parameter
387+ * @priv: Private driver interface data
388+ * @mode: Csi mode parameter
389+ * @cfg: Csi config parameter
390+ * @v1: Value1
391+ * @v2: Value2
392+ * @mac: Station mac for station filter
393+ */
394+ int (*csi_set)(void *priv, u8 mode, u8 cfg, u8 v1, u32 v2, u8 *mac);
395+ /**
396+ * csi_dump - Dump csi data to json file
397+ * @priv: Private driver interface data
398+ * @dump_buf: Dump_struct that store csi data and related info
399+ */
400+ int (*csi_dump)(void *priv, void *dump_buf);
401 };
402
403 /**
404diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
405index df4a7ec41..39b45ef4b 100644
406--- a/src/drivers/driver_nl80211.c
407+++ b/src/drivers/driver_nl80211.c
408@@ -161,6 +161,35 @@ pp_ctrl_policy[NUM_MTK_VENDOR_ATTRS_PP_CTRL] = {
409 [MTK_VENDOR_ATTR_PP_MODE] = { .type = NLA_U8 },
410 };
411
412+static struct nla_policy csi_ctrl_policy[NUM_MTK_VENDOR_ATTRS_CSI_CTRL] = {
413+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG] = { .type = NLA_NESTED },
414+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE] = { .type = NLA_U8 },
415+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG_TYPE] = { .type = NLA_U8 },
416+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL1] = { .type = NLA_U8 },
417+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL2] = { .type = NLA_U32 },
418+ [MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR] = { .type = NLA_NESTED },
419+ [MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM] = { .type = NLA_U16 },
420+ [MTK_VENDOR_ATTR_CSI_CTRL_DATA] = { .type = NLA_NESTED },
421+};
422+
423+static struct nla_policy csi_data_policy[NUM_MTK_VENDOR_ATTRS_CSI_DATA] = {
424+ [MTK_VENDOR_ATTR_CSI_DATA_VER] = { .type = NLA_U8 },
425+ [MTK_VENDOR_ATTR_CSI_DATA_TS] = { .type = NLA_U32 },
426+ [MTK_VENDOR_ATTR_CSI_DATA_RSSI] = { .type = NLA_U8 },
427+ [MTK_VENDOR_ATTR_CSI_DATA_SNR] = { .type = NLA_U8 },
428+ [MTK_VENDOR_ATTR_CSI_DATA_BW] = { .type = NLA_U8 },
429+ [MTK_VENDOR_ATTR_CSI_DATA_CH_IDX] = { .type = NLA_U8 },
430+ [MTK_VENDOR_ATTR_CSI_DATA_TA] = { .type = NLA_NESTED },
431+ [MTK_VENDOR_ATTR_CSI_DATA_NUM] = { .type = NLA_U32 },
432+ [MTK_VENDOR_ATTR_CSI_DATA_I] = { .type = NLA_NESTED },
433+ [MTK_VENDOR_ATTR_CSI_DATA_Q] = { .type = NLA_NESTED },
434+ [MTK_VENDOR_ATTR_CSI_DATA_INFO] = { .type = NLA_U32 },
435+ [MTK_VENDOR_ATTR_CSI_DATA_TX_ANT] = { .type = NLA_U8 },
436+ [MTK_VENDOR_ATTR_CSI_DATA_RX_ANT] = { .type = NLA_U8 },
437+ [MTK_VENDOR_ATTR_CSI_DATA_MODE] = { .type = NLA_U8 },
438+ [MTK_VENDOR_ATTR_CSI_DATA_CHAIN_INFO] = { .type = NLA_U32 },
439+};
440+
441 static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg)
442 {
443 struct nl_sock *handle;
444@@ -15192,6 +15221,210 @@ static int nl80211_get_mld_addr(void *priv, u8 *addr)
445 }
446 #endif
447
448+static int
449+nl80211_csi_set(void *priv, u8 mode, u8 cfg, u8 v1, u32 v2, u8 *mac)
450+{
451+ struct i802_bss *bss = priv;
452+ struct wpa_driver_nl80211_data *drv = bss->drv;
453+ struct nl_msg *msg;
454+ struct nlattr *data;
455+ void *tb1, *tb2;
456+ int ret, i;
457+
458+ if (!drv->mtk_csi_vendor_cmd_avail) {
459+ wpa_printf(MSG_ERROR,
460+ "nl80211: Driver does not support csi");
461+ return 0;
462+ }
463+
464+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
465+ if (!msg)
466+ goto fail;
467+
468+ if (nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_MTK) ||
469+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
470+ MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL))
471+ goto fail;
472+
473+ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
474+ if (!data)
475+ goto fail;
476+
477+ tb1 = nla_nest_start(msg, MTK_VENDOR_ATTR_CSI_CTRL_CFG | NLA_F_NESTED);
478+ if (!tb1)
479+ goto fail;
480+
481+ nla_put_u8(msg, MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE, mode);
482+ nla_put_u8(msg, MTK_VENDOR_ATTR_CSI_CTRL_CFG_TYPE, cfg);
483+ nla_put_u8(msg, MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL1, v1);
484+ nla_put_u32(msg, MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL2, v2);
485+
486+ nla_nest_end(msg, tb1);
487+
488+ if (mac) {
489+ tb2 = nla_nest_start(msg, MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR | NLA_F_NESTED);
490+ if (!tb2)
491+ goto fail;
492+
493+ for (i = 0; i < ETH_ALEN; i++)
494+ nla_put_u8(msg, i, mac[i]);
495+
496+ nla_nest_end(msg, tb2);
497+ }
498+
499+ nla_nest_end(msg, data);
500+
501+ ret = send_and_recv_cmd(drv, msg);
502+
503+ if (ret)
504+ wpa_printf(MSG_ERROR, "Failed to set csi. ret=%d (%s)",
505+ ret, strerror(-ret));
506+
507+ return ret;
508+
509+fail:
510+ nlmsg_free(msg);
511+ return -ENOBUFS;
512+
513+}
514+
515+static int
516+mt76_csi_dump_cb(struct nl_msg *msg, void *arg)
517+{
518+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
519+ struct nlattr *tb1[NUM_MTK_VENDOR_ATTRS_CSI_CTRL];
520+ struct nlattr *tb2[NUM_MTK_VENDOR_ATTRS_CSI_DATA];
521+ struct nlattr *attr, *cur, *data;
522+ int len = 0, rem, idx;
523+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
524+ struct csi_resp_data *csi_resp = (struct csi_resp_data *)arg;
525+ struct csi_data *c = csi_resp->csi_buf;
526+
527+ c += csi_resp->buf_cnt;
528+
529+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
530+ genlmsg_attrlen(gnlh, 0), NULL);
531+
532+ attr = tb[NL80211_ATTR_VENDOR_DATA];
533+ if (!attr)
534+ return NL_SKIP;
535+
536+ nla_parse_nested(tb1, MTK_VENDOR_ATTR_CSI_CTRL_MAX,
537+ attr, csi_ctrl_policy);
538+
539+ if (!tb1[MTK_VENDOR_ATTR_CSI_CTRL_DATA])
540+ return NL_SKIP;
541+
542+ nla_parse_nested(tb2, MTK_VENDOR_ATTR_CSI_DATA_MAX,
543+ tb1[MTK_VENDOR_ATTR_CSI_CTRL_DATA], csi_data_policy);
544+
545+ if (!(tb2[MTK_VENDOR_ATTR_CSI_DATA_VER] &&
546+ tb2[MTK_VENDOR_ATTR_CSI_DATA_TS] &&
547+ tb2[MTK_VENDOR_ATTR_CSI_DATA_RSSI] &&
548+ tb2[MTK_VENDOR_ATTR_CSI_DATA_SNR] &&
549+ tb2[MTK_VENDOR_ATTR_CSI_DATA_BW] &&
550+ tb2[MTK_VENDOR_ATTR_CSI_DATA_CH_IDX] &&
551+ tb2[MTK_VENDOR_ATTR_CSI_DATA_TA] &&
552+ tb2[MTK_VENDOR_ATTR_CSI_DATA_I] &&
553+ tb2[MTK_VENDOR_ATTR_CSI_DATA_Q] &&
554+ tb2[MTK_VENDOR_ATTR_CSI_DATA_INFO] &&
555+ tb2[MTK_VENDOR_ATTR_CSI_DATA_MODE] &&
556+ tb2[MTK_VENDOR_ATTR_CSI_DATA_CHAIN_INFO])) {
557+ fprintf(stderr, "Attributes error for CSI data\n");
558+ return NL_SKIP;
559+ }
560+
561+ c->rssi = nla_get_u8(tb2[MTK_VENDOR_ATTR_CSI_DATA_RSSI]);
562+ c->snr = nla_get_u8(tb2[MTK_VENDOR_ATTR_CSI_DATA_SNR]);
563+ c->data_bw = nla_get_u8(tb2[MTK_VENDOR_ATTR_CSI_DATA_BW]);
564+ c->pri_ch_idx = nla_get_u8(tb2[MTK_VENDOR_ATTR_CSI_DATA_CH_IDX]);
565+ c->rx_mode = nla_get_u8(tb2[MTK_VENDOR_ATTR_CSI_DATA_MODE]);
566+
567+ c->tx_idx = nla_get_u16(tb2[MTK_VENDOR_ATTR_CSI_DATA_TX_ANT]);
568+ c->rx_idx = nla_get_u16(tb2[MTK_VENDOR_ATTR_CSI_DATA_RX_ANT]);
569+
570+ c->ext_info = nla_get_u32(tb2[MTK_VENDOR_ATTR_CSI_DATA_INFO]);
571+ c->chain_info = nla_get_u32(tb2[MTK_VENDOR_ATTR_CSI_DATA_CHAIN_INFO]);
572+
573+ c->ts = nla_get_u32(tb2[MTK_VENDOR_ATTR_CSI_DATA_TS]);
574+
575+ c->data_num = nla_get_u32(tb2[MTK_VENDOR_ATTR_CSI_DATA_NUM]);
576+
577+ idx = 0;
578+ nla_for_each_nested(cur, tb2[MTK_VENDOR_ATTR_CSI_DATA_TA], rem) {
579+ if (idx < ETH_ALEN)
580+ c->ta[idx++] = nla_get_u8(cur);
581+ }
582+
583+ idx = 0;
584+ nla_for_each_nested(cur, tb2[MTK_VENDOR_ATTR_CSI_DATA_I], rem) {
585+ if (idx < c->data_num)
586+ c->data_i[idx++] = nla_get_u16(cur);
587+ }
588+
589+ idx = 0;
590+ nla_for_each_nested(cur, tb2[MTK_VENDOR_ATTR_CSI_DATA_Q], rem) {
591+ if (idx < c->data_num)
592+ c->data_q[idx++] = nla_get_u16(cur);
593+ }
594+
595+ csi_resp->buf_cnt++;
596+
597+ return NL_SKIP;
598+}
599+
600+static int
601+nl80211_csi_dump(void *priv, void *dump_buf)
602+{
603+ struct i802_bss *bss = priv;
604+ struct wpa_driver_nl80211_data *drv = bss->drv;
605+ struct nl_msg *msg;
606+ struct nlattr *data;
607+ int ret;
608+ struct csi_resp_data *csi_resp;
609+ u16 pkt_num, i;
610+
611+ if (!drv->mtk_csi_vendor_cmd_avail) {
612+ wpa_printf(MSG_INFO,
613+ "nl80211: Driver does not support csi");
614+ return 0;
615+ }
616+
617+ csi_resp = (struct csi_resp_data *)dump_buf;
618+ pkt_num = csi_resp->usr_need_cnt;
619+
620+ if (pkt_num > 3000)
621+ return -EINVAL;
622+
623+#define CSI_DUMP_PER_NUM 3
624+ for (i = 0; i < pkt_num / CSI_DUMP_PER_NUM; i++) {
625+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_VENDOR);
626+ if (!msg)
627+ goto fail;
628+
629+ if (nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_MTK) ||
630+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
631+ MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL))
632+ goto fail;
633+
634+ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
635+ if (!data)
636+ goto fail;
637+
638+ nla_put_u16(msg, MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM, CSI_DUMP_PER_NUM);
639+
640+ nla_nest_end(msg, data);
641+
642+ ret = send_and_recv_resp(drv, msg, mt76_csi_dump_cb, dump_buf);
643+ }
644+
645+ return ret;
646+
647+fail:
648+ nlmsg_free(msg);
649+ return -ENOBUFS;
650+}
651+
652 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
653 .name = "nl80211",
654 .desc = "Linux nl80211/cfg80211",
655@@ -15375,4 +15608,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
656 #ifdef CONFIG_IEEE80211BE
657 .get_mld_addr = nl80211_get_mld_addr,
658 #endif
659+ .csi_set = nl80211_csi_set,
660+ .csi_dump = nl80211_csi_dump,
661 };
662diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
663index a0a62e536..b710b50cd 100644
664--- a/src/drivers/driver_nl80211.h
665+++ b/src/drivers/driver_nl80211.h
666@@ -212,6 +212,7 @@ struct wpa_driver_nl80211_data {
667 unsigned int mtk_background_radar_vendor_cmd_avail:1;
668 unsigned int mtk_pp_vendor_cmd_avail:1;
669 unsigned int mtk_beacon_ctrl_vendor_cmd_avail:1;
670+ unsigned int mtk_csi_vendor_cmd_avail:1;
671
672 u32 ignore_next_local_disconnect;
673 u32 ignore_next_local_deauth;
674diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
675index f3e3d52e2..8688b849f 100644
676--- a/src/drivers/driver_nl80211_capa.c
677+++ b/src/drivers/driver_nl80211_capa.c
678@@ -1173,6 +1173,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
679 case MTK_NL80211_VENDOR_SUBCMD_BEACON_CTRL :
680 drv->mtk_beacon_ctrl_vendor_cmd_avail = 1;
681 break;
682+ case MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL:
683+ drv->mtk_csi_vendor_cmd_avail = 1;
684+ break;
685 }
686 }
687
688--
6892.39.2
690