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