blob: 72c6355e60561f5cfd39ae1a4735e165a7d3e505 [file] [log] [blame]
developer683be522023-05-11 14:24:50 +08001From c8a55373f42c6149df669ba74ffbff70ec74d8db Mon Sep 17 00:00:00 2001
2From: Evelyn Tsai <evelyn.tsai@mediatek.com>
3Date: Fri, 12 May 2023 05:18:48 +0800
4Subject: [PATCH 24/28] hostapd: mtk: Air Monitor support in hostapd by vendor
5
6Signed-off-by: mtk23888 <dipanshu.mittal@mediatek.com>
7---
8 hostapd/ctrl_iface.c | 113 +++++++++++++++++++
9 hostapd/hostapd_cli.c | 15 +++
10 src/ap/ap_drv_ops.c | 14 +++
11 src/ap/ap_drv_ops.h | 3 +
12 src/common/mtk_vendor.h | 8 ++
13 src/drivers/driver.h | 16 +++
14 src/drivers/driver_nl80211.c | 180 ++++++++++++++++++++++++++++++
15 src/drivers/driver_nl80211.h | 1 +
16 src/drivers/driver_nl80211_capa.c | 2 +
17 9 files changed, 352 insertions(+)
18
19diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
20index 79457d7..234b800 100644
21--- a/hostapd/ctrl_iface.c
22+++ b/hostapd/ctrl_iface.c
23@@ -3840,6 +3840,44 @@ hostapd_ctrl_iface_ap_wireless(struct hostapd_data *hapd, char *cmd,
24
25 if (hostapd_drv_ap_wireless(hapd, (u8) sub_cmd, atoi(value)) != 0)
26 return -1;
27+ return os_snprintf(buf, buflen, "OK\n");
28+}
29+
30+static int
31+hostapd_ctrl_iface_set_amnt(struct hostapd_data *hapd, char *cmd,
32+ char *buf, size_t buflen)
33+{
34+ char *tmp, sta_mac[ETH_ALEN] = {0};
35+ int amnt_idx = 0;
36+
37+ tmp = strtok_r(cmd, " ", &cmd);
38+
39+ if (!tmp) {
40+ wpa_printf(MSG_ERROR, "Error in command format\n");
41+ return -1;
42+ }
43+
44+ amnt_idx = strtol(tmp, &tmp, 10);
45+
46+ if (amnt_idx < 0 || amnt_idx > 15) {
47+ wpa_printf(MSG_ERROR, "Wrong AMNT index %d\n", amnt_idx);
48+ return -1;
49+ }
50+
51+ if (!cmd) {
52+ wpa_printf(MSG_ERROR, "Error in command format\n");
53+ return -1;
54+ }
55+
56+ if (hwaddr_aton(cmd, sta_mac) < 0) {
57+ wpa_printf(MSG_ERROR, "station mac is not right.\n");
58+ return -1;
59+ }
60+
61+ if (hostapd_drv_amnt_set(hapd, amnt_idx, sta_mac)) {
62+ wpa_printf(MSG_ERROR, "Not able to set amnt index\n");
63+ return -1;
64+ }
65
66 return os_snprintf(buf, buflen, "OK\n");
67 }
68@@ -3893,6 +3931,75 @@ exit:
69 return os_snprintf(buf, buflen, "OK\n");
70 }
71
72+static int
73+hostapd_ctrl_iface_dump_amnt(struct hostapd_data *hapd, char *cmd,
74+ char *buf, size_t buflen)
75+{
76+ char *tmp;
77+ int amnt_idx = 0, ret = 0;
78+ struct amnt_resp_data *resp_buf;
79+ char *pos, *end;
80+ struct amnt_data *res;
81+
82+ pos = buf;
83+ end = buf + buflen;
84+
85+ tmp = strtok_r(cmd, " ", &cmd);
86+
87+ if (!tmp) {
88+ wpa_printf(MSG_ERROR, "Error in command format\n");
89+ return -1;
90+ }
91+
92+ amnt_idx = strtoul(tmp, &tmp, 0);
93+
94+ if ((amnt_idx < 0 || amnt_idx > 15) && amnt_idx != 0xff) {
95+ wpa_printf(MSG_ERROR, "Wrong AMNT index\n");
96+ return -1;
97+ }
98+
99+ if (amnt_idx == 0xff)
100+ resp_buf = (struct amnt_resp_data *) os_zalloc(AIR_MONITOR_MAX_ENTRY
101+ * sizeof(struct amnt_data) + 1);
102+ else
103+ resp_buf = (struct amnt_resp_data *) os_zalloc(sizeof(struct amnt_data) + 1);
104+
105+ if (resp_buf == NULL) {
106+ wpa_printf(MSG_ERROR, "Error in memory allocation\n");
107+ return -1;
108+ }
109+
110+ if (hostapd_drv_amnt_dump(hapd, amnt_idx, (u8 *)resp_buf)) {
111+ wpa_printf(MSG_ERROR, "Not able to set amnt index\n");
112+ os_free(resp_buf);
113+ return -1;
114+ }
115+
116+ for (int i = 0; i < resp_buf->sta_num && i < AIR_MONITOR_MAX_ENTRY; i++) {
117+ res = &resp_buf->resp_data[i];
118+ ret = os_snprintf(pos, end - pos,
119+ "[hostapd_cli] amnt_idx: %d, addr="MACSTR
120+ ", rssi=%d/%d/%d/%d, last_seen=%u\n",
121+ res->idx,
122+ MAC2STR(res->addr), res->rssi[0],
123+ res->rssi[1], res->rssi[2],
124+ res->rssi[3], res->last_seen);
125+ if (os_snprintf_error(end - pos, ret)) {
126+ os_free(resp_buf);
127+ return 0;
128+ }
129+ pos = pos + ret;
130+ }
131+
132+ os_free(resp_buf);
133+
134+ if (pos == buf)
135+ return os_snprintf(buf, buflen, "Index %d is not monitored\n",
136+ amnt_idx);
137+ else
138+ return pos - buf;
139+}
140+
141 static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
142 char *buf, char *reply,
143 int reply_size,
144@@ -4476,6 +4583,12 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
145 reply_len = hostapd_ctrl_iface_ap_wireless(hapd, buf + 12, reply, reply_size);
146 } else if (os_strncmp(buf, "ap_rfeatures ", 13) == 0) {
147 reply_len = hostapd_ctrl_iface_ap_rfeatures(hapd, buf + 13, reply, reply_size);
148+ } else if (os_strncmp(buf, "SET_AMNT", 8) == 0) {
149+ reply_len = hostapd_ctrl_iface_set_amnt(hapd, buf+9,
150+ reply, reply_size);
151+ } else if (os_strncmp(buf, "DUMP_AMNT", 9) == 0) {
152+ reply_len = hostapd_ctrl_iface_dump_amnt(hapd, buf+10,
153+ reply, reply_size);
154 } else {
155 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
156 reply_len = 16;
157diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
158index dc01ad9..02f8546 100644
159--- a/hostapd/hostapd_cli.c
160+++ b/hostapd/hostapd_cli.c
161@@ -1633,6 +1633,17 @@ static int hostapd_cli_cmd_get_amsdu(struct wpa_ctrl *ctrl, int argc,
162 return hostapd_cli_cmd(ctrl, "GET_AMSDU", 0, NULL, NULL);
163 }
164
165+static int hostapd_cli_cmd_set_amnt(struct wpa_ctrl *ctrl, int argc,
166+ char *argv[])
167+{
168+ return hostapd_cli_cmd(ctrl, "SET_AMNT", 2, argc, argv);
169+}
170+
171+static int hostapd_cli_cmd_dump_amnt(struct wpa_ctrl *ctrl, int argc,
172+ char *argv[])
173+{
174+ return hostapd_cli_cmd(ctrl, "DUMP_AMNT", 1, argc, argv);
175+}
176
177 struct hostapd_cli_cmd {
178 const char *cmd;
179@@ -1847,6 +1858,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
180 " = show iBF state (enabled/disabled)"},
181 { "get_amsdu", hostapd_cli_cmd_get_amsdu, NULL,
182 " = show AMSDU state"},
183+ { "set_amnt", hostapd_cli_cmd_set_amnt, NULL,
184+ " = Set Station index and mac to monitor"},
185+ { "dump_amnt", hostapd_cli_cmd_dump_amnt, NULL,
186+ " = Dump RSSI of monitoring Station"},
187 { NULL, NULL, NULL, NULL }
188 };
189
190diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
191index 78b52c8..0052a6d 100644
192--- a/src/ap/ap_drv_ops.c
193+++ b/src/ap/ap_drv_ops.c
194@@ -1160,3 +1160,17 @@ int hostapd_drv_ap_trig_type(struct hostapd_data *hapd, u8 enable, u8 type)
195 return 0;
196 return hapd->driver->ap_trigtype(hapd->drv_priv, enable, type);
197 }
198+
199+int hostapd_drv_amnt_set(struct hostapd_data *hapd, u8 amnt_idx, u8 *amnt_sta_mac)
200+{
201+ if (!hapd->driver || !hapd->driver->amnt_set)
202+ return 0;
203+ return hapd->driver->amnt_set(hapd->drv_priv, amnt_idx, amnt_sta_mac);
204+}
205+
206+int hostapd_drv_amnt_dump(struct hostapd_data *hapd, u8 amnt_idx, u8 *amnt_dump_buf)
207+{
208+ if (!hapd->driver || !hapd->driver->amnt_dump)
209+ return 0;
210+ return hapd->driver->amnt_dump(hapd->drv_priv, amnt_idx, amnt_dump_buf);
211+}
212diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
213index bb9fdf7..9d5a23b 100644
214--- a/src/ap/ap_drv_ops.h
215+++ b/src/ap/ap_drv_ops.h
216@@ -161,6 +161,9 @@ int hostapd_drv_ap_wireless(struct hostapd_data *hapd, u8 sub_vendor_id, int val
217 int hostapd_drv_ap_rfeatures(struct hostapd_data *hapd, u8 sub_vendor_id, int value);
218 int hostapd_drv_ap_trig_type(struct hostapd_data *hapd, u8 enable, u8 type);
219
220+int hostapd_drv_amnt_set(struct hostapd_data *hapd, u8 amnt_idx, u8 *amnt_sta_mac);
221+int hostapd_drv_amnt_dump(struct hostapd_data *hapd, u8 amnt_idx, u8 *amnt_dump_buf);
222+
223 #include "drivers/driver.h"
224
225 int hostapd_drv_wnm_oper(struct hostapd_data *hapd,
226diff --git a/src/common/mtk_vendor.h b/src/common/mtk_vendor.h
227index 32438af..74f467c 100644
228--- a/src/common/mtk_vendor.h
229+++ b/src/common/mtk_vendor.h
230@@ -256,10 +256,18 @@ struct csi_data {
231 u16 rx_idx;
232 };
233
234+#define AIR_MONITOR_MAX_ENTRY 16
235+
236 struct amnt_data {
237 u8 idx;
238 u8 addr[ETH_ALEN];
239 s8 rssi[4];
240 u32 last_seen;
241 };
242+
243+struct amnt_resp_data {
244+ u8 sta_num;
245+ struct amnt_data resp_data[0];
246+};
247+
248 #endif /* MTK_VENDOR_H */
249diff --git a/src/drivers/driver.h b/src/drivers/driver.h
250index ae692c2..cb885f9 100644
251--- a/src/drivers/driver.h
252+++ b/src/drivers/driver.h
253@@ -5084,6 +5084,22 @@ struct wpa_driver_ops {
254 * @type: trigger type
255 */
256 int (*ap_trigtype)(void *priv, u8 enable, u8 type);
257+
258+ /**
259+ * amnt_set - add/delete station from monitoring
260+ * @priv: Private driver interface data
261+ * @amnt_idx: Monitor Index
262+ * @amnt_sta_mac: station mac address
263+ */
264+ int (*amnt_set)(void *priv, u8 amnt_idx, u8 *amnt_sta_mac);
265+
266+ /**
267+ * amnt_dump - Dump particular/ all station
268+ * @priv: Private driver interface data
269+ * @amnt_idx: Monitor Index
270+ * @amnt_dump_buf: Buffer to print
271+ */
272+ int (*amnt_dump)(void *priv, u8 amnt_idx, u8 *amnt_dump_buf);
273 };
274
275 /**
276diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
277index 730a696..088f625 100644
278--- a/src/drivers/driver_nl80211.c
279+++ b/src/drivers/driver_nl80211.c
280@@ -127,6 +127,19 @@ wireless_ctrl_policy[NUM_MTK_VENDOR_ATTRS_WIRELESS_CTRL] = {
281 [MTK_VENDOR_ATTR_WIRELESS_CTRL_CERT] = {.type = NLA_U8 },
282 };
283
284+static struct nla_policy
285+amnt_ctrl_policy[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL] = {
286+ [MTK_VENDOR_ATTR_AMNT_CTRL_SET] = {.type = NLA_NESTED },
287+ [MTK_VENDOR_ATTR_AMNT_CTRL_DUMP] = { .type = NLA_NESTED },
288+};
289+
290+static struct nla_policy
291+amnt_dump_policy[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP] = {
292+ [MTK_VENDOR_ATTR_AMNT_DUMP_INDEX] = {.type = NLA_U8 },
293+ [MTK_VENDOR_ATTR_AMNT_DUMP_LEN] = { .type = NLA_U8 },
294+ [MTK_VENDOR_ATTR_AMNT_DUMP_RESULT] = { .type = NLA_NESTED },
295+};
296+
297 static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg)
298 {
299 struct nl_sock *handle;
300@@ -14133,6 +14146,171 @@ fail:
301 return -ENOBUFS;
302 }
303
304+static int
305+nl80211_amnt_set(void *priv, u8 amnt_idx, u8 *amnt_sta_mac)
306+{
307+ struct i802_bss *bss = priv;
308+ struct wpa_driver_nl80211_data *drv = bss->drv;
309+ struct nl_msg *msg;
310+ struct nlattr *data;
311+ void *tb1;
312+ int ret;
313+
314+ if (!drv->mtk_amnt_vendor_cmd_avail) {
315+ wpa_printf(MSG_ERROR,
316+ "nl80211: Driver does not support air monitor");
317+ return 0;
318+ }
319+
320+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
321+ if (!msg)
322+ goto fail;
323+
324+ if (nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_MTK) ||
325+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
326+ MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL))
327+ goto fail;
328+
329+ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
330+ if (!data)
331+ goto fail;
332+
333+ tb1 = nla_nest_start(msg, MTK_VENDOR_ATTR_AMNT_CTRL_SET);
334+ if (!tb1)
335+ goto fail;
336+
337+ nla_put_u8(msg, MTK_VENDOR_ATTR_AMNT_SET_INDEX, amnt_idx);
338+
339+ nla_put(msg, MTK_VENDOR_ATTR_AMNT_SET_MACADDR, ETH_ALEN, amnt_sta_mac);
340+
341+ nla_nest_end(msg, tb1);
342+ nla_nest_end(msg, data);
343+
344+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
345+
346+ if (ret)
347+ wpa_printf(MSG_ERROR, "Failed to set air monitor. ret=%d (%s)",
348+ ret, strerror(-ret));
349+
350+ return ret;
351+
352+fail:
353+ nlmsg_free(msg);
354+ return -ENOBUFS;
355+
356+}
357+
358+static int
359+mt76_amnt_dump_cb(struct nl_msg *msg, void *arg)
360+{
361+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
362+ struct nlattr *tb1[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL];
363+ struct nlattr *tb2[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP];
364+ struct nlattr *attr, *cur, *data;
365+ struct amnt_data *res;
366+ int len = 0, rem;
367+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
368+ struct amnt_resp_data *amnt_dump = (struct amnt_resp_data *)arg;
369+
370+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
371+ genlmsg_attrlen(gnlh, 0), NULL);
372+
373+ attr = tb[NL80211_ATTR_VENDOR_DATA];
374+ if (!attr)
375+ return NL_SKIP;
376+
377+ nla_parse_nested(tb1, MTK_VENDOR_ATTR_AMNT_CTRL_MAX,
378+ attr, amnt_ctrl_policy);
379+
380+ if (!tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP])
381+ return NL_SKIP;
382+
383+ nla_parse_nested(tb2, NUM_MTK_VENDOR_ATTRS_AMNT_DUMP,
384+ tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP], amnt_dump_policy);
385+
386+ if (!tb2[MTK_VENDOR_ATTR_AMNT_DUMP_LEN])
387+ return NL_SKIP;
388+
389+ len = nla_get_u8(tb2[MTK_VENDOR_ATTR_AMNT_DUMP_LEN]);
390+ if (!len)
391+ return 0;
392+
393+ if (!tb2[MTK_VENDOR_ATTR_AMNT_DUMP_RESULT])
394+ return NL_SKIP;
395+
396+ data = tb2[MTK_VENDOR_ATTR_AMNT_DUMP_RESULT];
397+
398+ nla_for_each_nested(cur, data, rem) {
399+ if (amnt_dump->sta_num >= AIR_MONITOR_MAX_ENTRY)
400+ return NL_SKIP;
401+ res = (struct amnt_data *) nla_data(cur);
402+ wpa_printf(MSG_ERROR, "[vendor] amnt_idx: %d, "
403+ "addr="MACSTR", "
404+ "rssi=%d/%d/%d/%d, last_seen=%u\n",
405+ res->idx,
406+ MAC2STR(res->addr),
407+ res->rssi[0], res->rssi[1], res->rssi[2],
408+ res->rssi[3], res->last_seen);
409+ os_memcpy(&amnt_dump->resp_data[amnt_dump->sta_num], res,
410+ sizeof(struct amnt_data));
411+ amnt_dump->sta_num++;
412+ }
413+ return 0;
414+}
415+
416+static int
417+nl80211_amnt_dump(void *priv, u8 amnt_idx, u8 *dump_buf)
418+{
419+ struct i802_bss *bss = priv;
420+ struct wpa_driver_nl80211_data *drv = bss->drv;
421+ struct nl_msg *msg;
422+ struct nlattr *data;
423+ void *tb1;
424+ int ret;
425+
426+ if (!drv->mtk_amnt_vendor_cmd_avail) {
427+ wpa_printf(MSG_INFO,
428+ "nl80211: Driver does not support air monitor");
429+ return 0;
430+ }
431+
432+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_VENDOR);
433+ if (!msg)
434+ goto fail;
435+
436+ if (nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_MTK) ||
437+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
438+ MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL))
439+ goto fail;
440+
441+ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
442+ if (!data)
443+ goto fail;
444+
445+ tb1 = nla_nest_start(msg, MTK_VENDOR_ATTR_AMNT_CTRL_DUMP
446+ | NLA_F_NESTED);
447+ if (!tb1)
448+ goto fail;
449+
450+ nla_put_u8(msg, MTK_VENDOR_ATTR_AMNT_DUMP_INDEX, amnt_idx);
451+
452+ nla_nest_end(msg, tb1);
453+ nla_nest_end(msg, data);
454+
455+ ret = send_and_recv_msgs(drv, msg, mt76_amnt_dump_cb,
456+ dump_buf, NULL, NULL);
457+
458+ if (ret)
459+ wpa_printf(MSG_ERROR, "Failed to Dump air monitor. ret=%d (%s)"
460+ , ret, strerror(-ret));
461+
462+ return ret;
463+
464+fail:
465+ nlmsg_free(msg);
466+ return -ENOBUFS;
467+}
468+
469 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
470 .name = "nl80211",
471 .desc = "Linux nl80211/cfg80211",
472@@ -14300,4 +14478,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
473 .ap_wireless = nl80211_ap_wireless,
474 .ap_rfeatures = nl80211_ap_rfeatures,
475 .ap_trigtype = nl80211_ap_trigtype,
476+ .amnt_set = nl80211_amnt_set,
477+ .amnt_dump = nl80211_amnt_dump,
478 };
479diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
480index 49588e6..e64a12e 100644
481--- a/src/drivers/driver_nl80211.h
482+++ b/src/drivers/driver_nl80211.h
483@@ -206,6 +206,7 @@ struct wpa_driver_nl80211_data {
484 unsigned int mtk_wireless_vendor_cmd_avail:1;
485 unsigned int mtk_bss_color_vendor_cmd_avail:1;
486 unsigned int mtk_rfeatures_vendor_cmd_avail:1;
487+ unsigned int mtk_amnt_vendor_cmd_avail:1;
488
489 u64 vendor_scan_cookie;
490 u64 remain_on_chan_cookie;
491diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
492index 0674b66..7b5079b 100644
493--- a/src/drivers/driver_nl80211_capa.c
494+++ b/src/drivers/driver_nl80211_capa.c
495@@ -1119,6 +1119,8 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
496 break;
497 case MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL :
498 drv->mtk_bss_color_vendor_cmd_avail = 1;
499+ case MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL:
500+ drv->mtk_amnt_vendor_cmd_avail = 1;
501 break;
502 case MTK_NL80211_VENDOR_SUBCMD_RFEATURE_CTRL:
503 drv->mtk_rfeatures_vendor_cmd_avail = 1;
504--
5052.18.0
506