blob: d7544bc587f649534bb27c1f6a700b393a15ad85 [file] [log] [blame]
developer66e89bc2024-04-23 14:50:01 +08001From 7b735e95647fe46cc5dcf7d859c8f9abbed5ae0d Mon Sep 17 00:00:00 2001
2From: Howard Hsu <howard-yh.hsu@mediatek.com>
3Date: Mon, 30 May 2022 16:31:34 +0800
4Subject: [PATCH 033/104] mtk: hostapd: Support EDCCA hostapd configuration
5
6edcca_enable and edcca_compensation and implement edcca related handlers.
7---
8 hostapd/config_file.c | 34 ++++++
9 hostapd/ctrl_iface.c | 124 +++++++++++++++++++++
10 src/ap/ap_config.c | 4 +
11 src/ap/ap_config.h | 30 ++++++
12 src/ap/ap_drv_ops.c | 24 +++++
13 src/ap/ap_drv_ops.h | 4 +
14 src/ap/hostapd.c | 7 ++
15 src/common/mtk_vendor.h | 20 ++--
16 src/drivers/driver.h | 4 +
17 src/drivers/driver_nl80211.c | 174 ++++++++++++++++++++++++++++++
18 src/drivers/driver_nl80211.h | 1 +
19 src/drivers/driver_nl80211_capa.c | 7 ++
20 12 files changed, 427 insertions(+), 6 deletions(-)
21
22diff --git a/hostapd/config_file.c b/hostapd/config_file.c
23index 0094db279..f8c1eec0a 100644
24--- a/hostapd/config_file.c
25+++ b/hostapd/config_file.c
26@@ -5348,6 +5348,40 @@ static int hostapd_config_fill(struct hostapd_config *conf,
27 bss->mld_indicate_disabled = atoi(pos);
28 #endif /* CONFIG_TESTING_OPTIONS */
29 #endif /* CONFIG_IEEE80211BE */
30+ } else if (os_strcmp(buf, "edcca_threshold") == 0) {
31+ if (hostapd_parse_intlist(&conf->edcca_threshold, pos) ||
32+ conf->edcca_threshold[0] < EDCCA_MIN_CONFIG_THRES ||
33+ conf->edcca_threshold[0] > EDCCA_MAX_CONFIG_THRES ||
34+ conf->edcca_threshold[1] < EDCCA_MIN_CONFIG_THRES ||
35+ conf->edcca_threshold[1] > EDCCA_MAX_CONFIG_THRES ||
36+ conf->edcca_threshold[2] < EDCCA_MIN_CONFIG_THRES ||
37+ conf->edcca_threshold[2] > EDCCA_MAX_CONFIG_THRES ||
38+ conf->edcca_threshold[3] < EDCCA_MIN_CONFIG_THRES ||
39+ conf->edcca_threshold[3] > EDCCA_MAX_CONFIG_THRES) {
40+ wpa_printf(MSG_ERROR, "Line %d: invalid edcca threshold",
41+ line);
42+ return 1;
43+ }
44+ } else if (os_strcmp(buf, "edcca_enable") == 0) {
45+ int mode = atoi(pos);
46+ if (mode < EDCCA_MODE_FORCE_DISABLE || mode > EDCCA_MODE_AUTO) {
47+ wpa_printf(MSG_ERROR, "Line %d: Invalid edcca_enable %d;"
48+ " allowed value 0 (Force Disable) or 1(Auto) ",
49+ line, mode);
50+ return 1;
51+ }
52+ conf->edcca_enable = (u8) mode;
53+ } else if (os_strcmp(buf, "edcca_compensation") == 0) {
54+ int val = atoi(pos);
55+ if (val < EDCCA_MIN_COMPENSATION ||
56+ val > EDCCA_MAX_COMPENSATION) {
57+ wpa_printf(MSG_ERROR, "Line %d: Invalid compensation"
58+ " value %d; allowed value %d ~ %d.",
59+ line, val, EDCCA_MIN_COMPENSATION,
60+ EDCCA_MAX_COMPENSATION);
61+ return 1;
62+ }
63+ conf->edcca_compensation = (s8) val;
64 } else {
65 wpa_printf(MSG_ERROR,
66 "Line %d: unknown configuration item '%s'",
67diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
68index fb9f09bb1..78a3380f2 100644
69--- a/hostapd/ctrl_iface.c
70+++ b/hostapd/ctrl_iface.c
71@@ -544,6 +544,19 @@ static const char * pbc_status_str(enum pbc_status status)
72 }
73
74
75+static const char *edcca_mode_str(enum edcca_mode status)
76+{
77+ switch (status) {
78+ case EDCCA_MODE_FORCE_DISABLE:
79+ return "Force Disable";
80+ case EDCCA_MODE_AUTO:
81+ return "Auto";
82+ default:
83+ return "Unknown";
84+ }
85+}
86+
87+
88 static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
89 char *buf, size_t buflen)
90 {
91@@ -3644,6 +3657,111 @@ static int hostapd_ctrl_iface_link_remove(struct hostapd_data *hapd, char *cmd,
92 #endif /* CONFIG_TESTING_OPTIONS */
93 #endif /* CONFIG_IEEE80211BE */
94
95+static int
96+hostapd_ctrl_iface_set_edcca(struct hostapd_data *hapd, char *cmd,
97+ char *buf, size_t buflen)
98+{
99+ char *pos, *config, *value;
100+ config = cmd;
101+ pos = os_strchr(config, ' ');
102+ if (pos == NULL)
103+ return -1;
104+ *pos++ = '\0';
105+
106+ if (pos == NULL)
107+ return -1;
108+ value = pos;
109+
110+ if (os_strcmp(config, "enable") == 0) {
111+ int mode = atoi(value);
112+ if (mode < EDCCA_MODE_FORCE_DISABLE || mode > EDCCA_MODE_AUTO) {
113+ wpa_printf(MSG_ERROR, "Invalid value for edcca enable");
114+ return -1;
115+ }
116+ hapd->iconf->edcca_enable = (u8) mode;
117+ if (hostapd_drv_configure_edcca_enable(hapd) != 0)
118+ return -1;
119+ } else if (os_strcmp(config, "compensation") == 0) {
120+ int compensation = atoi(value);
121+ if (compensation < EDCCA_MIN_COMPENSATION ||
122+ compensation > EDCCA_MAX_COMPENSATION) {
123+ wpa_printf(MSG_ERROR, "Invalid value for edcca compensation");
124+ return -1;
125+ }
126+ hapd->iconf->edcca_compensation = (s8) compensation;
127+ if (hostapd_drv_configure_edcca_enable(hapd) != 0)
128+ return -1;
129+ } else if (os_strcmp(config, "threshold") == 0) {
130+ char *thres_value;
131+ thres_value = os_strchr(value, ':');
132+ if (thres_value == NULL)
133+ return -1;
134+ *thres_value++ = '\0';
135+
136+ if (thres_value == NULL)
137+ return -1;
138+ int bw_idx = atoi(value);
139+ int threshold = atoi(thres_value);
140+
141+ if (bw_idx < EDCCA_BW_20 || bw_idx > EDCCA_BW_160) {
142+ wpa_printf(MSG_ERROR,
143+ "Unsupported Bandwidth idx %d for SET_EDCCA",
144+ bw_idx);
145+ return -1;
146+ }
147+ if (threshold < EDCCA_MIN_CONFIG_THRES ||
148+ threshold > EDCCA_MAX_CONFIG_THRES) {
149+ wpa_printf(MSG_ERROR,
150+ "Unsupported threshold %d for SET_EDCCA",
151+ threshold);
152+ return -1;
153+ }
154+
155+ int threshold_arr[EDCCA_MAX_BW_NUM];
156+ /* 0x7f means keep the origival value in firmware */
157+ os_memset(threshold_arr, 0x7f, sizeof(threshold_arr));
158+ threshold_arr[bw_idx] = threshold;
159+
160+ if (hostapd_drv_configure_edcca_threshold(hapd, threshold_arr) != 0)
161+ return -1;
162+ } else {
163+ wpa_printf(MSG_ERROR,
164+ "Unsupported parameter %s for SET_EDCCA", config);
165+ return -1;
166+ }
167+ return os_snprintf(buf, buflen, "OK\n");
168+}
169+
170+
171+static int
172+hostapd_ctrl_iface_get_edcca(struct hostapd_data *hapd, char *cmd, char *buf,
173+ size_t buflen)
174+{
175+ char *pos, *end;
176+
177+ pos = buf;
178+ end = buf + buflen;
179+ u8 value[EDCCA_MAX_BW_NUM] = {0};
180+
181+ if (os_strcmp(cmd, "enable") == 0) {
182+ return os_snprintf(pos, end - pos, "Enable: %s\n",
183+ edcca_mode_str(hapd->iconf->edcca_enable));
184+ } else if (os_strcmp(cmd, "compensation") == 0) {
185+ return os_snprintf(pos, end - pos, "Compensation: %d\n",
186+ hapd->iconf->edcca_compensation);
187+ } else if (os_strcmp(cmd, "threshold") == 0) {
188+ if (hostapd_drv_get_edcca(hapd, EDCCA_CTRL_GET_THRES, &value) != 0)
189+ return -1;
190+ return os_snprintf(pos, end - pos,
191+ "Threshold BW20: 0x%x, BW40: 0x%x, BW80: 0x%x, BW160: 0x%x\n",
192+ value[0], value[1], value[2], value[3]);
193+ } else {
194+ wpa_printf(MSG_ERROR,
195+ "Unsupported parameter %s for GET_EDCCA", cmd);
196+ return -1;
197+ }
198+}
199+
200
201 #ifdef CONFIG_NAN_USD
202
203@@ -4531,6 +4649,12 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
204 reply_len = -1;
205 #endif /* CONFIG_TESTING_OPTIONS */
206 #endif /* CONFIG_IEEE80211BE */
207+ } else if (os_strncmp(buf, "SET_EDCCA ", 10) == 0) {
208+ reply_len = hostapd_ctrl_iface_set_edcca(hapd, buf+10, reply,
209+ reply_size);
210+ } else if (os_strncmp(buf, "GET_EDCCA ", 10) == 0) {
211+ reply_len = hostapd_ctrl_iface_get_edcca(hapd, buf+10, reply,
212+ reply_size);
213 } else {
214 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
215 reply_len = 16;
216diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
217index 6c8b10291..965600577 100644
218--- a/src/ap/ap_config.c
219+++ b/src/ap/ap_config.c
220@@ -303,6 +303,9 @@ struct hostapd_config * hostapd_config_defaults(void)
221 conf->airtime_update_interval = AIRTIME_DEFAULT_UPDATE_INTERVAL;
222 #endif /* CONFIG_AIRTIME_POLICY */
223
224+ conf->edcca_enable = EDCCA_MODE_AUTO;
225+ conf->edcca_compensation = EDCCA_DEFAULT_COMPENSATION;
226+
227 hostapd_set_and_check_bw320_offset(conf, 0);
228
229 return conf;
230@@ -1034,6 +1037,7 @@ void hostapd_config_free(struct hostapd_config *conf)
231 #ifdef CONFIG_ACS
232 os_free(conf->acs_chan_bias);
233 #endif /* CONFIG_ACS */
234+ os_free(conf->edcca_threshold);
235 wpabuf_free(conf->lci);
236 wpabuf_free(conf->civic);
237 #ifdef CONFIG_AFC
238diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
239index 379dc22cf..09718fada 100644
240--- a/src/ap/ap_config.h
241+++ b/src/ap/ap_config.h
242@@ -1281,8 +1281,38 @@ struct hostapd_config {
243 int min_power;
244 } afc;
245 #endif /* CONFIG_AFC */
246+
247+ u8 edcca_enable;
248+ s8 edcca_compensation;
249+ int *edcca_threshold;
250+};
251+
252+enum edcca_mode {
253+ EDCCA_MODE_FORCE_DISABLE = 0,
254+ EDCCA_MODE_AUTO = 1,
255+};
256+
257+enum edcca_bw_id {
258+ EDCCA_BW_20 = 0,
259+ EDCCA_BW_40,
260+ EDCCA_BW_80,
261+ EDCCA_BW_160,
262+ EDCCA_MAX_BW_NUM,
263+};
264+
265+enum mtk_vendor_attr_edcca_ctrl_mode {
266+ EDCCA_CTRL_SET_EN = 0,
267+ EDCCA_CTRL_SET_THRES,
268+ EDCCA_CTRL_GET_EN,
269+ EDCCA_CTRL_GET_THRES,
270+ EDCCA_CTRL_NUM,
271 };
272
273+#define EDCCA_DEFAULT_COMPENSATION -6
274+#define EDCCA_MIN_COMPENSATION -126
275+#define EDCCA_MAX_COMPENSATION 126
276+#define EDCCA_MIN_CONFIG_THRES -126
277+#define EDCCA_MAX_CONFIG_THRES 0
278
279 static inline enum oper_chan_width
280 hostapd_get_oper_chwidth(struct hostapd_config *conf)
281diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
282index 527b2c984..a6caf6a73 100644
283--- a/src/ap/ap_drv_ops.c
284+++ b/src/ap/ap_drv_ops.c
285@@ -1245,3 +1245,27 @@ int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
286 return hapd->driver->set_secure_ranging_ctx(hapd->drv_priv, &params);
287 }
288 #endif /* CONFIG_PASN */
289+
290+int hostapd_drv_configure_edcca_enable(struct hostapd_data *hapd)
291+{
292+ if (!hapd->driver || !hapd->driver->configure_edcca_enable)
293+ return 0;
294+ return hapd->driver->configure_edcca_enable(hapd->drv_priv,
295+ hapd->iconf->edcca_enable,
296+ hapd->iconf->edcca_compensation);
297+}
298+
299+int hostapd_drv_configure_edcca_threshold(struct hostapd_data *hapd,
300+ const int *threshold)
301+{
302+ if (!hapd->driver || !hapd->driver->configure_edcca_threshold)
303+ return 0;
304+ return hapd->driver->configure_edcca_threshold(hapd->drv_priv, threshold);
305+}
306+
307+int hostapd_drv_get_edcca(struct hostapd_data *hapd, const u8 mode, u8 *value)
308+{
309+ if (!hapd->driver || !hapd->driver->get_edcca)
310+ return 0;
311+ return hapd->driver->get_edcca(hapd->drv_priv, mode, value);
312+}
313diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
314index f8a8725be..98836153f 100644
315--- a/src/ap/ap_drv_ops.h
316+++ b/src/ap/ap_drv_ops.h
317@@ -149,6 +149,10 @@ int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
318 u8 ltf_keyseed_len,
319 const u8 *ltf_keyseed, u32 action);
320
321+int hostapd_drv_configure_edcca_enable(struct hostapd_data *hapd);
322+int hostapd_drv_configure_edcca_threshold(struct hostapd_data *hapd,
323+ const int *threshold);
324+int hostapd_drv_get_edcca(struct hostapd_data *hapd, const u8 mode, u8 *value);
325
326 #include "drivers/driver.h"
327
328diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
329index 7959859b0..6af31179e 100644
330--- a/src/ap/hostapd.c
331+++ b/src/ap/hostapd.c
332@@ -2693,6 +2693,13 @@ dfs_offload:
333 }
334 #endif /* CONFIG_MESH */
335
336+ if (hostapd_drv_configure_edcca_enable(hapd) < 0)
337+ goto fail;
338+
339+ if (hostapd_drv_configure_edcca_threshold(hapd,
340+ hapd->iconf->edcca_threshold) < 0)
341+ goto fail;
342+
343 wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
344 iface->bss[0]->conf->iface);
345 if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
346diff --git a/src/common/mtk_vendor.h b/src/common/mtk_vendor.h
347index 4a19d2fc9..6121857dd 100644
348--- a/src/common/mtk_vendor.h
349+++ b/src/common/mtk_vendor.h
350@@ -30,14 +30,22 @@ enum mtk_vendor_attr_edcca_ctrl {
351 NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL - 1
352 };
353
354-enum mtk_vendor_attr_edcca_ctrl_mode {
355- EDCCA_CTRL_SET_EN = 0,
356- EDCCA_CTRL_SET_THERS,
357- EDCCA_CTRL_GET_EN,
358- EDCCA_CTRL_GET_THERS,
359- EDCCA_CTRL_NUM,
360+enum mtk_vendor_attr_edcca_dump {
361+ MTK_VENDOR_ATTR_EDCCA_DUMP_UNSPEC = 0,
362+
363+ MTK_VENDOR_ATTR_EDCCA_DUMP_MODE,
364+ MTK_VENDOR_ATTR_EDCCA_DUMP_PRI20_VAL,
365+ MTK_VENDOR_ATTR_EDCCA_DUMP_SEC40_VAL,
366+ MTK_VENDOR_ATTR_EDCCA_DUMP_SEC80_VAL,
367+ MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL,
368+
369+ /* keep last */
370+ NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP,
371+ MTK_VENDOR_ATTR_EDCCA_DUMP_MAX =
372+ NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP - 1
373 };
374
375+
376 static struct nla_policy edcca_ctrl_policy[NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL] = {
377 [MTK_VENDOR_ATTR_EDCCA_CTRL_MODE] = { .type = NLA_U8 },
378 [MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL] = { .type = NLA_U8 },
379diff --git a/src/drivers/driver.h b/src/drivers/driver.h
380index 3e3e309f4..ed5f5c013 100644
381--- a/src/drivers/driver.h
382+++ b/src/drivers/driver.h
383@@ -5220,6 +5220,10 @@ struct wpa_driver_ops {
384 const u8 *match, size_t match_len,
385 bool multicast);
386 #endif /* CONFIG_TESTING_OPTIONS */
387+ int (*configure_edcca_enable)(void *priv, const u8 edcca_enable,
388+ const s8 edcca_compensation);
389+ int (*configure_edcca_threshold)(void *priv, const int *threshold);
390+ int (*get_edcca)(void *priv, const u8 mode, u8 *value);
391 };
392
393 /**
394diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
395index 501d0e42e..d59efe8b6 100644
396--- a/src/drivers/driver_nl80211.c
397+++ b/src/drivers/driver_nl80211.c
398@@ -42,6 +42,8 @@
399 #include "radiotap_iter.h"
400 #include "rfkill.h"
401 #include "driver_nl80211.h"
402+#include "common/mtk_vendor.h"
403+#include "ap/ap_config.h"
404
405
406 #ifndef NETLINK_CAP_ACK
407@@ -14079,6 +14081,174 @@ static int testing_nl80211_radio_disable(void *priv, int disabled)
408
409 #endif /* CONFIG_TESTING_OPTIONS */
410
411+static int nl80211_configure_edcca_enable(void *priv,
412+ const u8 edcca_enable,
413+ const s8 edcca_compensation)
414+{
415+ struct i802_bss *bss = priv;
416+ struct wpa_driver_nl80211_data *drv = bss->drv;
417+ struct nl_msg *msg;
418+ struct nlattr *data;
419+ int ret;
420+
421+ if (!drv->mtk_edcca_vendor_cmd_avail) {
422+ wpa_printf(MSG_INFO,
423+ "nl80211: Driver does not support setting EDCCA enable");
424+ return 0;
425+ }
426+
427+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
428+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_MTK) ||
429+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
430+ MTK_NL80211_VENDOR_SUBCMD_EDCCA_CTRL) ||
431+ !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
432+ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_MODE, EDCCA_CTRL_SET_EN) ||
433+ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL, edcca_enable) ||
434+ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_COMPENSATE,
435+ edcca_compensation)) {
436+ wpa_printf (MSG_ERROR, "Prepare nl80211 msg fail");
437+ nlmsg_free(msg);
438+ return -ENOBUFS;
439+ }
440+ nla_nest_end(msg, data);
441+ ret = send_and_recv_cmd(drv, msg);
442+ if (ret) {
443+ wpa_printf(MSG_ERROR, "Failed to configure EDCCA enable. ret=%d (%s) ",
444+ ret, strerror(-ret));
445+ }
446+ return ret;
447+}
448+
449+static int nl80211_configure_edcca_threshold(void *priv, const int *threshold)
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+ int ret;
456+
457+ if (!drv->mtk_edcca_vendor_cmd_avail) {
458+ wpa_printf(MSG_INFO,
459+ "nl80211: Driver does not support setting EDCCA threshold");
460+ return 0;
461+ }
462+
463+ if (!threshold) {
464+ wpa_printf(MSG_INFO,
465+ "nl80211: Input EDCCA threshold is empty!");
466+ return 0;
467+ }
468+
469+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
470+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_MTK) ||
471+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
472+ MTK_NL80211_VENDOR_SUBCMD_EDCCA_CTRL) ||
473+ !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
474+ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_MODE, EDCCA_CTRL_SET_THRES) ||
475+ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL, threshold[0] & 0xff) ||
476+ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_SEC40_VAL, threshold[1] & 0xff) ||
477+ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_SEC80_VAL, threshold[2] & 0xff) ||
478+ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_SEC160_VAL, threshold[3] & 0xff)) {
479+ wpa_printf (MSG_ERROR, "Prepare nl80211 msg fail");
480+ nlmsg_free(msg);
481+ return -ENOBUFS;
482+ }
483+ nla_nest_end(msg, data);
484+ ret = send_and_recv_cmd(drv, msg);
485+ if (ret) {
486+ wpa_printf(MSG_ERROR, "Failed to configure EDCCA threshold. ret=%d (%s) ",
487+ ret, strerror(-ret));
488+ }
489+ return ret;
490+}
491+
492+
493+static int edcca_info_handler(struct nl_msg *msg, void *arg)
494+{
495+ u8 *info = (u8 *) arg;
496+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
497+ struct nlattr *tb_vendor[MTK_VENDOR_ATTR_EDCCA_DUMP_MAX + 1];
498+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
499+ struct nlattr *nl_vend, *attr;
500+
501+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
502+ genlmsg_attrlen(gnlh, 0), NULL);
503+
504+ nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
505+ if (!nl_vend)
506+ return NL_SKIP;
507+
508+ nla_parse(tb_vendor, MTK_VENDOR_ATTR_EDCCA_DUMP_MAX,
509+ nla_data(nl_vend), nla_len(nl_vend), NULL);
510+
511+ attr = tb_vendor[MTK_VENDOR_ATTR_EDCCA_DUMP_PRI20_VAL];
512+ if (!attr) {
513+ wpa_printf(MSG_ERROR, "nl80211: MTK_VENDOR_ATTR_EDCCA_DUMP_PRI20_VAL");
514+ return NL_SKIP;
515+ }
516+
517+ *info++ = nla_get_u8(attr);
518+
519+ attr = tb_vendor[MTK_VENDOR_ATTR_EDCCA_DUMP_SEC40_VAL];
520+ if (!attr) {
521+ wpa_printf(MSG_ERROR, "nl80211: MTK_VENDOR_ATTR_EDCCA_DUMP_SEC40_VAL");
522+ return NL_SKIP;
523+ }
524+
525+ *info++ = nla_get_u8(attr);
526+
527+ attr = tb_vendor[MTK_VENDOR_ATTR_EDCCA_DUMP_SEC80_VAL];
528+ if (!attr) {
529+ wpa_printf(MSG_ERROR, "nl80211: MTK_VENDOR_ATTR_EDCCA_DUMP_SEC80_VAL");
530+ return NL_SKIP;
531+ }
532+
533+ *info++ = nla_get_u8(attr);
534+
535+ attr = tb_vendor[MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL];
536+ if (!attr) {
537+ wpa_printf(MSG_ERROR, "nl80211: MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL");
538+ return NL_SKIP;
539+ }
540+
541+ *info = nla_get_u8(attr);
542+ return NL_SKIP;
543+}
544+
545+
546+static int nl80211_get_edcca(void *priv, const u8 mode, u8 *value)
547+{
548+ struct i802_bss *bss = priv;
549+ struct wpa_driver_nl80211_data *drv = bss->drv;
550+ struct nl_msg *msg;
551+ struct nlattr *data;
552+ int ret;
553+
554+ if (!drv->mtk_edcca_vendor_cmd_avail) {
555+ wpa_printf(MSG_INFO,
556+ "nl80211: Driver does not support setting EDCCA threshold");
557+ return 0;
558+ }
559+
560+ if (!(msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_VENDOR)) ||
561+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_MTK) ||
562+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
563+ MTK_NL80211_VENDOR_SUBCMD_EDCCA_CTRL) ||
564+ !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED)) ||
565+ nla_put_u8(msg, MTK_VENDOR_ATTR_EDCCA_CTRL_MODE, mode)) {
566+ wpa_printf (MSG_ERROR, "Prepare nl80211 msg fail");
567+ nlmsg_free(msg);
568+ return -ENOBUFS;
569+ }
570+ nla_nest_end(msg, data);
571+ ret = send_and_recv_resp(drv, msg, edcca_info_handler, value);
572+ if (ret) {
573+ wpa_printf(MSG_ERROR, "Failed to get EDCCA configuration. ret=%d (%s)",
574+ ret, strerror(-ret));
575+ }
576+ return ret;
577+}
578+
579
580 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
581 .name = "nl80211",
582@@ -14240,4 +14410,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
583 .register_frame = testing_nl80211_register_frame,
584 .radio_disable = testing_nl80211_radio_disable,
585 #endif /* CONFIG_TESTING_OPTIONS */
586+/* Need ifdef CONFIG_DRIVER_NL80211_MTK */
587+ .configure_edcca_enable = nl80211_configure_edcca_enable,
588+ .configure_edcca_threshold = nl80211_configure_edcca_threshold,
589+ .get_edcca = nl80211_get_edcca,
590 };
591diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
592index 618746e67..62c47efbd 100644
593--- a/src/drivers/driver_nl80211.h
594+++ b/src/drivers/driver_nl80211.h
595@@ -200,6 +200,7 @@ struct wpa_driver_nl80211_data {
596 unsigned int secure_ranging_ctx_vendor_cmd_avail:1;
597 unsigned int puncturing:1;
598 unsigned int qca_ap_allowed_freqs:1;
599+ unsigned int mtk_edcca_vendor_cmd_avail:1;
600
601 u32 ignore_next_local_disconnect;
602 u32 ignore_next_local_deauth;
603diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
604index d6a887cef..cd4d799a1 100644
605--- a/src/drivers/driver_nl80211_capa.c
606+++ b/src/drivers/driver_nl80211_capa.c
607@@ -18,6 +18,7 @@
608 #include "common/qca-vendor-attr.h"
609 #include "common/brcm_vendor.h"
610 #include "driver_nl80211.h"
611+#include "common/mtk_vendor.h"
612
613
614 static int protocol_feature_handler(struct nl_msg *msg, void *arg)
615@@ -1138,6 +1139,12 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
616 break;
617 }
618 #endif /* CONFIG_DRIVER_NL80211_BRCM */
619+ } else if (vinfo->vendor_id == OUI_MTK) {
620+ switch (vinfo->subcmd) {
621+ case MTK_NL80211_VENDOR_SUBCMD_EDCCA_CTRL:
622+ drv->mtk_edcca_vendor_cmd_avail = 1;
623+ break;
624+ }
625 }
626
627 wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
628--
6292.39.2
630