Commit | Line | Data |
---|---|---|
f3fa1980 S |
1 | /* |
2 | * Driver interaction with extended Linux CFG8021 | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License version 2 as | |
6 | * published by the Free Software Foundation. | |
7 | * | |
8 | * Alternatively, this software may be distributed under the terms of BSD | |
9 | * license. | |
10 | * | |
11 | */ | |
12 | #include "includes.h" | |
13 | #include <linux/wireless.h> | |
14 | #include "netlink/genl/genl.h" | |
15 | ||
16 | #include "common.h" | |
17 | #include "driver_nl80211.h" | |
18 | #include "linux_ioctl.h" | |
19 | #include "wpa_supplicant_i.h" | |
20 | #include "config.h" | |
21 | #ifdef ANDROID | |
22 | #include "android_drv.h" | |
23 | #endif | |
24 | ||
c481cf08 | 25 | #include "mediatek_driver_nl80211.h" |
f3fa1980 S |
26 | #include "driver_i.h" |
27 | ||
c481cf08 JA |
28 | #include "p2p/p2p_i.h" |
29 | ||
f3fa1980 | 30 | #include "eloop.h" |
c481cf08 JA |
31 | #define PRIV_CMD_SIZE 512 |
32 | ||
33 | typedef struct android_wifi_priv_cmd { | |
34 | char buf[PRIV_CMD_SIZE]; | |
35 | int used_len; | |
36 | int total_len; | |
37 | } android_wifi_priv_cmd; | |
38 | ||
39 | static int drv_errors = 0; | |
40 | ||
41 | static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv) | |
42 | { | |
43 | drv_errors++; | |
44 | if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { | |
45 | drv_errors = 0; | |
46 | /* avoid the framework to handle HANGED */ | |
47 | /* | |
48 | * wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); | |
49 | */ | |
50 | } | |
51 | } | |
52 | ||
53 | static int testmode_sta_statistics_handler(struct nl_msg *msg, void *arg) | |
54 | { | |
55 | struct nlattr *tb[NL80211_ATTR_MAX + 1] = {}; | |
56 | struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); | |
57 | struct nlattr *sinfo[NL80211_TESTMODE_STA_STATISTICS_NUM] = {}; | |
58 | struct wpa_driver_sta_statistics_s *sta_statistics = (struct wpa_driver_sta_statistics_s *)arg; | |
59 | unsigned char i = 0; | |
60 | static struct nla_policy policy[NL80211_TESTMODE_STA_STATISTICS_NUM] = { | |
61 | [NL80211_TESTMODE_STA_STATISTICS_VERSION] = { .type = NLA_U8 }, | |
62 | [NL80211_TESTMODE_STA_STATISTICS_MAC] = { .type = NLA_UNSPEC }, | |
63 | [NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE] = { .type = NLA_U32 }, | |
64 | [NL80211_TESTMODE_STA_STATISTICS_FLAG] = { .type = NLA_U32 }, | |
65 | [NL80211_TESTMODE_STA_STATISTICS_PER] = { .type = NLA_U8 }, | |
66 | [NL80211_TESTMODE_STA_STATISTICS_RSSI] = { .type = NLA_U8 }, | |
67 | [NL80211_TESTMODE_STA_STATISTICS_PHY_MODE] = { .type = NLA_U32 }, | |
68 | [NL80211_TESTMODE_STA_STATISTICS_TX_RATE] = { .type = NLA_U16 }, | |
69 | [NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT] = { .type = NLA_U32 }, | |
70 | [NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT] = { .type = NLA_U32 }, | |
71 | [NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME] = { .type = NLA_U32 }, | |
72 | [NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT] = { .type = NLA_U32 }, | |
73 | [NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT] = { .type = NLA_U32 }, | |
74 | ||
75 | [NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME] = { .type = NLA_U32 }, | |
76 | [NL80211_TESTMODE_STA_STATISTICS_MAX_PROCESS_TIME] = { .type = NLA_U32 }, | |
77 | [NL80211_TESTMODE_STA_STATISTICS_AVG_HIF_PROCESS_TIME] = { .type = NLA_U32 }, | |
78 | [NL80211_TESTMODE_STA_STATISTICS_MAX_HIF_PROCESS_TIME] = { .type = NLA_U32 }, | |
79 | ||
80 | [NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY] = { .type = NLA_UNSPEC }, | |
81 | [NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY] = { .type = NLA_UNSPEC }, | |
82 | [NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY] = { .type = NLA_UNSPEC }, | |
83 | [NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY] = { .type = NLA_UNSPEC }, | |
84 | /* | |
85 | * how many packages TX during statistics interval | |
86 | */ | |
87 | [NL80211_TESTMODE_STA_STATISTICS_ENQUEUE] = { .type = NLA_U32 }, | |
88 | /* | |
89 | * how many packages this sta TX during statistics interval | |
90 | */ | |
91 | [NL80211_TESTMODE_STA_STATISTICS_STA_ENQUEUE] = { .type = NLA_U32 }, | |
92 | ||
93 | /* | |
94 | * how many packages dequeue during statistics interval | |
95 | */ | |
96 | [NL80211_TESTMODE_STA_STATISTICS_DEQUEUE] = { .type = NLA_U32 }, | |
97 | ||
98 | /* | |
99 | * how many packages this sta dequeue during statistics interval | |
100 | */ | |
101 | [NL80211_TESTMODE_STA_STATISTICS_STA_DEQUEUE] = { .type = NLA_U32 }, | |
102 | ||
103 | /* | |
104 | * how many TC[0-3] resource back from firmware during | |
105 | * statistics interval | |
106 | */ | |
107 | [NL80211_TESTMODE_STA_STATISTICS_RB_ARRAY] = { .type = NLA_UNSPEC }, | |
108 | [NL80211_TESTMODE_STA_STATISTICS_NO_TC_ARRAY] = { .type = NLA_UNSPEC }, | |
109 | [NL80211_TESTMODE_STA_STATISTICS_TC_USED_ARRAY] = { .type = NLA_UNSPEC }, | |
110 | [NL80211_TESTMODE_STA_STATISTICS_TC_WANTED_ARRAY] = { .type = NLA_UNSPEC }, | |
111 | ||
112 | [NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_CNT] = { .type = NLA_U32 }, | |
113 | [NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_PASS_CNT] = { .type = NLA_U32 }, | |
114 | [NL80211_TESTMODE_STA_STATISTICS_IRQ_TASK_CNT] = { .type = NLA_U32 }, | |
115 | [NL80211_TESTMODE_STA_STATISTICS_IRQ_AB_CNT] = { .type = NLA_U32 }, | |
116 | [NL80211_TESTMODE_STA_STATISTICS_IRQ_SW_CNT] = { .type = NLA_U32 }, | |
117 | [NL80211_TESTMODE_STA_STATISTICS_IRQ_TX_CNT] = { .type = NLA_U32 }, | |
118 | [NL80211_TESTMODE_STA_STATISTICS_IRQ_RX_CNT] = { .type = NLA_U32 }, | |
119 | [NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY] = { .type = NLA_UNSPEC } | |
120 | }; | |
121 | ||
122 | nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), | |
123 | genlmsg_attrlen(gnlh, 0), NULL); | |
124 | ||
125 | if (!tb[NL80211_ATTR_TESTDATA] || | |
126 | nla_parse_nested(sinfo, NL80211_TESTMODE_STA_STATISTICS_MAX, tb[NL80211_ATTR_TESTDATA], policy)) | |
127 | return NL_SKIP; | |
128 | ||
129 | for (i=1; i < NL80211_TESTMODE_STA_STATISTICS_NUM; i++) { | |
130 | ||
131 | if (!sinfo[i]) | |
132 | continue; | |
133 | ||
134 | switch(i) { | |
135 | case NL80211_TESTMODE_STA_STATISTICS_VERSION: | |
136 | sta_statistics->version = nla_get_u8(sinfo[i]); | |
137 | break; | |
138 | case NL80211_TESTMODE_STA_STATISTICS_MAC: | |
139 | nla_memcpy(sta_statistics->addr, sinfo[i], ETH_ALEN); | |
140 | break; | |
141 | case NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE: | |
142 | sta_statistics->link_score = nla_get_u32(sinfo[i]); | |
143 | break; | |
144 | case NL80211_TESTMODE_STA_STATISTICS_FLAG: | |
145 | sta_statistics->flag = nla_get_u32(sinfo[i]); | |
146 | break; | |
147 | case NL80211_TESTMODE_STA_STATISTICS_PER: | |
148 | sta_statistics->per = nla_get_u8(sinfo[i]); | |
149 | break; | |
150 | case NL80211_TESTMODE_STA_STATISTICS_RSSI: | |
151 | sta_statistics->rssi = (((int)nla_get_u8(sinfo[i]) - 220) / 2); | |
152 | break; | |
153 | case NL80211_TESTMODE_STA_STATISTICS_PHY_MODE: | |
154 | sta_statistics->phy_mode = nla_get_u32(sinfo[i]); | |
155 | break; | |
156 | case NL80211_TESTMODE_STA_STATISTICS_TX_RATE: | |
157 | sta_statistics->tx_rate = (((double)nla_get_u16(sinfo[i])) / 2); | |
158 | break; | |
159 | case NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT: | |
160 | sta_statistics->tx_fail_cnt = nla_get_u32(sinfo[i]); | |
161 | break; | |
162 | case NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT: | |
163 | sta_statistics->tx_timeout_cnt = nla_get_u32(sinfo[i]); | |
164 | break; | |
165 | case NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME: | |
166 | sta_statistics->tx_avg_air_time = nla_get_u32(sinfo[i]); | |
167 | break; | |
168 | case NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT: | |
169 | sta_statistics->tx_total_cnt = nla_get_u32(sinfo[i]); | |
170 | break; | |
171 | case NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT: | |
172 | sta_statistics->tx_exc_threshold_cnt = nla_get_u32(sinfo[i]); | |
173 | break; | |
174 | case NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME: | |
175 | sta_statistics->tx_avg_process_time = nla_get_u32(sinfo[i]); | |
176 | break; | |
177 | case NL80211_TESTMODE_STA_STATISTICS_MAX_PROCESS_TIME: | |
178 | sta_statistics->tx_max_process_time = nla_get_u32(sinfo[i]); | |
179 | break; | |
180 | case NL80211_TESTMODE_STA_STATISTICS_AVG_HIF_PROCESS_TIME: | |
181 | sta_statistics->tx_avg_hif_process_time = nla_get_u32(sinfo[i]); | |
182 | break; | |
183 | case NL80211_TESTMODE_STA_STATISTICS_MAX_HIF_PROCESS_TIME: | |
184 | sta_statistics->tx_max_hif_process_time = nla_get_u32(sinfo[i]); | |
185 | break; | |
186 | case NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY: | |
187 | nla_memcpy(sta_statistics->tc_buf_full_cnt, sinfo[i], sizeof(sta_statistics->tc_buf_full_cnt)); | |
188 | break; | |
189 | case NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY: | |
190 | nla_memcpy(sta_statistics->tc_que_len, sinfo[i], sizeof(sta_statistics->tc_que_len)); | |
191 | break; | |
192 | case NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY: | |
193 | nla_memcpy(sta_statistics->tc_avg_que_len, sinfo[i], sizeof(sta_statistics->tc_avg_que_len)); | |
194 | break; | |
195 | case NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY: | |
196 | nla_memcpy(sta_statistics->tc_cur_que_len, sinfo[i], sizeof(sta_statistics->tc_cur_que_len)); | |
197 | break; | |
198 | ||
199 | case NL80211_TESTMODE_STA_STATISTICS_ENQUEUE: | |
200 | sta_statistics->enqueue_total_cnt = nla_get_u32(sinfo[i]); | |
201 | break; | |
202 | ||
203 | case NL80211_TESTMODE_STA_STATISTICS_DEQUEUE: | |
204 | sta_statistics->dequeue_total_cnt = nla_get_u32(sinfo[i]); | |
205 | break; | |
206 | ||
207 | case NL80211_TESTMODE_STA_STATISTICS_STA_ENQUEUE: | |
208 | sta_statistics->enqueue_sta_total_cnt = nla_get_u32(sinfo[i]); | |
209 | break; | |
210 | ||
211 | case NL80211_TESTMODE_STA_STATISTICS_STA_DEQUEUE: | |
212 | sta_statistics->dequeue_sta_total_cnt = nla_get_u32(sinfo[i]); | |
213 | break; | |
214 | ||
215 | case NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_CNT: | |
216 | sta_statistics->isr_cnt = nla_get_u32(sinfo[i]); | |
217 | break; | |
218 | ||
219 | case NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_PASS_CNT: | |
220 | sta_statistics->isr_pass_cnt = nla_get_u32(sinfo[i]); | |
221 | break; | |
222 | case NL80211_TESTMODE_STA_STATISTICS_IRQ_TASK_CNT: | |
223 | sta_statistics->isr_task_cnt = nla_get_u32(sinfo[i]); | |
224 | break; | |
225 | ||
226 | case NL80211_TESTMODE_STA_STATISTICS_IRQ_AB_CNT: | |
227 | sta_statistics->isr_ab_cnt = nla_get_u32(sinfo[i]); | |
228 | break; | |
229 | ||
230 | case NL80211_TESTMODE_STA_STATISTICS_IRQ_SW_CNT: | |
231 | sta_statistics->isr_sw_cnt = nla_get_u32(sinfo[i]); | |
232 | break; | |
233 | ||
234 | case NL80211_TESTMODE_STA_STATISTICS_IRQ_TX_CNT: | |
235 | sta_statistics->isr_tx_cnt = nla_get_u32(sinfo[i]); | |
236 | break; | |
237 | ||
238 | case NL80211_TESTMODE_STA_STATISTICS_IRQ_RX_CNT: | |
239 | sta_statistics->isr_rx_cnt = nla_get_u32(sinfo[i]); | |
240 | break; | |
241 | ||
242 | case NL80211_TESTMODE_STA_STATISTICS_NO_TC_ARRAY: | |
243 | nla_memcpy(sta_statistics->dequeue_no_tc_res, sinfo[i], | |
244 | sizeof(sta_statistics->dequeue_no_tc_res)); | |
245 | break; | |
246 | ||
247 | case NL80211_TESTMODE_STA_STATISTICS_TC_USED_ARRAY: | |
248 | nla_memcpy(sta_statistics->tc_used_res, sinfo[i], | |
249 | sizeof(sta_statistics->tc_used_res)); | |
250 | break; | |
251 | case NL80211_TESTMODE_STA_STATISTICS_TC_WANTED_ARRAY: | |
252 | nla_memcpy(sta_statistics->tc_wanted_res, sinfo[i], | |
253 | sizeof(sta_statistics->tc_wanted_res)); | |
254 | break; | |
255 | ||
256 | case NL80211_TESTMODE_STA_STATISTICS_RB_ARRAY: | |
257 | nla_memcpy(sta_statistics->tc_back_count, sinfo[i], | |
258 | sizeof(sta_statistics->tc_back_count)); | |
259 | break; | |
260 | ||
261 | case NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY: | |
262 | nla_memcpy(sta_statistics->reserved, sinfo[i], sizeof(sta_statistics->reserved)); | |
263 | break; | |
264 | default: | |
265 | break; | |
266 | } | |
267 | } | |
268 | ||
269 | return NL_SKIP; | |
270 | } | |
271 | ||
272 | #ifdef CONFIG_MTK_LTE_COEX | |
273 | static int testmode_available_channel_handler(struct nl_msg *msg, void *arg) | |
274 | { | |
275 | struct nlattr *tb[NL80211_ATTR_MAX + 1] = {}; | |
276 | struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); | |
277 | struct nlattr *tb_chan[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_MAX + 1] = {}; | |
278 | struct wpa_driver_available_chan_s *available_chans = (struct wpa_driver_available_chan_s *)arg; | |
279 | static struct nla_policy chan_policy[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_MAX + 1] = { | |
280 | [NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_2G_BASE_1] = { .type = NLA_U32 }, | |
281 | [NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_36] = { .type = NLA_U32 }, | |
282 | [NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_52] = { .type = NLA_U32 }, | |
283 | [NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_100] = { .type = NLA_U32 }, | |
284 | [NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_149] = { .type = NLA_U32 }, | |
285 | }; | |
286 | ||
287 | nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), | |
288 | genlmsg_attrlen(gnlh, 0), NULL); | |
289 | ||
290 | if (!tb[NL80211_ATTR_TESTDATA] || | |
291 | nla_parse_nested(tb_chan, NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_MAX, tb[NL80211_ATTR_TESTDATA], chan_policy)) | |
292 | return NL_SKIP; | |
293 | ||
294 | if (tb_chan[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_2G_BASE_1]) | |
295 | available_chans->ch_2g_base1 = nla_get_u32(tb_chan[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_2G_BASE_1]); | |
296 | ||
297 | if (tb_chan[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_36]) | |
298 | available_chans->ch_5g_base36 = nla_get_u32(tb_chan[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_36]); | |
299 | ||
300 | if (tb_chan[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_52]) | |
301 | available_chans->ch_5g_base52 = nla_get_u32(tb_chan[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_52]); | |
302 | ||
303 | if (tb_chan[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_100]) | |
304 | available_chans->ch_5g_base100 = nla_get_u32(tb_chan[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_100]); | |
305 | ||
306 | if (tb_chan[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_149]) | |
307 | available_chans->ch_5g_base149 = nla_get_u32(tb_chan[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_149]); | |
308 | ||
309 | return NL_SKIP; | |
310 | } | |
311 | #endif | |
312 | ||
313 | static int wpa_driver_nl80211_testmode(void *priv, const u8 *data, size_t data_len) | |
314 | { | |
315 | struct i802_bss *bss = priv; | |
316 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
317 | struct nl_msg *msg, *cqm = NULL; | |
318 | struct wpa_driver_testmode_params *params; | |
319 | int index; | |
320 | ||
321 | msg = nlmsg_alloc(); | |
322 | if (!msg) | |
323 | return -1; | |
324 | ||
325 | wpa_printf(MSG_DEBUG, "nl80211 test mode: ifindex=%d", drv->ifindex); | |
326 | ||
327 | nl80211_cmd(drv, msg, 0, NL80211_CMD_TESTMODE); | |
328 | ||
329 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); | |
330 | NLA_PUT(msg, NL80211_ATTR_TESTDATA, data_len, data); | |
331 | ||
332 | params = (struct wpa_driver_testmode_params *)data; | |
333 | ||
334 | /* Mask version field */ | |
335 | index = params->hdr.index & BITS(0, 23); | |
336 | ||
337 | switch(index) { | |
338 | case 0x10: | |
339 | { | |
340 | struct wpa_driver_get_sta_statistics_params *sta_params = | |
341 | (struct wpa_driver_get_sta_statistics_params *)data; | |
342 | return send_and_recv_msgs(drv, msg, testmode_sta_statistics_handler, sta_params->buf); | |
343 | } | |
344 | #ifdef CONFIG_MTK_LTE_COEX | |
345 | case 0x30: | |
346 | { | |
347 | struct wpa_driver_get_available_channel_params *chan_params = | |
348 | (struct wpa_driver_get_available_channel_params *)data; | |
349 | return send_and_recv_msgs(drv, msg, testmode_available_channel_handler, chan_params->buf); | |
350 | } | |
351 | #endif | |
352 | default: | |
353 | { | |
354 | int ret = send_and_recv_msgs(drv, msg, NULL, NULL); | |
355 | wpa_printf(MSG_EXCESSIVE, "ret=%d, nl=%p", ret, drv->global->nl); | |
356 | return ret; | |
357 | } | |
358 | } | |
359 | ||
360 | nla_put_failure: | |
361 | nlmsg_free(msg); | |
362 | return -ENOBUFS; | |
363 | } | |
364 | ||
365 | static int wpa_driver_nl80211_driver_sw_cmd(void *priv, int set, u32 *adr, u32 *dat) | |
366 | { | |
367 | struct i802_bss *bss = priv; | |
368 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
369 | struct wpa_driver_sw_cmd_params params; | |
370 | struct nl_msg *msg, *cqm = NULL; | |
371 | int ret = 0; | |
372 | ||
373 | os_memset(¶ms, 0, sizeof(params)); | |
374 | ||
375 | params.hdr.index = NL80211_TESTMODE_SW_CMD; | |
376 | params.hdr.index = params.hdr.index | (0x01 << 24); | |
377 | params.hdr.buflen = sizeof(struct wpa_driver_sw_cmd_params); | |
378 | ||
379 | params.adr = *adr; | |
380 | params.data = *dat; | |
381 | ||
382 | if (set) | |
383 | params.set = 1; | |
384 | else | |
385 | params.set = 0; | |
386 | ||
387 | wpa_driver_nl80211_testmode(priv, (u8 *)¶ms, sizeof(struct wpa_driver_sw_cmd_params)); | |
388 | return 0; | |
389 | } | |
390 | ||
391 | #ifdef CONFIG_HOTSPOT_MGR_SUPPORT | |
392 | static int wpa_driver_hotspot_block_list_update(void *priv, const u8 *bssid, int blocked) | |
393 | { | |
394 | struct wpa_driver_hotspot_params params; | |
395 | ||
396 | os_memset(¶ms, 0, sizeof(params)); | |
397 | ||
398 | if (bssid) | |
399 | os_memcpy(params.bssid, bssid, ETH_ALEN); | |
400 | ||
401 | params.blocked = (u8)blocked; | |
402 | ||
403 | params.hdr.index = NL80211_TESTMODE_HS20; | |
404 | params.hdr.index = params.hdr.index | (0x01 << 24); | |
405 | params.hdr.buflen = sizeof(struct wpa_driver_hotspot_params); | |
406 | ||
407 | return wpa_driver_nl80211_testmode(priv, (u8 *)¶ms, | |
408 | sizeof(struct wpa_driver_hotspot_params)); | |
409 | } | |
410 | ||
411 | static int wpa_driver_sta_block(void *priv, char *cmd) | |
412 | { | |
413 | u8 bssid[ETH_ALEN] = {}; | |
414 | int blocked = 1; | |
415 | ||
416 | /* Block client device */ | |
417 | if (hwaddr_aton(cmd, bssid)) { | |
418 | wpa_printf(MSG_DEBUG, "STA block: invalid DEVICE ADDRESS '%s'", cmd); | |
419 | return -1; | |
420 | } | |
421 | ||
422 | wpa_printf(MSG_DEBUG, "Block STA " MACSTR, MAC2STR(bssid)); | |
423 | return wpa_driver_hotspot_block_list_update(priv, bssid, blocked); | |
424 | } | |
425 | ||
426 | static int wpa_driver_sta_unblock(void *priv, char *cmd) | |
427 | { | |
428 | u8 bssid[ETH_ALEN] = {}; | |
429 | int blocked = 0; | |
430 | ||
431 | /* Unblock client device */ | |
432 | if (hwaddr_aton(cmd, bssid)) { | |
433 | wpa_printf(MSG_DEBUG, "STA unblock : invalid DEVICE ADDRESS '%s'", cmd); | |
434 | return -1; | |
435 | } | |
436 | ||
437 | wpa_printf(MSG_DEBUG, "Unblock STA " MACSTR, MAC2STR(bssid)); | |
438 | return wpa_driver_hotspot_block_list_update(priv, bssid, blocked); | |
439 | } | |
440 | ||
441 | static int wpa_driver_set_max_client(void *priv, char *cmd, char *buf, size_t buflen) | |
442 | { | |
443 | char *str = NULL; | |
444 | int len = 0; | |
445 | int value = 0; | |
446 | struct wpa_driver_hotspot_set_config_params params; | |
447 | ||
448 | os_memset(¶ms, 0, sizeof(params)); | |
449 | ||
450 | value = atoi(cmd); | |
451 | ||
452 | wpa_printf(MSG_DEBUG, "CTRL_IFACE set_max_connect value=%d\n", value); | |
453 | ||
454 | params.hdr.index = NL80211_TESTMODE_HS_SET_CONFIG; | |
455 | params.hdr.index = params.hdr.index | (0x01 << 24); | |
456 | params.hdr.buflen = sizeof(struct wpa_driver_hotspot_set_config_params); | |
457 | ||
458 | params.index = 1; | |
459 | params.value = (u32)value; | |
460 | ||
461 | return wpa_driver_nl80211_testmode(priv, (u8 *)¶ms, | |
462 | sizeof(struct wpa_driver_hotspot_set_config_params)); | |
463 | } | |
464 | #endif /* CONFIG_HOTSPOT_MGR_SUPPORT */ | |
465 | ||
466 | #ifdef CONFIG_MTK_LTE_COEX | |
467 | int wpa_driver_get_lte_available_channels(void *priv, struct wpa_driver_available_chan_s *buf) | |
468 | { | |
469 | struct wpa_driver_get_available_channel_params params; | |
470 | ||
471 | os_memset(¶ms, 0, sizeof(params)); | |
472 | ||
473 | params.hdr.index = 0x30; | |
474 | params.hdr.index = params.hdr.index | (0x01 << 24); | |
475 | params.hdr.buflen = sizeof(struct wpa_driver_get_available_channel_params); | |
476 | /* buffer for return structure */ | |
477 | params.buf = (u8 *)buf; | |
478 | return wpa_driver_nl80211_testmode(priv, (u8 *)¶ms, | |
479 | sizeof(struct wpa_driver_get_available_channel_params)); | |
480 | } | |
481 | ||
482 | static u8 wpa_driver_do_mtk_acs(void *priv) | |
483 | { | |
484 | struct wpa_driver_available_chan_s available_chans; | |
485 | u8 ch[14]; | |
486 | int ch_num, i; | |
487 | int wait_cnt = 0; | |
488 | ||
489 | do { | |
490 | os_memset(&available_chans, 0, sizeof(struct wpa_driver_available_chan_s)); | |
491 | wpa_driver_get_lte_available_channels(priv, &available_chans); | |
492 | ||
493 | if (BIT(31) & available_chans.ch_2g_base1) { | |
494 | wpa_printf(MSG_DEBUG, "2G Channel: 0x%08x", available_chans.ch_2g_base1); | |
495 | break; | |
496 | } else { | |
497 | wpa_printf(MSG_DEBUG, "2G Channel: 0x%08x, waiting for scan complete", | |
498 | available_chans.ch_2g_base1); | |
499 | wait_cnt++; | |
500 | if (wait_cnt > 5) | |
501 | return 0; | |
502 | os_sleep(0, 1000*350); | |
503 | } | |
504 | } while(1); | |
505 | ||
506 | os_memset(ch, 0, sizeof(ch)); | |
507 | ch_num = 0; | |
508 | ||
509 | for (i = 0; i < 14; i++) { | |
510 | if (BIT(i) & available_chans.ch_2g_base1) { | |
511 | ch[ch_num] = i + 1; | |
512 | ch_num++; | |
513 | } else | |
514 | continue; | |
515 | } | |
516 | ||
517 | wpa_printf(MSG_DEBUG, "Driver report 2G available %d channel", ch_num); | |
518 | for (i = 0; i < ch_num; i++) | |
519 | wpa_printf(MSG_DEBUG,"Channel %d is fine", ch[i]); | |
520 | ||
521 | return ch[0]; | |
522 | } | |
523 | #endif /* CONFIG_MTK_LTE_COEX */ | |
524 | ||
525 | #ifdef CONFIG_WAPI_SUPPORT | |
526 | int wpa_driver_nl80211_set_wapi_key(void *priv, | |
527 | const u8 *addr, int key_idx, | |
528 | int set_tx, const u8 *seq, | |
529 | size_t seq_len, | |
530 | const u8 *key, size_t key_len) | |
531 | { | |
532 | struct i802_bss *bss = priv; | |
533 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
534 | struct nl_msg *msg, *cqm = NULL; | |
535 | struct wpa_driver_wapi_key_params params; | |
536 | int ret = 0; | |
537 | ||
538 | os_memset(¶ms, 0, sizeof(params)); | |
539 | ||
540 | params.hdr.index = NL80211_TESTMODE_WAPI; | |
541 | params.hdr.index = params.hdr.index | (0x01 << 24); | |
542 | params.hdr.buflen = sizeof(struct wpa_driver_wapi_key_params); | |
543 | ||
544 | wpa_printf(MSG_DEBUG, "[WAPI-DEBUG]1 %s: ", __FUNCTION__); | |
545 | ||
546 | if (seq_len > IW_ENCODE_SEQ_MAX_SIZE * 2) { | |
547 | wpa_printf(MSG_DEBUG, "[WAPI-DEBUG]%s: Invalid seq_len %lu", | |
548 | __FUNCTION__, (unsigned long)seq_len); | |
549 | return -1; | |
550 | } | |
551 | ||
552 | params.key_index = key_idx + 1; | |
553 | params.key_len = key_len; | |
554 | ||
555 | if (addr == NULL || | |
556 | os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0) | |
557 | params.extparams.ext_flags |= IW_ENCODE_EXT_GROUP_KEY; | |
558 | if (set_tx) | |
559 | params.extparams.ext_flags |= IW_ENCODE_EXT_SET_TX_KEY; | |
560 | ||
561 | if (addr) | |
562 | os_memcpy(params.extparams.addr, addr, ETH_ALEN); | |
563 | else | |
564 | os_memset(params.extparams.addr, 0xff, ETH_ALEN); | |
565 | ||
566 | if (key && key_len) { | |
567 | os_memcpy(params.extparams.key, key, key_len); | |
568 | params.extparams.key_len = key_len; | |
569 | } | |
570 | ||
571 | wpa_printf(MSG_DEBUG, "[WAPI-DEBUG]2 %s:", __FUNCTION__); | |
572 | ||
573 | wpa_printf(MSG_DEBUG, "%s: Set IW_ENCODE_ALG_SMS4 to ext->alg", | |
574 | __FUNCTION__); | |
575 | ||
576 | params.extparams.alg = IW_ENCODE_ALG_SMS4; | |
577 | ||
578 | wpa_printf(MSG_DEBUG, "[WAPI-DEBUG]3 %s: ", __FUNCTION__); | |
579 | ||
580 | if (seq && seq_len) | |
581 | os_memcpy(params.extparams.tx_seq, seq, seq_len); | |
582 | ||
583 | wpa_hexdump(MSG_DEBUG, "seq", seq, seq_len); | |
584 | ||
585 | wpa_printf(MSG_DEBUG, "[WAPI-DEBUG]4 Copy buffer %s: ", __FUNCTION__); | |
586 | ||
587 | wpa_driver_nl80211_testmode(priv, (u8 *)¶ms, sizeof(struct wpa_driver_wapi_key_params)); | |
588 | ||
589 | return 0; | |
590 | } | |
591 | ||
592 | /** | |
593 | * wpa_driver_nl80211_send_msg - send some information to driver | |
594 | * @priv: private driver interface data from init() | |
595 | * @msg_in: the message sent to driver | |
596 | * @msg_in_len: the length of sent message | |
597 | * @msg_out: the message given back from driver | |
598 | * @msg_out_len: the length of message given back from driver | |
599 | * | |
600 | * Returns: 0 on success, -1 on failure | |
601 | * | |
602 | */ | |
603 | static int wpa_driver_nl80211_send_msg(void *priv, const u8 *msg_in, int msg_in_len, | |
604 | u8 *msg_out, int *msg_out_len) | |
605 | { | |
606 | struct i802_bss *bss = priv; | |
607 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
608 | int ret = 0; | |
609 | ||
610 | if (msg_in_len > 1024) { | |
611 | wpa_printf(MSG_DEBUG, "wpa_driver_nl80211_send_msg: msg too long"); | |
612 | return -1; | |
613 | } | |
614 | ||
615 | return ret; | |
616 | } | |
617 | #endif /* CONFIG_WAPI_SUPPORT */ | |
618 | ||
619 | static inline int wpa_drv_set_test_mode(struct wpa_supplicant *wpa_s, | |
620 | const u8 *buf, size_t buf_len) | |
621 | { | |
622 | return wpa_driver_nl80211_testmode(wpa_s->drv_priv, buf, buf_len); | |
623 | } | |
624 | ||
625 | ||
626 | /********************************************************************** | |
627 | * OVERLAPPED functins, previous defination is in driver_nl80211.c, | |
628 | * it will be modified | |
629 | ***********************************************************************/ | |
630 | ||
631 | /**********************************************************************/ | |
632 | extern int wpa_config_write(const char *name, struct wpa_config *config); | |
633 | ||
634 | static int wpa_driver_mediatek_set_country(void *priv, const char *alpha2_arg) | |
635 | { | |
636 | struct i802_bss *bss = priv; | |
637 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
638 | int ioctl_sock = -1; | |
639 | struct iwreq iwr; | |
640 | int ret = -1; | |
641 | char buf[11]; | |
642 | #ifdef MTK_TC1_FEATURE | |
643 | char replace_ifname[IFNAMSIZ+1]; | |
644 | ||
645 | memset(replace_ifname, 0, IFNAMSIZ+1); | |
646 | os_strlcpy(replace_ifname, "wlan0", os_strlen("wlan0")+1); | |
647 | #endif | |
648 | ||
649 | ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); | |
650 | if (ioctl_sock < 0) { | |
651 | wpa_printf(MSG_ERROR, "%s: socket(PF_INET,SOCK_DGRAM)", __func__); | |
652 | return -1; | |
653 | } | |
654 | os_memset(&iwr, 0, sizeof(iwr)); | |
655 | #ifdef MTK_TC1_FEATURE | |
656 | // convert 'p2p0' -> 'wlan0' : | |
657 | // when iface name is p2p0, COUNTRY driver command doesn't support in MTK solution. | |
658 | if (os_strncmp(drv->first_bss->ifname, "p2p0", os_strlen("p2p0")) == 0) { | |
659 | wpa_printf(MSG_DEBUG, "Change interface name : p2p0->wlan0"); | |
660 | os_strlcpy(iwr.ifr_name, replace_ifname, IFNAMSIZ ); | |
661 | } else { | |
662 | os_strlcpy(iwr.ifr_name, drv->first_bss->ifname, IFNAMSIZ); | |
663 | } | |
664 | #else | |
665 | os_strlcpy(iwr.ifr_name, drv->first_bss->ifname, IFNAMSIZ); | |
666 | #endif | |
667 | snprintf(buf, sizeof(buf), "COUNTRY %s", alpha2_arg); | |
668 | iwr.u.data.pointer = buf; | |
669 | iwr.u.data.length = strlen(buf); | |
670 | if ((ret = ioctl(ioctl_sock, 0x8B0C, &iwr)) < 0) { // SIOCSIWPRIV | |
671 | wpa_printf(MSG_DEBUG, "ioctl[SIOCSIWPRIV]: %s", buf); | |
672 | close(ioctl_sock); | |
673 | return ret; | |
674 | } | |
675 | else { | |
676 | close(ioctl_sock); | |
677 | return 0; | |
678 | } | |
679 | ||
680 | } | |
681 | ||
682 | /* | |
683 | * update channel list in wpa_supplicant | |
684 | * if coutry code chanaged | |
685 | */ | |
686 | static void wpa_driver_notify_country_change(struct wpa_global *global, char *cmd) | |
687 | { | |
688 | struct wpa_supplicant *wpa_s; | |
689 | ||
690 | if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) { | |
691 | union wpa_event_data event; | |
692 | ||
693 | os_memset(&event, 0, sizeof(event)); | |
694 | event.channel_list_changed.initiator = REGDOM_SET_BY_USER; | |
695 | if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) { | |
696 | event.channel_list_changed.type = REGDOM_TYPE_COUNTRY; | |
697 | if (os_strlen(cmd) > 9) { | |
698 | event.channel_list_changed.alpha2[0] = cmd[8]; | |
699 | event.channel_list_changed.alpha2[1] = cmd[9]; | |
700 | } | |
701 | } else { | |
702 | event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; | |
703 | } | |
704 | // Notify all interfaces | |
705 | for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { | |
706 | wpa_supplicant_event(wpa_s, EVENT_CHANNEL_LIST_CHANGED, &event); | |
707 | } | |
708 | } | |
709 | } | |
710 | ||
711 | /** | |
712 | * mtk_p2p_get_device - Fetch a peer entry | |
713 | * @p2p: P2P module context from p2p_init() | |
714 | * @addr: P2P Device Address of the peer | |
715 | * Returns: Pointer to the device entry or %NULL if not found | |
716 | */ | |
717 | struct p2p_device *mtk_p2p_get_device(struct p2p_data *p2p, const u8 *addr) | |
718 | { | |
719 | struct p2p_device *dev; | |
720 | ||
721 | dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { | |
722 | if (memcmp(dev->info.p2p_device_addr, addr, ETH_ALEN) == 0) | |
723 | return dev; | |
724 | } | |
725 | return NULL; | |
726 | } | |
727 | /* | |
728 | * we should use interface MAC address | |
729 | * instead of device MAC when query | |
730 | * STA statistics, as driver uses interface addr | |
731 | * to do TX/RX | |
732 | * In most cases, the interface addr and device addr | |
733 | * should be the same | |
734 | */ | |
735 | u8 *wpas_p2p_get_sta_mac(struct wpa_supplicant *wpa_s, u8 *org_addr) | |
736 | { | |
737 | struct p2p_data *p2p = wpa_s->global->p2p; | |
738 | struct wpa_ssid *ssid = wpa_s->current_ssid; | |
739 | struct p2p_device *dev = NULL; | |
740 | int is_p2p_client = 0; | |
741 | ||
742 | if (!p2p) { | |
743 | wpa_printf(MSG_DEBUG, "interface %s not support p2p", wpa_s->ifname); | |
744 | return NULL; | |
745 | } | |
746 | ||
747 | if (!ssid) { | |
748 | wpa_printf(MSG_DEBUG, "P2P: ssid not connected"); | |
749 | return NULL; | |
750 | } | |
751 | ||
752 | dev = mtk_p2p_get_device(p2p, org_addr); | |
753 | ||
754 | if (!dev) { | |
755 | wpa_printf(MSG_DEBUG, "P2P: device " MACSTR "not found", | |
756 | MAC2STR(org_addr)); | |
757 | return NULL; | |
758 | } | |
759 | ||
760 | is_p2p_client = ssid->mode == WPAS_MODE_INFRA ? 1 : 0; | |
761 | ||
762 | if (is_p2p_client) { | |
763 | if (memcmp(dev->info.p2p_device_addr, wpa_s->bssid, ETH_ALEN) && | |
764 | !is_zero_ether_addr(wpa_s->bssid)) { | |
765 | wpa_printf(MSG_DEBUG, "P2P: we are GC, Use interface_addr " | |
766 | MACSTR "instead of " MACSTR, | |
767 | MAC2STR(wpa_s->bssid), | |
768 | MAC2STR(org_addr)); | |
769 | return wpa_s->bssid; | |
770 | } | |
771 | } | |
772 | ||
773 | /* | |
774 | * we are GO, interface_addr should be filled | |
775 | * when RX NL80211_CMD_NEW_STA event | |
776 | * if it is defferent between device addr and interface addr | |
777 | */ | |
778 | if (memcmp(dev->info.p2p_device_addr, dev->interface_addr, ETH_ALEN) && | |
779 | !is_zero_ether_addr(dev->interface_addr)) { | |
780 | wpa_printf(MSG_DEBUG, "P2P: we are GO, Use interface_addr " MACSTR | |
781 | "instead of " MACSTR, | |
782 | MAC2STR(dev->interface_addr), | |
783 | MAC2STR(org_addr)); | |
784 | return dev->interface_addr; | |
785 | } | |
786 | return NULL; | |
787 | } | |
788 | ||
789 | /* Move GET_STA_STATISTICS to "DRIVER GET_STA_STATISTICS", implement in 3rd part lib */ | |
790 | /* [ALPS00618361] [WFD Quality Enhancement] */ | |
791 | int wpas_get_sta_statistics(struct wpa_supplicant *wpa_s, u8 *sta_addr, u8 *buf) | |
792 | { | |
793 | struct wpa_driver_get_sta_statistics_params params; | |
794 | ||
795 | os_memset(¶ms, 0, sizeof(params)); | |
796 | ||
797 | if(sta_addr) | |
798 | os_memcpy(params.addr, sta_addr, ETH_ALEN); | |
799 | ||
800 | wpa_printf(MSG_DEBUG, "get_sta_statistics ["MACSTR"]", MAC2STR(params.addr)); | |
801 | ||
802 | params.hdr.index = NL80211_TESTMODE_STATISTICS; | |
803 | params.hdr.index = params.hdr.index | (0x01 << 24); | |
804 | params.hdr.buflen = sizeof(struct wpa_driver_get_sta_statistics_params); | |
805 | ||
806 | /* buffer for return structure */ | |
807 | params.buf = buf; | |
808 | ||
809 | return wpa_driver_nl80211_testmode(wpa_s->drv_priv, (u8 *)¶ms, | |
810 | sizeof(struct wpa_driver_get_sta_statistics_params)); | |
811 | } | |
812 | ||
813 | /* [ALPS00618361] [WFD Quality Enhancement] [changelist 1686130] */ | |
814 | static int print_sta_statistics(struct wpa_supplicant *wpa_s, struct wpa_driver_sta_statistics_s *sta_stats, | |
815 | unsigned long mask, char *buf, size_t buflen) | |
816 | { | |
817 | size_t i; | |
818 | int ret; | |
819 | char *pos, *end; | |
820 | ||
821 | pos = buf; | |
822 | end = buf + buflen; | |
823 | ||
824 | ret = os_snprintf(pos, end - pos, "sta_addr="MACSTR"\n", MAC2STR(sta_stats->addr)); | |
825 | if (ret < 0 || ret >= end - pos) | |
826 | return 0; | |
827 | pos += ret; | |
828 | ||
829 | ret = os_snprintf(pos, end - pos, "link_score=%d\n", sta_stats->link_score); | |
830 | if (ret < 0 || ret >= end - pos) | |
831 | return 0; | |
832 | pos += ret; | |
833 | ||
834 | ret = os_snprintf(pos, end - pos, "per=%d\n", sta_stats->per); | |
835 | if (ret < 0 || ret >= end - pos) | |
836 | return 0; | |
837 | pos += ret; | |
838 | ||
839 | ret = os_snprintf(pos, end - pos, "rssi=%d\n", sta_stats->rssi); | |
840 | if (ret < 0 || ret >= end - pos) | |
841 | return 0; | |
842 | pos += ret; | |
843 | ||
844 | ret = os_snprintf(pos, end - pos, "phy=0x%08X\n", sta_stats->phy_mode); | |
845 | if (ret < 0 || ret >= end - pos) | |
846 | return 0; | |
847 | pos += ret; | |
848 | ||
849 | ret = os_snprintf(pos, end - pos, "rate=%.1f\n", sta_stats->tx_rate); | |
850 | if (ret < 0 || ret >= end - pos) | |
851 | return 0; | |
852 | pos += ret; | |
853 | ||
854 | ret = os_snprintf(pos, end - pos, "total_cnt=%d\n", sta_stats->tx_total_cnt); | |
855 | if (ret < 0 || ret >= end - pos) | |
856 | return 0; | |
857 | pos += ret; | |
858 | ||
859 | ret = os_snprintf(pos, end - pos, "threshold_cnt=%d\n", sta_stats->tx_exc_threshold_cnt); | |
860 | if (ret < 0 || ret >= end - pos) | |
861 | return 0; | |
862 | pos += ret; | |
863 | ||
864 | ret = os_snprintf(pos, end - pos, "fail_cnt=%d\n", sta_stats->tx_fail_cnt); | |
865 | if (ret < 0 || ret >= end - pos) | |
866 | return 0; | |
867 | pos += ret; | |
868 | ||
869 | ret = os_snprintf(pos, end - pos, "timeout_cnt=%d\n", sta_stats->tx_timeout_cnt); | |
870 | if (ret < 0 || ret >= end - pos) | |
871 | return 0; | |
872 | pos += ret; | |
873 | ||
874 | ret = os_snprintf(pos, end - pos, "apt=%d\n", sta_stats->tx_avg_process_time); | |
875 | if (ret < 0 || ret >= end - pos) | |
876 | return 0; | |
877 | pos += ret; | |
878 | ||
879 | ret = os_snprintf(pos, end - pos, "aat=%d\n", sta_stats->tx_avg_air_time); | |
880 | if (ret < 0 || ret >= end - pos) | |
881 | return 0; | |
882 | pos += ret; | |
883 | ||
884 | ret = os_snprintf(pos, end - pos, "TC_buf_full_cnt=%d:%d:%d:%d\n", | |
885 | sta_stats->tc_buf_full_cnt[TC0_INDEX], | |
886 | sta_stats->tc_buf_full_cnt[TC1_INDEX], | |
887 | sta_stats->tc_buf_full_cnt[TC2_INDEX], | |
888 | sta_stats->tc_buf_full_cnt[TC3_INDEX]); | |
889 | if (ret < 0 || ret >= end - pos) | |
890 | return 0; | |
891 | pos += ret; | |
892 | ||
893 | ret = os_snprintf(pos, end - pos, "TC_sta_que_len=%d:%d:%d:%d\n", | |
894 | sta_stats->tc_que_len[TC0_INDEX], | |
895 | sta_stats->tc_que_len[TC1_INDEX], | |
896 | sta_stats->tc_que_len[TC2_INDEX], | |
897 | sta_stats->tc_que_len[TC3_INDEX]); | |
898 | if (ret < 0 || ret >= end - pos) | |
899 | return 0; | |
900 | pos += ret; | |
901 | ||
902 | ret = os_snprintf(pos, end - pos, "TC_avg_que_len=%d:%d:%d:%d\n", | |
903 | sta_stats->tc_avg_que_len[TC0_INDEX], | |
904 | sta_stats->tc_avg_que_len[TC1_INDEX], | |
905 | sta_stats->tc_avg_que_len[TC2_INDEX], | |
906 | sta_stats->tc_avg_que_len[TC3_INDEX]); | |
907 | if (ret < 0 || ret >= end - pos) | |
908 | return 0; | |
909 | pos += ret; | |
910 | ||
911 | ret = os_snprintf(pos, end - pos, "TC_cur_que_len=%d:%d:%d:%d\n", | |
912 | sta_stats->tc_cur_que_len[TC0_INDEX], | |
913 | sta_stats->tc_cur_que_len[TC1_INDEX], | |
914 | sta_stats->tc_cur_que_len[TC2_INDEX], | |
915 | sta_stats->tc_cur_que_len[TC3_INDEX]); | |
916 | if (ret < 0 || ret >= end - pos) | |
917 | return 0; | |
918 | pos += ret; | |
919 | ||
920 | ret = os_snprintf(pos, end - pos, "flag=0x%08X\n", sta_stats->flag); | |
921 | if (ret < 0 || ret >= end - pos) | |
922 | return 0; | |
923 | pos += ret; | |
924 | ||
925 | ret = os_snprintf(pos, end - pos, "reserved0="); | |
926 | if (ret < 0 || ret >= end - pos) | |
927 | return 0; | |
928 | pos += ret; | |
929 | for (i = 0; i < 16; i++) { | |
930 | ret = os_snprintf(pos, end - pos, "%02X", sta_stats->reserved[i]); | |
931 | if (ret < 0 || ret >= end - pos) | |
932 | return 0; | |
933 | pos += ret; | |
934 | ||
935 | if (((i + 1) % 4) == 0) { | |
936 | ret = os_snprintf(pos, end - pos, " "); | |
937 | if (ret < 0 || ret >= end - pos) | |
938 | return 0; | |
939 | pos += ret; | |
940 | } | |
941 | } | |
942 | ret = os_snprintf(pos, end - pos, "\n"); | |
943 | if (ret < 0 || ret >= end - pos) | |
944 | return 0; | |
945 | pos += ret; | |
946 | ||
947 | ret = os_snprintf(pos, end - pos, "reserved1="); | |
948 | if (ret < 0 || ret >= end - pos) | |
949 | return 0; | |
950 | pos += ret; | |
951 | for (i = 16; i < 32; i++) { | |
952 | ret = os_snprintf(pos, end - pos, "%02X", sta_stats->reserved[i]); | |
953 | if (ret < 0 || ret >= end - pos) | |
954 | return 0; | |
955 | pos += ret; | |
956 | ||
957 | if (((i + 1) % 4) == 0) { | |
958 | ret = os_snprintf(pos, end - pos, " "); | |
959 | if (ret < 0 || ret >= end - pos) | |
960 | return 0; | |
961 | pos += ret; | |
962 | } | |
963 | } | |
964 | ret = os_snprintf(pos, end - pos, "\n"); | |
965 | if (ret < 0 || ret >= end - pos) | |
966 | return 0; | |
967 | pos += ret; | |
968 | ||
969 | ret = os_snprintf(pos, end - pos, "====\n"); | |
970 | if (ret < 0 || ret >= end - pos) | |
971 | return 0; | |
972 | pos += ret; | |
973 | ||
974 | return pos - buf; | |
975 | } | |
976 | ||
977 | /* [ALPS00618361] [WFD Quality Enhancement] [changelist 1686130] */ | |
978 | static void format_sta_statistics(struct wpa_driver_sta_statistics_s *s) | |
979 | { | |
980 | wpa_printf(MSG_DEBUG, "NWFD: Basic info* AVG:%4d:EN:%4d:DE:%4d:SEN:%4d:SDE:%4d:HIF:%4d", | |
981 | s->tx_avg_process_time, | |
982 | s->enqueue_total_cnt, | |
983 | s->dequeue_total_cnt, | |
984 | s->enqueue_sta_total_cnt, | |
985 | s->dequeue_sta_total_cnt, | |
986 | s->tx_total_cnt); | |
987 | ||
988 | wpa_printf(MSG_DEBUG, "NWFD: Time info* TTL:%4d:AVG:%4d:MAX:%4d:HIFAVG:%4d:HIFMAX:%4d", | |
989 | s->tx_total_cnt, | |
990 | s->tx_avg_process_time, | |
991 | s->tx_max_process_time, | |
992 | s->tx_avg_hif_process_time, | |
993 | s->tx_max_hif_process_time); | |
994 | ||
995 | wpa_printf(MSG_DEBUG, "NWFD: No TC RES* Score:%4d:EN:%4d#%4d#%4d#%4d:DE:%4d#%4d#%4d#%4d", | |
996 | s->link_score, | |
997 | s->tc_buf_full_cnt[TC0_INDEX], | |
998 | s->tc_buf_full_cnt[TC1_INDEX], | |
999 | s->tc_buf_full_cnt[TC2_INDEX], | |
1000 | s->tc_buf_full_cnt[TC3_INDEX], | |
1001 | s->dequeue_no_tc_res[TC0_INDEX], | |
1002 | s->dequeue_no_tc_res[TC1_INDEX], | |
1003 | s->dequeue_no_tc_res[TC2_INDEX], | |
1004 | s->dequeue_no_tc_res[TC3_INDEX]); | |
1005 | ||
1006 | wpa_printf(MSG_DEBUG, "NWFD: Irq info* T:%4d:P:%4d:TT:%4d:A:%4d:S:%4d:R:%4d:T:%4d", | |
1007 | s->isr_cnt, | |
1008 | s->isr_pass_cnt, | |
1009 | s->isr_task_cnt, | |
1010 | s->isr_ab_cnt, | |
1011 | s->isr_sw_cnt, | |
1012 | s->isr_rx_cnt, | |
1013 | s->isr_tx_cnt); | |
1014 | ||
1015 | /* | |
1016 | * TC resouce information: format: | |
1017 | * 1. how many TC resource wanted during statistics intervals | |
1018 | * 2. how many TC resource acquire successfully | |
1019 | * 3. how many TC resource back during statistics intervals | |
1020 | */ | |
1021 | wpa_printf(MSG_DEBUG, "NWFD: TC Res info[W:U:B]* Score:%4d:" | |
1022 | "#%5d:%5d:%5d#" | |
1023 | "#%5d:%5d:%5d#" | |
1024 | "#%5d:%5d:%5d#" | |
1025 | "#%5d:%5d:%5d#", | |
1026 | s->link_score, | |
1027 | s->tc_wanted_res[TC0_INDEX], | |
1028 | s->tc_used_res[TC0_INDEX], | |
1029 | s->tc_back_count[TC0_INDEX], | |
1030 | ||
1031 | s->tc_wanted_res[TC1_INDEX], | |
1032 | s->tc_used_res[TC1_INDEX], | |
1033 | s->tc_back_count[TC1_INDEX], | |
1034 | ||
1035 | s->tc_wanted_res[TC2_INDEX], | |
1036 | s->tc_used_res[TC2_INDEX], | |
1037 | s->tc_back_count[TC2_INDEX], | |
1038 | ||
1039 | s->tc_wanted_res[TC3_INDEX], | |
1040 | s->tc_used_res[TC3_INDEX], | |
1041 | s->tc_back_count[TC3_INDEX]); | |
1042 | } | |
1043 | ||
1044 | int wpa_driver_get_sta_statistics(struct wpa_supplicant *wpa_s, char *addr, | |
1045 | char *buf, size_t buflen) | |
1046 | { | |
1047 | char *str = NULL; | |
1048 | int len = 0; | |
1049 | u8 sta_addr[ETH_ALEN]; | |
1050 | u8 *mac = NULL; | |
1051 | struct wpa_driver_sta_statistics_s sta_statistics; | |
1052 | ||
1053 | memset(&sta_statistics, 0 ,sizeof(sta_statistics)); | |
1054 | ||
1055 | if (hwaddr_aton(addr, sta_addr)) { | |
1056 | wpa_printf(MSG_DEBUG, "CTRL_IFACE GET_STA_STATISTICS: invalid " | |
1057 | "address '%s'", addr); | |
1058 | return -1; | |
1059 | } | |
1060 | ||
1061 | mac = wpas_p2p_get_sta_mac(wpa_s, sta_addr); | |
1062 | ||
1063 | if (wpas_get_sta_statistics(wpa_s, mac ? mac : sta_addr, | |
1064 | (u8 *)&sta_statistics) < 0) { | |
1065 | wpa_printf(MSG_DEBUG, "CTRL_IFACE GET_STA_STATISTICS: command failed"); | |
1066 | return -1; | |
1067 | } | |
1068 | len = print_sta_statistics(wpa_s, &sta_statistics, 0x00, buf, buflen); | |
1069 | ||
1070 | format_sta_statistics(&sta_statistics); | |
1071 | return len; | |
1072 | } | |
1073 | ||
1074 | #ifdef CONFIG_MTK_P2P_SIGMA | |
1075 | static int wpas_p2p_sigma_test_mode(struct wpa_supplicant *wpa_s, int index, int value) | |
1076 | { | |
1077 | struct wpa_driver_p2p_sigma_params params; | |
1078 | ||
1079 | os_memset(¶ms, 0, sizeof(params)); | |
1080 | ||
1081 | params.hdr.index = 1; | |
1082 | params.hdr.index = params.hdr.index | (0x01 << 24); | |
1083 | params.hdr.buflen = sizeof(struct wpa_driver_p2p_sigma_params); | |
1084 | ||
1085 | params.idx = (u32)index; | |
1086 | params.value = (u32)value; | |
1087 | ||
1088 | return wpa_driver_nl80211_testmode(wpa_s->drv_priv, (u8 *)¶ms, | |
1089 | sizeof(struct wpa_driver_p2p_sigma_params)); | |
1090 | } | |
1091 | ||
1092 | static int p2p_ctrl_iface_set_opps(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) | |
1093 | { | |
1094 | char *str = NULL; | |
1095 | u8 addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | |
1096 | int len = 0; | |
1097 | size_t ssid_len = 0; | |
1098 | char *ssid; | |
1099 | int CTWin; | |
1100 | ||
1101 | wpa_printf(MSG_DEBUG, "CTRL_IFACE set_opps cmd=%s\n", cmd); | |
1102 | ||
1103 | CTWin = atoi(cmd); | |
1104 | ||
1105 | str = os_strchr(cmd, ' '); | |
1106 | if (str) { | |
1107 | *str ++ = '\0'; | |
1108 | ||
1109 | if (hwaddr_aton(str, addr)) | |
1110 | return -1; | |
1111 | } | |
f3fa1980 | 1112 | |
c481cf08 JA |
1113 | str = os_strchr(str, ' '); |
1114 | if (str) { | |
1115 | *str ++ = '\0'; | |
f3fa1980 | 1116 | |
c481cf08 JA |
1117 | ssid = wpa_config_parse_string(str, &ssid_len); |
1118 | if (ssid) { | |
1119 | wpa_printf(MSG_DEBUG, "CTRL_IFACE set_opps CTWin=%d "MACSTR" SSID(%zu)%s\n", | |
1120 | CTWin, MAC2STR(addr), ssid_len, ssid); | |
1121 | os_free(ssid); | |
1122 | } | |
1123 | else { | |
1124 | wpa_printf(MSG_DEBUG, "CTRL_IFACE set_opps CTWin=%d "MACSTR" SSID(%zu)\n", | |
1125 | CTWin, MAC2STR(addr), ssid_len); | |
1126 | } | |
1127 | } | |
1128 | ||
1129 | wpas_p2p_sigma_test_mode(wpa_s, 107, (int)CTWin); | |
1130 | ||
1131 | //len = os_snprintf(buf, buflen, "return OK"); | |
1132 | ||
1133 | return len; | |
1134 | } | |
1135 | ||
1136 | static int p2p_ctrl_iface_set_power_save(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) | |
f3fa1980 | 1137 | { |
c481cf08 JA |
1138 | char *str = NULL; |
1139 | int len = 0; | |
1140 | int value = 0; | |
f3fa1980 | 1141 | |
c481cf08 | 1142 | wpa_printf(MSG_DEBUG, "CTRL_IFACE set_power_save cmd=%s\n", cmd); |
f3fa1980 | 1143 | |
c481cf08 JA |
1144 | value = atoi(cmd); |
1145 | ||
1146 | wpa_printf(MSG_DEBUG, "CTRL_IFACE set_power_save value=%d\n", value); | |
1147 | ||
1148 | wpas_p2p_sigma_test_mode(wpa_s, 108, (int)value); | |
1149 | ||
1150 | //len = os_snprintf(buf, buflen, "return OK"); | |
1151 | ||
1152 | return len; | |
1153 | ||
1154 | } | |
1155 | ||
1156 | static int p2p_ctrl_iface_set_sleep(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) | |
1157 | { | |
1158 | char *str = NULL; | |
1159 | u8 addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | |
1160 | int len = 0; | |
1161 | size_t ssid_len = 0; | |
1162 | char *ssid; | |
1163 | ||
1164 | if (hwaddr_aton(cmd, addr)) | |
f3fa1980 | 1165 | return -1; |
c481cf08 JA |
1166 | |
1167 | str = os_strchr(cmd, ' '); | |
1168 | if (str) { | |
1169 | *str ++ = '\0'; | |
1170 | ||
1171 | ssid = wpa_config_parse_string(str, &ssid_len); | |
1172 | if (ssid) { | |
1173 | wpa_printf(MSG_DEBUG, "CTRL_IFACE set_sleep "MACSTR" SSID(%zu)%s\n", | |
1174 | MAC2STR(addr), ssid_len, ssid); | |
1175 | os_free(ssid); | |
1176 | } | |
1177 | else { | |
1178 | wpa_printf(MSG_DEBUG, "CTRL_IFACE set_sleep "MACSTR" SSID(%zu)\n", | |
1179 | MAC2STR(addr), ssid_len); | |
1180 | } | |
f3fa1980 | 1181 | } |
c481cf08 JA |
1182 | |
1183 | wpas_p2p_sigma_test_mode(wpa_s, 106, 0); | |
1184 | ||
1185 | //len = os_snprintf(buf, buflen, "return OK"); | |
1186 | ||
1187 | return len; | |
1188 | ||
1189 | } | |
1190 | #endif /* CONFIG_MTK_P2P_SIGMA */ | |
1191 | ||
1192 | /* utils for parse cmdline: | |
1193 | * cmd: paramters in cmd line | |
1194 | * argv: paramter vector | |
1195 | * len: cmd lenght | |
1196 | * example: | |
1197 | * cmd = "driver P2P_SET_NOA 1 2 3" | |
1198 | * argv[0] = "driver" | |
1199 | * argv[1] = "P2P_SET_NOA" | |
1200 | * argv[2] = "1" | |
1201 | * argv[3] = "2" | |
1202 | * argv[4] = "3" | |
1203 | */ | |
1204 | ||
1205 | int tokenize_space(char *cmd, char *argv[], int len) | |
1206 | { | |
1207 | char *pos; | |
1208 | char *start; | |
1209 | int argc = 0; | |
1210 | ||
1211 | start = pos = cmd; | |
1212 | for (;;) { | |
1213 | argv[argc] = pos; | |
1214 | argc++; | |
1215 | while (*pos != '\n' && *pos != ' ' && *pos != '\0') { | |
1216 | pos++; | |
1217 | if (pos - start >= len) | |
1218 | break; | |
1219 | } | |
1220 | ||
1221 | if (*pos == '\0') | |
1222 | break; | |
1223 | ||
1224 | if (*pos == '\n' || *pos == ' ') { | |
1225 | *pos++ = '\0'; | |
1226 | if (pos - start >= len) | |
1227 | break; | |
1228 | } | |
f3fa1980 | 1229 | } |
c481cf08 JA |
1230 | |
1231 | return argc; | |
1232 | } | |
1233 | ||
1234 | static int p2p_ctrl_iface_set_noa(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) | |
1235 | { | |
1236 | struct wpa_driver_p2p_noa_params { | |
1237 | struct wpa_driver_test_mode_info hdr; | |
1238 | u32 idx; | |
1239 | u32 value; /* should not be used in this case */ | |
1240 | u32 count; | |
1241 | u32 interval; | |
1242 | u32 duration; | |
1243 | }; | |
1244 | char *argv[64]; | |
1245 | int argc; | |
1246 | struct wpa_driver_p2p_noa_params noa_param; | |
1247 | ||
1248 | os_memset(&noa_param, 0, sizeof(noa_param)); | |
1249 | ||
1250 | /* P2P_SET_NOA 255 100 3 */ | |
1251 | /* | |
1252 | * argv format: | |
1253 | * argv[0] = "P2P_SET_NOA" | |
1254 | * argv[1] = "255" | |
1255 | * argv[2] = "100" | |
1256 | * argv[3] = "3" | |
1257 | */ | |
1258 | argc = tokenize_space(cmd, argv, os_strlen(cmd)); | |
1259 | ||
1260 | if (argc != 4) { | |
1261 | wpa_printf(MSG_DEBUG, "P2P: NOA: invalid cmd format"); | |
1262 | return -1; | |
f3fa1980 | 1263 | } |
c481cf08 JA |
1264 | |
1265 | /* fill in the params structure */ | |
1266 | noa_param.hdr.index = 1; | |
1267 | noa_param.hdr.index = noa_param.hdr.index | (0x01 << 24); | |
1268 | noa_param.hdr.buflen = sizeof(struct wpa_driver_p2p_noa_params); | |
1269 | ||
1270 | noa_param.idx = 4; | |
1271 | noa_param.count = (u32)atoi(argv[1]); | |
1272 | noa_param.interval= (u32)atoi(argv[2]); | |
1273 | noa_param.duration= (u32)atoi(argv[3]); | |
1274 | ||
1275 | wpa_printf(MSG_DEBUG, "P2P: set noa: %d %d %d", | |
1276 | noa_param.count, | |
1277 | noa_param.interval, | |
1278 | noa_param.duration); | |
1279 | ||
1280 | return wpa_driver_nl80211_testmode(wpa_s->drv_priv, (u8 *)&noa_param, | |
1281 | sizeof(struct wpa_driver_p2p_noa_params)); | |
1282 | } | |
1283 | ||
1284 | static int p2p_ctrl_iface_set_ps(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) | |
1285 | { | |
1286 | char *argv[64]; | |
1287 | int argc; | |
1288 | int enable; | |
1289 | s32 ctw; | |
1290 | struct wpa_driver_p2p_sigma_params opps_param; | |
1291 | ||
1292 | os_memset(&opps_param, 0, sizeof(opps_param)); | |
1293 | ||
1294 | /* P2P_SET_PS 2 1 3 | |
1295 | * argv format: | |
1296 | * argv[0] = "P2P_SET_PS" | |
1297 | * argv[1] = "2" | |
1298 | * argv[2] = "1" | |
1299 | * argv[3] = "3" | |
1300 | */ | |
1301 | argc = tokenize_space(cmd, argv, os_strlen(cmd)); | |
1302 | ||
1303 | if (argc != 4) { | |
1304 | wpa_printf(MSG_DEBUG, "P2P: Opps: invalid cmd format"); | |
1305 | return -1; | |
1306 | } | |
1307 | ||
1308 | /* fill in the params structure */ | |
1309 | opps_param.hdr.index = 1; | |
1310 | opps_param.hdr.index = opps_param.hdr.index | (0x01 << 24); | |
1311 | opps_param.hdr.buflen = sizeof(struct wpa_driver_p2p_sigma_params); | |
1312 | ||
1313 | opps_param.idx = 107; | |
1314 | ||
1315 | enable = atoi(argv[2]); | |
1316 | ctw = atoi(argv[3]); | |
1317 | ||
1318 | /* BIT 7 control OPPS on / off */ | |
1319 | if (enable) | |
1320 | ctw |= BIT(7); | |
1321 | ||
1322 | opps_param.value = ctw; | |
1323 | ||
1324 | wpa_printf(MSG_DEBUG, "P2P: set opps: 0x%x", | |
1325 | opps_param.value); | |
1326 | ||
1327 | return wpa_driver_nl80211_testmode(wpa_s->drv_priv, (u8 *)&opps_param, | |
1328 | sizeof(struct wpa_driver_p2p_sigma_params)); | |
1329 | } | |
1330 | ||
1331 | #ifdef CONFIG_MTK_WFD_SINK | |
1332 | static int wpas_wfd_data_update(struct wpa_supplicant *wpa_s, struct wfd_data_s *p_wfd_data) | |
1333 | { | |
1334 | struct wpa_driver_wfd_data_s params; | |
1335 | os_memset(¶ms, 0, sizeof(params)); | |
1336 | ||
1337 | wpa_printf(MSG_DEBUG, "WFD: wpas_wfd_data_update wfd_en %u wfd_dev_info 0x%x wfd_ctrl_port %u wfd_state 0x%x", | |
1338 | p_wfd_data->WfdEnable, p_wfd_data->WfdDevInfo, p_wfd_data->WfdControlPort, p_wfd_data->WfdState); | |
1339 | ||
1340 | ||
1341 | params.hdr.index = 2; | |
1342 | params.hdr.index = params.hdr.index | (0x01 << 24); | |
1343 | params.hdr.buflen = sizeof(struct wfd_data_s); | |
1344 | ||
1345 | params.WfdCmdType = p_wfd_data->WfdCmdType; | |
1346 | params.WfdEnable = p_wfd_data->WfdEnable; | |
1347 | params.WfdCoupleSinkStatus = p_wfd_data->WfdCoupleSinkStatus; | |
1348 | params.WfdDevInfo = p_wfd_data->WfdDevInfo; | |
1349 | params.WfdControlPort = p_wfd_data->WfdControlPort; | |
1350 | params.WfdMaximumTp = p_wfd_data->WfdMaximumTp; | |
1351 | params.WfdExtendCap = p_wfd_data->WfdExtendCap; | |
1352 | os_memcpy(params.WfdCoupleSinkAddress, p_wfd_data->WfdCoupleSinkAddress, ETH_ALEN); | |
1353 | os_memcpy(params.WfdAssociatedBssid, p_wfd_data->WfdAssociatedBssid, ETH_ALEN); | |
1354 | os_memcpy(params.WfdVideoIp, p_wfd_data->WfdVideoIp, sizeof(p_wfd_data->WfdVideoIp)); | |
1355 | os_memcpy(params.WfdAudioIp, p_wfd_data->WfdAudioIp, sizeof(p_wfd_data->WfdAudioIp)); | |
1356 | params.WfdVideoPort = p_wfd_data->WfdVideoPort; | |
1357 | params.WfdAudioPort = p_wfd_data->WfdAudioPort; | |
1358 | params.WfdFlag = p_wfd_data->WfdFlag; | |
1359 | params.WfdPolicy = p_wfd_data->WfdPolicy; | |
1360 | params.WfdState = p_wfd_data->WfdState; | |
1361 | params.WfdSessionInformationIELen = p_wfd_data->WfdSessionInformationIELen; | |
1362 | os_memcpy(params.WfdSessionInformationIE, p_wfd_data->WfdSessionInformationIE, | |
1363 | p_wfd_data->WfdSessionInformationIELen); | |
1364 | os_memcpy(params.WfdPrimarySinkMac, p_wfd_data->WfdPrimarySinkMac, ETH_ALEN); | |
1365 | os_memcpy(params.WfdSecondarySinkMac, p_wfd_data->WfdSecondarySinkMac, ETH_ALEN); | |
1366 | params.WfdAdvancedFlag = p_wfd_data->WfdAdvancedFlag; | |
1367 | ||
1368 | params.WfdSessionAvailable = p_wfd_data->WfdSessionAvailable; | |
1369 | params.WfdSigmaMode = p_wfd_data->WfdSigmaMode; | |
1370 | os_memcpy(params.WfdLocalIp, p_wfd_data->WfdLocalIp, sizeof(p_wfd_data->WfdLocalIp)); | |
1371 | ||
1372 | return wpa_drv_set_test_mode(wpa_s, (u8 *)¶ms, sizeof(struct wpa_driver_wfd_data_s)); | |
1373 | } | |
1374 | ||
1375 | static int p2p_get_capability(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) | |
1376 | { | |
1377 | int ret = 0; | |
1378 | struct p2p_data *p2p = wpa_s->global->p2p; | |
1379 | wpa_printf(MSG_DEBUG, "%s %d, %d", __func__, __LINE__, p2p->dev_capab); | |
1380 | if (os_strncmp(cmd, "p2p_dev_capa", os_strlen("p2p_dev_capa")) == 0) { | |
1381 | ret = snprintf(buf, buflen, "p2p_dev_capa=%d\n", p2p->dev_capab); | |
1382 | wpa_printf(MSG_DEBUG, "%s %d %d, %s", __func__, __LINE__, p2p->dev_capab, buf); | |
1383 | } else if (os_strncmp(cmd, "p2p_group_capa", os_strlen("p2p_group_capa")) == 0) { | |
1384 | wpa_printf(MSG_DEBUG, "%s not implement", __func__); | |
1385 | ret = -1; | |
1386 | } | |
1387 | return ret; | |
1388 | } | |
1389 | ||
1390 | static int p2p_set_capability(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) | |
1391 | { | |
1392 | int ret = 0; | |
1393 | wpa_printf(MSG_DEBUG, "%s %d", __func__, __LINE__); | |
1394 | struct p2p_data *p2p = wpa_s->global->p2p; | |
1395 | if (os_strncmp(cmd, "p2p_dev_capa ", os_strlen("p2p_dev_capa ")) == 0) { | |
1396 | int old_cap = p2p->dev_capab; | |
1397 | int dev_cap = atoi(cmd + os_strlen("p2p_dev_capa ")); | |
1398 | p2p->dev_capab = dev_cap & 0xff; | |
1399 | wpa_printf(MSG_DEBUG, "%s %d %d, %d", __func__, __LINE__, p2p->dev_capab, | |
1400 | old_cap); | |
1401 | } else if (os_strncmp(cmd, "p2p_group_capa ", os_strlen("p2p_group_capa ")) == 0) { | |
1402 | wpa_printf(MSG_DEBUG, "%s group not implement", __func__); | |
1403 | ret = -1; | |
1404 | } | |
1405 | return ret; | |
1406 | } | |
1407 | ||
1408 | /** | |
1409 | * priv_p2p_freq_to_channel - Convert frequency into channel info | |
1410 | * @op_class: Buffer for returning operating class | |
1411 | * @channel: Buffer for returning channel number | |
1412 | * Returns: 0 on success, -1 if the specified frequency is unknown | |
1413 | */ | |
1414 | static int priv_p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel) | |
1415 | { | |
1416 | /* TODO: more operating classes */ | |
1417 | if (freq >= 2412 && freq <= 2472) { | |
1418 | if ((freq - 2407) % 5) | |
1419 | return -1; | |
1420 | ||
1421 | *op_class = 81; /* 2.407 GHz, channels 1..13 */ | |
1422 | *channel = (freq - 2407) / 5; | |
1423 | return 0; | |
1424 | } | |
1425 | ||
1426 | if (freq == 2484) { | |
1427 | *op_class = 82; /* channel 14 */ | |
1428 | *channel = 14; | |
1429 | return 0; | |
1430 | } | |
1431 | ||
1432 | if (freq >= 5180 && freq <= 5240) { | |
1433 | if ((freq - 5000) % 5) | |
1434 | return -1; | |
1435 | ||
1436 | *op_class = 115; /* 5 GHz, channels 36..48 */ | |
1437 | *channel = (freq - 5000) / 5; | |
1438 | return 0; | |
1439 | } | |
1440 | ||
1441 | if (freq >= 5260 && freq <= 5320) { | |
1442 | *op_class = 118; /* 5 GHz, channels 52..64 */ | |
1443 | *channel = (freq - 5000) / 5; | |
1444 | return 0; | |
1445 | } | |
1446 | ||
1447 | if (freq >= 5500 && freq <= 5700) { | |
1448 | *op_class = 121; /* 5 GHz, channels 100..140 */ | |
1449 | *channel = (freq - 5000) / 5; | |
1450 | return 0; | |
1451 | } | |
1452 | ||
1453 | if (freq >= 5745 && freq <= 5805) { | |
1454 | if ((freq - 5000) % 5) | |
1455 | return -1; | |
1456 | ||
1457 | *op_class = 124; /* 5 GHz, channels 149..161 */ | |
1458 | *channel = (freq - 5000) / 5; | |
f3fa1980 S |
1459 | return 0; |
1460 | } | |
1461 | ||
c481cf08 JA |
1462 | if (freq >= 5825 && freq <= 5845) { |
1463 | *op_class = 125; /* 5 GHz, channels 149,153,157,161,165,169 */ | |
1464 | *channel = (freq - 5000) / 5; | |
1465 | return 0; | |
1466 | } | |
1467 | ||
1468 | return -1; | |
f3fa1980 S |
1469 | } |
1470 | ||
c481cf08 | 1471 | static int p2p_wfd_sink_config_scc(struct wpa_supplicant *wpa_s, int scc, unsigned int oper_freq) |
f3fa1980 | 1472 | { |
c481cf08 JA |
1473 | int ret = 0; |
1474 | u8 op_reg_class = 0, op_channel = 0; | |
1475 | unsigned int r; | |
1476 | struct wpa_supplicant *iface; | |
1477 | struct p2p_data *p2p = wpa_s->global->p2p; | |
1478 | wpa_printf(MSG_DEBUG, "%s %d", __func__, __LINE__); | |
1479 | if (!p2p) { | |
1480 | wpa_printf(MSG_DEBUG, "Not support p2p."); | |
1481 | return ret; | |
1482 | } | |
1483 | if (scc && oper_freq) { | |
1484 | priv_p2p_freq_to_channel(oper_freq, &op_reg_class, &op_channel); | |
1485 | p2p->op_channel = op_channel; | |
1486 | p2p->op_reg_class = op_reg_class; | |
1487 | p2p->channels.reg_classes = 1; | |
1488 | p2p->channels.reg_class[0].channels = 1; | |
1489 | p2p->channels.reg_class[0].reg_class = op_reg_class; | |
1490 | p2p->channels.reg_class[0].channel[0] = op_channel; | |
1491 | wpa_printf(MSG_DEBUG, "Enable SCC in WFD sink mode class %d, channel %d", | |
1492 | op_reg_class, op_channel); | |
1493 | return ret; | |
1494 | } | |
1495 | /* Get back to MCC */ | |
1496 | wpa_printf(MSG_DEBUG, "Config MCC"); | |
1497 | if (wpa_s->conf->p2p_oper_reg_class && | |
1498 | wpa_s->conf->p2p_oper_channel) { | |
1499 | p2p->op_reg_class = wpa_s->conf->p2p_oper_reg_class; | |
1500 | p2p->op_channel = wpa_s->conf->p2p_oper_channel; | |
1501 | p2p->cfg->cfg_op_channel = 1; | |
1502 | } else { | |
1503 | p2p->op_reg_class = 81; | |
1504 | os_get_random((u8 *)&r, sizeof(r)); | |
1505 | p2p->op_channel = 1 + (r % 3) * 5; | |
1506 | p2p->cfg->cfg_op_channel = 0; | |
1507 | } | |
f3fa1980 | 1508 | |
c481cf08 JA |
1509 | os_memcpy(&p2p->channels, &p2p->cfg->channels, sizeof(struct p2p_channels)); |
1510 | return ret; | |
1511 | } | |
1512 | ||
1513 | ||
1514 | static int mtk_get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s, | |
1515 | struct wpa_used_freq_data *freqs_data, | |
1516 | unsigned int len) | |
1517 | { | |
1518 | struct wpa_supplicant *ifs; | |
1519 | u8 bssid[ETH_ALEN]; | |
1520 | int freq; | |
1521 | unsigned int idx = 0, i; | |
1522 | ||
1523 | wpa_dbg(wpa_s, MSG_DEBUG, | |
1524 | "Determining shared radio frequencies (max len %u)", len); | |
1525 | os_memset(freqs_data, 0, sizeof(struct wpa_used_freq_data) * len); | |
1526 | ||
1527 | dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant, | |
1528 | radio_list) { | |
1529 | wpa_printf(MSG_DEBUG, "Get shared freqs ifname %s", ifs->ifname); | |
1530 | if (idx == len) | |
1531 | break; | |
1532 | ||
1533 | if (ifs->current_ssid == NULL || ifs->assoc_freq == 0) | |
1534 | continue; | |
1535 | ||
1536 | if (ifs->current_ssid->mode == WPAS_MODE_AP || | |
1537 | ifs->current_ssid->mode == WPAS_MODE_P2P_GO) | |
1538 | freq = ifs->current_ssid->frequency; | |
1539 | else if (wpa_drv_get_bssid(ifs, bssid) == 0) | |
1540 | freq = ifs->assoc_freq; | |
1541 | else | |
1542 | continue; | |
1543 | ||
1544 | /* Hold only distinct freqs */ | |
1545 | for (i = 0; i < idx; i++) | |
1546 | if (freqs_data[i].freq == freq) | |
1547 | break; | |
1548 | ||
1549 | if (i == idx) | |
1550 | freqs_data[idx++].freq = freq; | |
1551 | ||
1552 | if (ifs->current_ssid->mode == WPAS_MODE_INFRA) { | |
1553 | freqs_data[i].flags = ifs->current_ssid->p2p_group ? | |
1554 | WPA_FREQ_USED_BY_P2P_CLIENT : | |
1555 | WPA_FREQ_USED_BY_INFRA_STATION; | |
1556 | } | |
f3fa1980 | 1557 | } |
c481cf08 JA |
1558 | |
1559 | return idx; | |
1560 | } | |
1561 | ||
1562 | ||
1563 | static int mtk_get_shared_radio_freqs(struct wpa_supplicant *wpa_s, | |
1564 | int *freq_array, unsigned int len) | |
1565 | { | |
1566 | struct wpa_used_freq_data *freqs_data; | |
1567 | int num, i; | |
1568 | ||
1569 | os_memset(freq_array, 0, sizeof(int) * len); | |
1570 | ||
1571 | freqs_data = os_calloc(len, sizeof(struct wpa_used_freq_data)); | |
1572 | if (!freqs_data) | |
1573 | return -1; | |
1574 | ||
1575 | num = mtk_get_shared_radio_freqs_data(wpa_s, freqs_data, len); | |
1576 | for (i = 0; i < num; i++) | |
1577 | freq_array[i] = freqs_data[i].freq; | |
1578 | ||
1579 | os_free(freqs_data); | |
1580 | ||
1581 | return num; | |
f3fa1980 | 1582 | } |
c481cf08 | 1583 | #endif |
f3fa1980 S |
1584 | |
1585 | int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, | |
1586 | size_t buf_len ) | |
1587 | { | |
1588 | struct i802_bss *bss = priv; | |
1589 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
1590 | struct ifreq ifr; | |
c481cf08 | 1591 | android_wifi_priv_cmd priv_cmd; |
f3fa1980 S |
1592 | struct wpa_supplicant *wpa_s; |
1593 | struct hostapd_data *hapd; | |
1594 | int handled = 0; | |
1595 | int cmd_len = 0; | |
1596 | union wpa_event_data event; | |
1597 | static int user_force_band = 0; | |
1598 | int ret = -1; | |
1599 | ||
1600 | if (drv == NULL) { | |
c481cf08 | 1601 | wpa_printf(MSG_ERROR, "%s: drv is NULL, exit", __func__); |
f3fa1980 S |
1602 | return -1; |
1603 | } | |
1604 | if (drv->ctx == NULL) { | |
c481cf08 | 1605 | wpa_printf(MSG_ERROR, "%s: drv->ctx is NULL, exit", __func__); |
f3fa1980 S |
1606 | return -1; |
1607 | } | |
1608 | ||
c481cf08 | 1609 | if (bss->drv->nlmode == NL80211_IFTYPE_AP) { |
f3fa1980 S |
1610 | hapd = (struct hostapd_data *)(drv->ctx); |
1611 | } | |
1612 | else { | |
1613 | wpa_s = (struct wpa_supplicant *)(drv->ctx); | |
1614 | if (wpa_s->conf == NULL) { | |
c481cf08 | 1615 | wpa_printf(MSG_ERROR, "%s: wpa_s->conf is NULL, exit", __func__); |
f3fa1980 S |
1616 | return -1; |
1617 | } | |
1618 | } | |
1619 | ||
c481cf08 | 1620 | wpa_printf(MSG_INFO, "%s: %s recv cmd %s", __func__, bss->ifname, cmd); |
f3fa1980 S |
1621 | handled = 1; |
1622 | ||
1623 | if (os_strncasecmp(cmd, "POWERMODE ", 10) == 0) { | |
1624 | int state; | |
1625 | state = atoi(cmd + 10); | |
1626 | wpa_printf(MSG_DEBUG, "POWERMODE=%d", state); | |
c481cf08 JA |
1627 | } else if (os_strncasecmp(cmd, "GET_STA_STATISTICS ", 19) == 0) { |
1628 | ret = wpa_driver_get_sta_statistics(wpa_s, cmd + 19, buf, buf_len); | |
f3fa1980 S |
1629 | } else if (os_strncmp(cmd, "MACADDR", os_strlen("MACADDR")) == 0) { |
1630 | u8 macaddr[ETH_ALEN] = {}; | |
1631 | os_memcpy(&macaddr, wpa_s->own_addr, ETH_ALEN); | |
1632 | ret = snprintf(buf, buf_len, "Macaddr = " MACSTR "\n", MAC2STR(macaddr)); | |
1633 | wpa_printf(MSG_DEBUG, "%s", buf); | |
c481cf08 | 1634 | } else if(os_strncasecmp(cmd, "COUNTRY", os_strlen("COUNTRY")) == 0) { |
f3fa1980 S |
1635 | if (os_strlen(cmd) != os_strlen("COUNTRY") + 3) { |
1636 | wpa_printf(MSG_DEBUG, "Ignore COUNTRY cmd %s", cmd); | |
1637 | ret = 0; | |
1638 | } else { | |
c481cf08 JA |
1639 | wpa_printf(MSG_INFO, "Set country: %s", cmd + 8); |
1640 | // ret = wpa_drv_set_country(wpa_s, cmd + 8); | |
1641 | ret = wpa_driver_mediatek_set_country(priv, cmd + 8); | |
f3fa1980 S |
1642 | if (ret == 0) { |
1643 | wpa_printf(MSG_DEBUG, "Update channel list after country code changed"); | |
c481cf08 | 1644 | wpa_driver_notify_country_change(wpa_s->global, cmd); |
f3fa1980 S |
1645 | } |
1646 | } | |
1647 | } else if (os_strcasecmp(cmd, "start") == 0) { | |
c481cf08 JA |
1648 | if ((ret = linux_set_iface_flags(drv->global->ioctl_sock, |
1649 | drv->first_bss->ifname, 1))) { | |
f3fa1980 S |
1650 | wpa_printf(MSG_INFO, "nl80211: Could not set interface UP, ret=%d \n", ret); |
1651 | } else { | |
1652 | wpa_msg(drv->ctx, MSG_INFO, "CTRL-EVENT-DRIVER-STATE STARTED"); | |
1653 | } | |
1654 | } else if (os_strcasecmp(cmd, "stop") == 0) { | |
1655 | if (drv->associated) { | |
1656 | ret = wpa_drv_deauthenticate(wpa_s, drv->bssid, WLAN_REASON_DEAUTH_LEAVING); | |
1657 | if (ret != 0) | |
1658 | wpa_printf(MSG_DEBUG, "DRIVER-STOP error, ret=%d", ret); | |
1659 | } else { | |
1660 | wpa_printf(MSG_INFO, "nl80211: not associated, no need to deauthenticate \n"); | |
1661 | } | |
1662 | ||
c481cf08 JA |
1663 | if ((ret = linux_set_iface_flags(drv->global->ioctl_sock, |
1664 | drv->first_bss->ifname, 0))) { | |
f3fa1980 S |
1665 | wpa_printf(MSG_INFO, "nl80211: Could not set interface Down, ret=%d \n", ret); |
1666 | } else { | |
1667 | wpa_msg(drv->ctx, MSG_INFO, "CTRL-EVENT-DRIVER-STATE STOPPED"); | |
1668 | } | |
1669 | } else if (os_strncasecmp(cmd, "getpower", 8) == 0) { | |
c481cf08 | 1670 | u32 mode = 0; |
f3fa1980 S |
1671 | // ret = wpa_driver_wext_driver_get_power(drv, &mode); |
1672 | if (ret == 0) { | |
1673 | ret = snprintf(buf, buf_len, "powermode = %u\n", mode); | |
1674 | wpa_printf(MSG_DEBUG, "%s", buf); | |
1675 | if (ret < (int)buf_len) | |
1676 | return ret; | |
1677 | } | |
c481cf08 JA |
1678 | } else if (os_strncasecmp(cmd, "rxfilter-add", 12) == 0) { |
1679 | u32 sw_cmd = 0x9F000000; | |
1680 | u32 idx = 0; | |
1681 | char *cp = cmd + 12; | |
1682 | char *endp; | |
1683 | ||
1684 | if (*cp != '\0') { | |
1685 | idx = (u32)strtol(cp, &endp, 0); | |
1686 | if (endp != cp) { | |
1687 | idx += 0x00900200; | |
1688 | wpa_driver_nl80211_driver_sw_cmd(priv, 1, &sw_cmd, &idx); | |
1689 | ret = 0; | |
1690 | } | |
f3fa1980 | 1691 | } |
c481cf08 JA |
1692 | } else if (os_strncasecmp(cmd, "rxfilter-remove", 15) == 0) { |
1693 | u32 sw_cmd = 0x9F000000; | |
1694 | u32 idx = 0; | |
1695 | char *cp = cmd + 15; | |
f3fa1980 | 1696 | char *endp; |
c481cf08 | 1697 | |
f3fa1980 | 1698 | if (*cp != '\0') { |
c481cf08 JA |
1699 | idx = (u32)strtol(cp, &endp, 0); |
1700 | if (endp != cp) { | |
1701 | idx += 0x00900300; | |
1702 | wpa_driver_nl80211_driver_sw_cmd(priv, 1, &sw_cmd, &idx); | |
1703 | ret = 0; | |
1704 | } | |
f3fa1980 | 1705 | } |
c481cf08 JA |
1706 | } else if (os_strncasecmp(cmd, "rxfilter-stop", 13) == 0) { |
1707 | u32 sw_cmd = 0x9F000000; | |
1708 | u32 idx = 0x00900000; | |
1709 | wpa_driver_nl80211_driver_sw_cmd(priv, 1, &sw_cmd, &idx); | |
1710 | ret = 0; | |
1711 | } else if (os_strncasecmp(cmd, "rxfilter-start", 14) == 0) { | |
1712 | u32 sw_cmd = 0x9F000000; | |
1713 | u32 idx = 0x00900100; | |
1714 | wpa_driver_nl80211_driver_sw_cmd(priv, 1, &sw_cmd, &idx); | |
1715 | ret = 0; | |
f3fa1980 S |
1716 | } else if (os_strcasecmp(cmd, "btcoexscan-start") == 0) { |
1717 | ret = 0; /* mt5921 linux driver not implement yet */ | |
1718 | } else if (os_strcasecmp(cmd, "btcoexscan-stop") == 0) { | |
1719 | ret = 0; /* mt5921 linux driver not implement yet */ | |
1720 | } else if (os_strncasecmp(cmd, "btcoexmode", 10) == 0) { | |
1721 | ret = 0; /* mt5921 linux driver not implement yet */ | |
c481cf08 JA |
1722 | #ifdef CONFIG_HOTSPOT_MGR_SUPPORT |
1723 | } else if (os_strncmp(cmd, "STA-BLOCK ", 10) == 0) { | |
1724 | if (wpa_driver_sta_block(priv, cmd + 10)) { | |
1725 | ret = -1; | |
1726 | } else { | |
1727 | ret = 0; | |
1728 | } | |
1729 | } else if (os_strncmp(cmd, "STA-UNBLOCK ", 12) == 0) { | |
1730 | if (wpa_driver_sta_unblock(priv, cmd + 12)) { | |
1731 | ret = -1; | |
1732 | } else { | |
1733 | ret = 0; | |
1734 | } | |
1735 | } else if (os_strncasecmp(cmd, "set_max_client ", 15) == 0) { | |
1736 | wpa_driver_set_max_client(priv, cmd + 15, buf, buf_len); | |
1737 | #endif /* CONFIG_HOTSPOT_MGR_SUPPORT */ | |
1738 | #ifdef CONFIG_MTK_LTE_COEX | |
1739 | } else if (os_strncmp(cmd, "MTK-ACS", 7) == 0) { | |
1740 | u8 ch = wpa_driver_do_mtk_acs(priv); | |
1741 | os_memcpy(buf, &ch, sizeof(u8)); | |
1742 | ret = sizeof(u8); | |
1743 | #endif /* CONFIG_MTK_LTE_COEX */ | |
1744 | #ifdef CONFIG_WAPI_SUPPORT | |
1745 | } else if (os_strncasecmp(cmd, "set-wapi-key", 12) == 0) { | |
1746 | struct wapi_key_param_type { | |
1747 | u8 *addr; | |
1748 | int key_idx; | |
1749 | int set_tx; | |
1750 | u8 *seq; | |
1751 | size_t seq_len; | |
1752 | u8 *key; | |
1753 | size_t key_len; | |
1754 | } *wapi_key_param; | |
1755 | wapi_key_param = (struct wapi_key_param_type*)buf; | |
1756 | ||
1757 | ret = wpa_driver_nl80211_set_wapi_key(priv, (const u8*)wapi_key_param->addr, | |
1758 | wapi_key_param->key_idx, wapi_key_param->set_tx, | |
1759 | (const u8*)wapi_key_param->seq, wapi_key_param->seq_len, | |
1760 | (const u8*)wapi_key_param->key, wapi_key_param->key_len); | |
1761 | } else if (os_strncasecmp(cmd, "wapi-msg-send", 13) == 0) { | |
1762 | struct wapi_msg_send_param_type { | |
1763 | u8 *msg_in; | |
1764 | int msg_in_len; | |
1765 | u8 *msg_out; | |
1766 | int *msg_out_len; | |
1767 | } *wapi_msg_send_param; | |
1768 | wapi_msg_send_param = (struct wapi_msg_send_param_type*)buf; | |
1769 | ret = wpa_driver_nl80211_send_msg(priv, (const u8*)wapi_msg_send_param->msg_in, | |
1770 | wapi_msg_send_param->msg_in_len, wapi_msg_send_param->msg_out, | |
1771 | wapi_msg_send_param->msg_out_len); | |
1772 | #endif /* CONFIG_WAPI_SUPPORT */ | |
1773 | #ifdef CONFIG_MTK_WFD_SINK | |
1774 | } else if (os_strncmp(cmd, "p2p_get_cap ", os_strlen("p2p_get_cap ")) == 0) { | |
1775 | struct p2p_data *p2p = wpa_s->global->p2p; | |
1776 | if (p2p) { | |
1777 | wpa_printf(MSG_DEBUG, "%s %d, %d ", | |
1778 | __func__, __LINE__, p2p->dev_capab); | |
1779 | ret = p2p_get_capability(wpa_s, cmd + os_strlen("p2p_get_cap "), | |
1780 | buf, buf_len); | |
1781 | } | |
1782 | } else if (os_strncmp(cmd, "p2p_set_cap ", os_strlen("p2p_set_cap ")) == 0) { | |
1783 | struct p2p_data *p2p = wpa_s->global->p2p; | |
1784 | if (p2p) { | |
1785 | wpa_printf(MSG_DEBUG, "%s %d", __func__, __LINE__); | |
1786 | ret = p2p_set_capability(wpa_s, cmd + os_strlen("p2p_set_cap "), | |
1787 | buf, buf_len); | |
1788 | } | |
1789 | } else if (os_strncmp(cmd, "MIRACAST ", os_strlen("MIRACAST ")) == 0) { | |
1790 | unsigned char miracast = atoi(cmd + os_strlen("MIRACAST ")); | |
1791 | char *pos = os_strstr(cmd, " freq="); | |
1792 | unsigned int freq = 0; | |
1793 | int num; | |
1794 | wpa_printf(MSG_DEBUG, "MIRACAST %d", miracast); | |
1795 | switch (miracast) { | |
1796 | case 0: | |
1797 | case 1: | |
1798 | num = mtk_get_shared_radio_freqs(wpa_s, &freq, 1); | |
1799 | if (num > 0 && freq > 0) { | |
1800 | wpa_printf(MSG_DEBUG, "AIS connected %d", freq); | |
1801 | p2p_wfd_sink_config_scc(wpa_s, 1, freq); | |
1802 | } else | |
1803 | p2p_wfd_sink_config_scc(wpa_s, 0, 0); | |
1804 | handled = 0; /* DRIVER MIRACAST used as private cmd*/ | |
1805 | break; | |
1806 | case 2: | |
1807 | if (pos) { | |
1808 | pos += 6; | |
1809 | freq = atoi(pos); | |
1810 | wpa_printf(MSG_DEBUG, "MIRACAST freq %d", freq); | |
1811 | p2p_wfd_sink_config_scc(wpa_s, 1, freq); | |
1812 | /* rebuild DRIVER MIRACAST 2 cmd */ | |
1813 | os_memset(cmd, 0, os_strlen(cmd)); | |
1814 | os_memcpy(cmd, "MIRACAST 2", os_strlen("MIRACAST 2")); | |
1815 | } else { | |
1816 | num = mtk_get_shared_radio_freqs(wpa_s, &freq, 1); | |
1817 | if (num > 0 && freq > 0) { | |
1818 | wpa_printf(MSG_DEBUG, "AIS connected %d", freq); | |
1819 | p2p_wfd_sink_config_scc(wpa_s, 1, freq); | |
1820 | } else | |
1821 | p2p_wfd_sink_config_scc(wpa_s, 0, 0); | |
1822 | } | |
1823 | ||
1824 | handled = 0; /* DRIVER MIRACAST used as private cmd*/ | |
1825 | ||
1826 | break; | |
1827 | default: | |
1828 | wpa_printf(MSG_DEBUG, "Unknown MIRACAST value %d", miracast); | |
1829 | handled = 0; /* DRIVER MIRACAST used as private cmd*/ | |
1830 | break; | |
1831 | } | |
1832 | } else if (os_strncasecmp(cmd, "p2p_use_mcc=", os_strlen("p2p_use_mcc=")) == 0) { | |
1833 | unsigned char use_mcc = atoi(cmd + os_strlen("p2p_use_mcc=")); | |
1834 | wpa_printf(MSG_DEBUG, "p2p_use_mcc %d", use_mcc); | |
1835 | // MCC/SCC should be determined by GO negotation | |
1836 | // wpa_s->global->p2p->p2p_use_mcc = use_mcc; | |
1837 | if (use_mcc) { | |
1838 | wpa_printf(MSG_DEBUG, "SCC_MCC, config MCC"); | |
1839 | p2p_wfd_sink_config_scc(wpa_s, 0, 0); | |
1840 | } else { | |
1841 | int shared_freq; | |
1842 | int num = 0; | |
1843 | wpa_printf(MSG_DEBUG, "use_mcc=0"); | |
1844 | num = mtk_get_shared_radio_freqs(wpa_s, &shared_freq, 1); | |
1845 | if (num > 0 && shared_freq > 0) { | |
1846 | wpa_printf(MSG_DEBUG, "p2p disconnected, AIS connected %d", shared_freq); | |
1847 | p2p_wfd_sink_config_scc(wpa_s, 1, shared_freq); | |
1848 | } else | |
1849 | p2p_wfd_sink_config_scc(wpa_s, 0, 0); | |
1850 | } | |
1851 | } else if (os_strncmp(cmd, "wfd_data_update", os_strlen("wfd_data_update")) == 0) { | |
1852 | wpa_printf(MSG_DEBUG, "CONFIG_MTK_P2P: Update wfd_data"); | |
1853 | ret = wpas_wfd_data_update(wpa_s, (struct wfd_data_s *)buf); | |
1854 | #endif | |
1855 | #ifdef CONFIG_MTK_P2P_SIGMA | |
1856 | } else if (os_strncasecmp(cmd, "mcc", 3) == 0) { | |
1857 | if (wpa_s->drv_priv) { | |
1858 | int mcc = 0; | |
1859 | char *value = NULL; | |
1860 | value = os_strchr(cmd, ' '); | |
1861 | if (value == NULL) | |
1862 | return -1; | |
1863 | *value++ = '\0'; | |
1864 | struct wpa_supplicant *_wpa_s; | |
1865 | mcc = atoi(value); | |
1866 | if (mcc) { | |
1867 | for (_wpa_s = wpa_s->global->ifaces; _wpa_s; _wpa_s = _wpa_s->next) { | |
1868 | ||
1869 | /* | |
1870 | * 2 is appropriate? | |
1871 | * just legacy wifi vs p2p wifi? | |
1872 | */ | |
1873 | _wpa_s->num_multichan_concurrent = 2; | |
1874 | _wpa_s->drv_flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; | |
1875 | if (_wpa_s->global->p2p && _wpa_s->global->p2p->cfg) | |
1876 | _wpa_s->global->p2p->cfg->concurrent_operations = 1; | |
1877 | } | |
1878 | } else { | |
1879 | for (_wpa_s = wpa_s->global->ifaces; _wpa_s; _wpa_s = _wpa_s->next) { | |
1880 | ||
1881 | /* | |
1882 | * assign as 0 beacause our driver will | |
1883 | * not report iface_combination to supplicant | |
1884 | */ | |
1885 | _wpa_s->num_multichan_concurrent = 0; | |
1886 | _wpa_s->drv_flags &= ~WPA_DRIVER_FLAGS_P2P_CONCURRENT; | |
1887 | if (_wpa_s->global->p2p && _wpa_s->global->p2p->cfg) | |
1888 | _wpa_s->global->p2p->cfg->concurrent_operations = 0; | |
1889 | } | |
1890 | } | |
1891 | ||
1892 | wpa_printf(MSG_DEBUG, "mcc = %d", mcc); | |
1893 | ret = 0; | |
1894 | } | |
1895 | } else if (os_strncmp(cmd, "p2p_set_opps ", 13) == 0) { | |
1896 | ret = p2p_ctrl_iface_set_opps(wpa_s, cmd + 13, buf, buf_len); | |
1897 | } else if (os_strncmp(cmd, "p2p_set_power_save ", 19) == 0) { | |
1898 | ret = p2p_ctrl_iface_set_power_save(wpa_s, cmd + 19, buf, buf_len); | |
1899 | } else if (os_strncmp(cmd, "p2p_set_sleep ", 14) == 0) { | |
1900 | ret = p2p_ctrl_iface_set_sleep(wpa_s, cmd + 14, buf, buf_len); | |
1901 | } else if (os_strncmp(cmd, "p2p_set_sleep", 13) == 0) { | |
1902 | char cmd2[] = {"ff:ff:ff:ff:ff:ff \"\""}; | |
1903 | ret = p2p_ctrl_iface_set_sleep(wpa_s, cmd2, buf, buf_len); | |
1904 | } else if (os_strncasecmp(cmd, "sigma_mode", 10) == 0) { | |
1905 | int sigma = 0; | |
1906 | char *value = NULL; | |
1907 | value = os_strchr(cmd, ' '); | |
1908 | if (value == NULL) | |
1909 | return -1; | |
1910 | *value++ = '\0'; | |
1911 | sigma = atoi(value); | |
1912 | wpa_printf(MSG_DEBUG, "p2p: sigma: set mode %d", sigma); | |
1913 | // we should not have workaround for sigma programs | |
1914 | // wpa_s->global->p2p->sigma_mode = sigma; | |
1915 | ret = 0; | |
1916 | #endif /* CONFIG_MTK_P2P_SIGMA */ | |
1917 | } else if (os_strncmp(cmd, "P2P_SET_NOA", os_strlen("P2P_SET_NOA")) == 0) { | |
1918 | ret = p2p_ctrl_iface_set_noa(wpa_s, cmd, buf, buf_len); | |
1919 | } else if (os_strncmp(cmd, "P2P_SET_PS", os_strlen("P2P_SET_PS")) == 0) { | |
1920 | ret = p2p_ctrl_iface_set_ps(wpa_s, cmd, buf, buf_len); | |
1921 | } else if (os_strncasecmp(cmd, "SETSUSPENDMODE ", 15) == 0) { | |
1922 | struct wpa_driver_suspendmode_params params; | |
1923 | params.hdr.index = NL80211_TESTMODE_SUSPEND; | |
1924 | params.hdr.index = params.hdr.index | (0x01 << 24); | |
1925 | params.hdr.buflen = sizeof(params); | |
1926 | params.suspend = *(cmd+15)-'0'; | |
1927 | wpa_driver_nl80211_testmode(priv, (u8* )¶ms, sizeof(params)); | |
1928 | handled = 0; /* 6630 driver handled this command in driver, so give a chance to 6630 driver */ | |
1929 | }else if(os_strncasecmp(cmd, "mtk_rx_packet_filter ", 21) == 0) { | |
1930 | char buf[9] = {0}, *errChar = NULL; | |
1931 | char *pos = NULL; | |
1932 | /* mtk_rx_packet_filter 00000000000000FE 0000000000000000 0000000000000000 */ | |
1933 | struct wpa_driver_rx_filter_params params; | |
1934 | params.hdr.index = NL80211_TESTMODE_RXFILTER; | |
1935 | params.hdr.index = params.hdr.index | (0x01 << 24); | |
1936 | params.hdr.buflen = sizeof(params); | |
1937 | ||
1938 | pos = cmd; | |
1939 | pos = pos + 21; | |
1940 | if (pos == NULL || strlen(cmd) != 71 ) { | |
1941 | wpa_printf(MSG_DEBUG, "[mtk_rx_packet_filter] Error! \n"); | |
1942 | return -1; | |
1943 | } | |
1944 | ||
1945 | os_memcpy(buf,pos,8); | |
1946 | buf[8] = '\0'; | |
1947 | params.Ipv4FilterHigh = strtol(buf,&errChar,16); | |
1948 | wpa_printf(MSG_DEBUG, "[mtk_rx_packet_filter]params.Ipv4FilterHigh (0x%08x),errChar [%p]\n", params.Ipv4FilterHigh,errChar); | |
1949 | ||
1950 | pos = pos + 8; | |
1951 | os_memcpy(buf,pos,8); | |
1952 | buf[8] = '\0'; | |
1953 | params.Ipv4FilterLow = strtol(buf,&errChar,16); | |
1954 | wpa_printf(MSG_DEBUG, "[mtk_rx_packet_filter]params.Ipv4FilterLow (0x%08x),errChar [%p]\n", params.Ipv4FilterLow,errChar); | |
1955 | ||
1956 | pos = pos + 9; | |
1957 | os_memcpy(buf,pos,8); | |
1958 | buf[8] = '\0'; | |
1959 | params.Ipv6FilterHigh = strtol(buf,&errChar,16); | |
1960 | wpa_printf(MSG_DEBUG, "[mtk_rx_packet_filter]params.Ipv6FilterHigh (0x%08x),errChar [%p]\n", params.Ipv6FilterHigh,errChar); | |
1961 | ||
1962 | pos = pos + 8; | |
1963 | os_memcpy(buf,pos,8); | |
1964 | buf[8] = '\0'; | |
1965 | params.Ipv6FilterLow = strtol(buf,&errChar,16); | |
1966 | wpa_printf(MSG_DEBUG, "[mtk_rx_packet_filter]params.Ipv6FilterLow (0x%08x),errChar [%p]\n", params.Ipv6FilterLow,errChar); | |
1967 | ||
1968 | pos = pos + 9; | |
1969 | os_memcpy(buf,pos,8); | |
1970 | buf[8] = '\0'; | |
1971 | params.SnapFilterHigh = strtol(buf,&errChar,16); | |
1972 | wpa_printf(MSG_DEBUG, "[mtk_rx_packet_filter]params.SnapFilterHigh (0x%08x),errChar [%p]\n", params.SnapFilterHigh,errChar); | |
1973 | ||
1974 | pos = pos + 8; | |
1975 | os_memcpy(buf,pos,8); | |
1976 | buf[8] = '\0'; | |
1977 | params.SnapFilterLow = strtol(buf,&errChar,16); | |
1978 | wpa_printf(MSG_DEBUG, "[mtk_rx_packet_filter]params.SnapFilterLow (0x%08x),errChar [%p]\n", params.SnapFilterLow,errChar); | |
1979 | ||
1980 | ret = wpa_driver_nl80211_testmode(priv, (u8 *)¶ms, sizeof(params)); | |
f3fa1980 | 1981 | } else { |
c481cf08 JA |
1982 | u8 buffer[100]; |
1983 | struct wpa_driver_test_mode_info *params = (struct wpa_driver_test_mode_info *)buffer; | |
1984 | params->index = NL80211_TESTMODE_STR_CMD | (0x01 << 24); | |
1985 | params->buflen = sizeof(*params) + strlen(cmd); | |
1986 | strncpy((char*)(params+1), cmd, sizeof(buffer)-sizeof(*params)); | |
1987 | ret = wpa_driver_nl80211_testmode(priv, buffer, params->buflen); | |
f3fa1980 | 1988 | handled = 0; |
c481cf08 | 1989 | wpa_printf(MSG_INFO, "Transparent command for driver nl80211, ret=%d", ret); |
f3fa1980 S |
1990 | } |
1991 | ||
c481cf08 JA |
1992 | if (handled == 0) { |
1993 | cmd_len = strlen(cmd); | |
1994 | ||
1995 | memset(&ifr, 0, sizeof(ifr)); | |
1996 | memset(&priv_cmd, 0, sizeof(priv_cmd)); | |
1997 | memset(buf, 0, buf_len); | |
1998 | strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); | |
1999 | ifr.ifr_name[IFNAMSIZ - 1] = '\0'; | |
2000 | ||
2001 | if (cmd_len >= PRIV_CMD_SIZE) { | |
2002 | wpa_printf(MSG_INFO, "%s: cmd: %s overflow", | |
2003 | __func__, cmd); | |
2004 | cmd_len = PRIV_CMD_SIZE - 1; | |
2005 | } | |
2006 | ||
2007 | memcpy(priv_cmd.buf, cmd, cmd_len + 1); | |
2008 | priv_cmd.used_len = cmd_len + 1; | |
2009 | priv_cmd.total_len = PRIV_CMD_SIZE; | |
2010 | ifr.ifr_data = &priv_cmd; | |
2011 | ||
2012 | ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); | |
2013 | if (ret < 0) { | |
2014 | wpa_printf(MSG_ERROR, "%s: failed to issue private commands," | |
2015 | " error msg: %s\n", __func__, strerror(errno)); | |
2016 | wpa_driver_send_hang_msg(drv); | |
2017 | ret = snprintf(buf, buf_len, "%s\n", "FAIL"); | |
2018 | } else { | |
2019 | ||
2020 | wpa_printf(MSG_INFO, "%s: ret = %d used = %u total = %u", | |
2021 | __func__, ret , priv_cmd.used_len, priv_cmd.total_len); | |
2022 | ||
2023 | drv_errors = 0; | |
2024 | ret = 0; | |
2025 | if ((os_strncasecmp(cmd, "WLS_BATCHING", 12) == 0)) | |
2026 | ret = strlen(buf); | |
2027 | /* | |
2028 | * There no need to call wpa_supplicant_event func | |
2029 | * on which the cmd is SETBAND | |
2030 | */ | |
2031 | if (os_strncasecmp(cmd, "SETBAND", 7) == 0) { | |
2032 | /* | |
2033 | * wpa_supplicant_event(drv->ctx, | |
2034 | * EVENT_CHANNEL_LIST_CHANGED, NULL); | |
2035 | */ | |
2036 | wpa_printf(MSG_INFO, "%s: Unsupported command SETBAND\n", __func__); | |
2037 | } | |
2038 | } | |
2039 | } /* handled == 0 */ | |
2040 | ||
f3fa1980 S |
2041 | return ret; |
2042 | } | |
2043 | ||
2044 | int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration) | |
2045 | { | |
c481cf08 | 2046 | char buf[MAX_DRV_CMD_SIZE]; |
f3fa1980 S |
2047 | struct i802_bss *bss = priv; |
2048 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
2049 | ||
c481cf08 JA |
2050 | wpa_printf(MSG_DEBUG, "iface %s P2P_SET_NOA %d %d %d", bss->ifname, count, start, duration); |
2051 | snprintf(buf, sizeof(buf), "P2P_SET_NOA %d %d %d", count, start, duration); | |
2052 | return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf)+1); | |
f3fa1980 S |
2053 | } |
2054 | ||
2055 | int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len) | |
2056 | { | |
2057 | struct i802_bss *bss = priv; | |
2058 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
2059 | ||
2060 | wpa_printf(MSG_DEBUG, "iface %s P2P_GET_NOA, ignored", bss->ifname); | |
2061 | return -1; | |
2062 | } | |
2063 | ||
2064 | int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow) | |
2065 | { | |
c481cf08 | 2066 | char buf[MAX_DRV_CMD_SIZE]; |
f3fa1980 S |
2067 | struct i802_bss *bss = priv; |
2068 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
2069 | ||
c481cf08 JA |
2070 | wpa_printf(MSG_DEBUG, "iface %s P2P_SET_PS %d %d %d", bss->ifname, legacy_ps, opp_ps, ctwindow); |
2071 | snprintf(buf, sizeof(buf), "P2P_SET_PS %d %d %d", legacy_ps, opp_ps, ctwindow); | |
2072 | return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf)+1); | |
f3fa1980 S |
2073 | } |
2074 | ||
2075 | int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon, | |
2076 | const struct wpabuf *proberesp, | |
2077 | const struct wpabuf *assocresp) | |
2078 | { | |
2079 | struct i802_bss *bss = priv; | |
2080 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
2081 | ||
2082 | wpa_printf(MSG_DEBUG, "iface %s set_ap_wps_p2p_ie, ignored", bss->ifname); | |
2083 | return 0; | |
2084 | } | |
2085 |