1 /** @file moal_main.c
2 *
3 * @brief This file contains the major functions in WLAN
4 * driver.
5 *
6 *
7 * Copyright 2008-2022 NXP
8 *
9 * This software file (the File) is distributed by NXP
10 * under the terms of the GNU General Public License Version 2, June 1991
11 * (the License). You may use, redistribute and/or modify the File in
12 * accordance with the terms and conditions of the License, a copy of which
13 * is available by writing to the Free Software Foundation, Inc.,
14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
15 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
16 *
17 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
19 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
20 * this warranty disclaimer.
21 *
22 */
23
24 /********************************************************
25 Change log:
26 10/21/2008: initial version
27 ********************************************************/
28
29 #include "moal_main.h"
30 #ifdef USB
31 #include "moal_usb.h"
32 #endif
33 #ifdef SDIO
34 #include "moal_sdio.h"
35 #endif
36 #ifdef PCIE
37 #include "moal_pcie.h"
38 #endif
39 #ifdef UAP_SUPPORT
40 #include "moal_uap.h"
41 #endif
42 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
43 #include "moal_cfg80211.h"
44 #include "moal_cfg80211_util.h"
45 #endif
46 #ifdef STA_CFG80211
47 #ifdef STA_SUPPORT
48 #include "moal_sta_cfg80211.h"
49 #endif
50 #endif
51 #ifdef UAP_CFG80211
52 #ifdef UAP_SUPPORT
53 #include "moal_uap_cfg80211.h"
54 #endif
55 #endif
56 #include "moal_eth_ioctl.h"
57
58 #include <linux/if_ether.h>
59 #include <linux/in.h>
60 #include <linux/tcp.h>
61 #include <net/tcp.h>
62 #include <net/dsfield.h>
63 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
64 #include <linux/mpls.h>
65 #endif
66 #include <linux/if_vlan.h>
67
68 #ifdef CONFIG_OF
69 #include <linux/of.h>
70 #endif
71
72 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
73 #if IS_ENABLED(CONFIG_IPV6)
74 #include <net/addrconf.h>
75 #endif
76 #endif
77
78 /********************************************************
79 Global Variables
80 ********************************************************/
81 /** the pointer of new fwdump fname for each dump**/
82 static char *fwdump_fname;
83 /** Semaphore for add/remove card */
84 struct semaphore AddRemoveCardSem;
85 /**
86 * The global variable of a pointer to moal_handle
87 * structure variable
88 **/
89 moal_handle *m_handle[MAX_MLAN_ADAPTER];
90 static int reg_work;
91 /********************************************************
92 Local Variables
93 ********************************************************/
94
95 #ifdef SD8801
96 static struct _card_info card_info_SD8801 = {
97 .embedded_supp = 0,
98 .drcs = 0,
99 .go_noa = 0,
100 .v14_fw_api = 1,
101 .v16_fw_api = 0,
102 .v17_fw_api = 0,
103 .pmic = 0,
104 .cal_data_cfg = 0,
105 .low_power_enable = 1,
106 .rx_rate_max = 76,
107 .histogram_table_num = 1,
108 .feature_control = FEATURE_CTRL_DEFAULT & (~FEATURE_CTRL_STREAM_2X2),
109 .fw_name = SD8801_DEFAULT_WLAN_FW_NAME,
110 .fw_name_wlan = SD8801_DEFAULT_WLAN_FW_NAME,
111 #ifdef SDIO
112 .dump_fw_info = 0,
113 .dump_fw_ctrl_reg = 0x63,
114 .dump_fw_start_reg = 0x64,
115 .dump_fw_end_reg = 0x6A,
116 .dump_fw_host_ready = 0xee,
117 .dump_reg.reg_table = {0x28, 0x30, 0x34, 0x38, 0x3c},
118 .dump_reg.reg_table_size = 5,
119 .scratch_reg = 0x60,
120 .func1_reg_start = 0x10,
121 .func1_reg_end = 0x17,
122 .fw_reset_reg = 0x64,
123 .fw_reset_val = 0,
124 .slew_rate_reg = 0x8000231C,
125 .slew_rate_bit_offset = 14,
126 #endif
127 .sniffer_support = 1,
128 .per_pkt_cfg_support = 0,
129 };
130 #endif
131 #ifdef SD8887
132 static struct _card_info card_info_SD8887 = {
133 .embedded_supp = 1,
134 .drcs = 1,
135 .go_noa = 1,
136 .v16_fw_api = 0,
137 .pmic = 0,
138 .cal_data_cfg = 1,
139 .low_power_enable = 1,
140 .rx_rate_max = 196,
141 .histogram_table_num = 3,
142 .feature_control = FEATURE_CTRL_DEFAULT & (~FEATURE_CTRL_STREAM_2X2),
143 .rev_id_reg = 0xc8,
144 .fw_name = SD8887_DEFAULT_COMBO_FW_NAME,
145 .fw_name_wlan = SD8887_DEFAULT_WLAN_FW_NAME,
146 #ifdef SDIO
147 .dump_fw_info = DUMP_FW_SDIO_V2,
148 .dump_fw_ctrl_reg = 0xa2,
149 .dump_fw_start_reg = 0xa3,
150 .dump_fw_end_reg = 0xaa,
151 .dump_fw_host_ready = 0xee,
152 .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
153 0x65, 0x66, 0x68, 0x69, 0x6a},
154 .dump_reg.reg_table_size = 13,
155 .scratch_reg = 0x90,
156 .func1_reg_start = 0x10,
157 .func1_reg_end = 0x17,
158 .fw_reset_reg = 0x0B6,
159 .fw_reset_val = 1,
160 .slew_rate_reg = 0x80002328,
161 .slew_rate_bit_offset = 12,
162 #endif
163 .sniffer_support = 0,
164 .per_pkt_cfg_support = 0,
165 };
166 #endif
167
168 #ifdef SD8897
169 static struct _card_info card_info_SD8897 = {
170 .embedded_supp = 1,
171 .drcs = 1,
172 .go_noa = 1,
173 .v16_fw_api = 0,
174 .pmic = 0,
175 .cal_data_cfg = 0,
176 .low_power_enable = 0,
177 .rx_rate_max = 196,
178 .histogram_table_num = 1,
179 .feature_control = FEATURE_CTRL_DEFAULT,
180 .rev_id_reg = 0xbc,
181 .fw_name = SD8897_DEFAULT_COMBO_FW_NAME,
182 .fw_name_wlan = SD8897_DEFAULT_WLAN_FW_NAME,
183 #ifdef SDIO
184 .dump_fw_info = DUMP_FW_SDIO_V2,
185 .dump_fw_ctrl_reg = 0xe2,
186 .dump_fw_start_reg = 0xe3,
187 .dump_fw_end_reg = 0xea,
188 .dump_fw_host_ready = 0xee,
189 .dump_reg.reg_table = {0x4C, 0x50, 0x54, 0x55, 0x58, 0x59, 0x5c, 0x5d},
190 .dump_reg.reg_table_size = 8,
191 .scratch_reg = 0xc0,
192 .func1_reg_start = 0x04,
193 .func1_reg_end = 0x0b,
194 .fw_reset_reg = 0x0E8,
195 .fw_reset_val = 1,
196 .slew_rate_reg = 0x80002328,
197 .slew_rate_bit_offset = 12,
198 #endif
199 .sniffer_support = 0,
200 .per_pkt_cfg_support = 0,
201 };
202 #endif
203
204 #ifdef PCIE8897
205 static struct _card_info card_info_PCIE8897 = {
206 .embedded_supp = 1,
207 .drcs = 1,
208 .go_noa = 1,
209 .v16_fw_api = 0,
210 .pmic = 0,
211 .cal_data_cfg = 0,
212 .low_power_enable = 0,
213 .rx_rate_max = 196,
214 .histogram_table_num = 1,
215 .feature_control = FEATURE_CTRL_DEFAULT,
216 .rev_id_reg = 0x0c58,
217 .fw_name = PCIE8897_DEFAULT_COMBO_FW_NAME,
218 .fw_name_wlan = PCIE8897_DEFAULT_WLAN_FW_NAME,
219 .sniffer_support = 0,
220 .per_pkt_cfg_support = 0,
221 };
222 #endif
223
224 #ifdef USB8897
225 static struct _card_info card_info_USB8897 = {
226 .embedded_supp = 1,
227 .drcs = 1,
228 .go_noa = 1,
229 .v16_fw_api = 0,
230 .pmic = 0,
231 .cal_data_cfg = 0,
232 .low_power_enable = 0,
233 .rx_rate_max = 196,
234 .histogram_table_num = 1,
235 .feature_control = FEATURE_CTRL_DEFAULT,
236 .fw_name = USB8897_DEFAULT_COMBO_FW_NAME,
237 .fw_name_wlan = USB8897_DEFAULT_WLAN_FW_NAME,
238 .sniffer_support = 0,
239 .per_pkt_cfg_support = 0,
240 };
241 #endif
242
243 #ifdef SD8977
244 static struct _card_info card_info_SD8977 = {
245 .embedded_supp = 1,
246 .drcs = 1,
247 .go_noa = 1,
248 .v16_fw_api = 1,
249 .pmic = 1,
250 .cal_data_cfg = 1,
251 .low_power_enable = 0,
252 .rx_rate_max = 76,
253 .histogram_table_num = 1,
254 .feature_control = FEATURE_CTRL_DEFAULT & (~FEATURE_CTRL_STREAM_2X2),
255 .rev_id_reg = 0xc8,
256 .host_strap_reg = 0xf4,
257 .magic_reg = 0xf0,
258 .fw_name = SD8977_DEFAULT_COMBO_FW_NAME,
259 .fw_name_wlan = SD8977_DEFAULT_WLAN_FW_NAME,
260 #ifdef SDIO
261 .dump_fw_info = DUMP_FW_SDIO_V3,
262 .dump_fw_ctrl_reg = 0xf9,
263 .dump_fw_start_reg = 0xf1,
264 .dump_fw_end_reg = 0xf8,
265 .dump_fw_host_ready = 0xcc,
266 .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
267 0x65, 0x66, 0x68, 0x69, 0x6a},
268 .dump_reg.reg_table_size = 13,
269 .scratch_reg = 0xe8,
270 .func1_reg_start = 0x10,
271 .func1_reg_end = 0x17,
272 .fw_reset_reg = 0x0EE,
273 .fw_reset_val = 0x99,
274 .slew_rate_reg = 0x80002328,
275 .slew_rate_bit_offset = 12,
276 #endif
277 .sniffer_support = 1,
278 .per_pkt_cfg_support = 1,
279 };
280 #endif
281
282 #ifdef SD8978
283 static struct _card_info card_info_SD8978 = {
284 .embedded_supp = 1,
285 .drcs = 1,
286 .go_noa = 1,
287 .v16_fw_api = 1,
288 .pmic = 1,
289 .cal_data_cfg = 1,
290 .low_power_enable = 0,
291 .rx_rate_max = 76,
292 .histogram_table_num = 1,
293 .feature_control = FEATURE_CTRL_DEFAULT & (~FEATURE_CTRL_STREAM_2X2),
294 .rev_id_reg = 0xc8,
295 .host_strap_reg = 0xf4,
296 .magic_reg = 0xf0,
297 .fw_name = SD8978_DEFAULT_COMBO_FW_NAME,
298 .fw_name_wlan = SD8978_DEFAULT_WLAN_FW_NAME,
299 #ifdef SDIO
300 .dump_fw_info = DUMP_FW_SDIO_V3,
301 .dump_fw_ctrl_reg = 0xf9,
302 .dump_fw_start_reg = 0xf1,
303 .dump_fw_end_reg = 0xf8,
304 .dump_fw_host_ready = 0xcc,
305 .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
306 0x65, 0x66, 0x68, 0x69, 0x6a},
307 .dump_reg.reg_table_size = 13,
308 .scratch_reg = 0xe8,
309 .func1_reg_start = 0x10,
310 .func1_reg_end = 0x17,
311 .fw_reset_reg = 0x0EE,
312 .fw_reset_val = 0x99,
313 .slew_rate_reg = 0x80002328,
314 .slew_rate_bit_offset = 12,
315 #endif
316 .sniffer_support = 1,
317 .per_pkt_cfg_support = 1,
318 };
319 #endif
320
321 #ifdef SD8997
322 static struct _card_info card_info_SD8997 = {
323 .embedded_supp = 1,
324 .drcs = 1,
325 .go_noa = 1,
326 .v16_fw_api = 1,
327 .pmic = 1,
328 .cal_data_cfg = 1,
329 .low_power_enable = 0,
330 .rx_rate_max = 196,
331 .histogram_table_num = 3,
332 .feature_control = FEATURE_CTRL_DEFAULT,
333 .rev_id_reg = 0xc8,
334 .host_strap_reg = 0xf4,
335 .magic_reg = 0xf0,
336 .fw_name = SD8997_DEFAULT_COMBO_FW_NAME,
337 .fw_name_wlan = SD8997_DEFAULT_WLAN_FW_NAME,
338 #ifdef SDIO
339 .dump_fw_info = DUMP_FW_SDIO_V3,
340 .dump_fw_ctrl_reg = 0xf9,
341 .dump_fw_start_reg = 0xf1,
342 .dump_fw_end_reg = 0xf8,
343 .dump_fw_host_ready = 0xcc,
344 .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
345 0x65, 0x66, 0x68, 0x69, 0x6a},
346 .dump_reg.reg_table_size = 13,
347 .scratch_reg = 0xe8,
348 .func1_reg_start = 0x10,
349 .func1_reg_end = 0x17,
350 .fw_reset_reg = 0x0EE,
351 .fw_reset_val = 0x99,
352 .slew_rate_reg = 0x80002328,
353 .slew_rate_bit_offset = 12,
354 #endif
355 .sniffer_support = 1,
356 .per_pkt_cfg_support = 1,
357 };
358 #endif
359
360 #ifdef SD9098
361 static struct _card_info card_info_SD9098 = {
362 .embedded_supp = 1,
363 .drcs = 1,
364 .go_noa = 1,
365 .v16_fw_api = 1,
366 .v17_fw_api = 1,
367 .pmic = 1,
368 .cal_data_cfg = 0,
369 .low_power_enable = 0,
370 .rx_rate_max = 412,
371 .histogram_table_num = 3,
372 .feature_control = FEATURE_CTRL_DEFAULT,
373 .rev_id_reg = 0xc8,
374 .host_strap_reg = 0xf4,
375 .magic_reg = 0xf0,
376 .fw_name = SD9098_DEFAULT_COMBO_FW_NAME,
377 .fw_name_wlan = SD9098_DEFAULT_WLAN_FW_NAME,
378 #ifdef SDIO
379 .dump_fw_info = DUMP_FW_SDIO_V3,
380 .dump_fw_ctrl_reg = 0xf9,
381 .dump_fw_start_reg = 0xf1,
382 .dump_fw_end_reg = 0xf8,
383 .dump_fw_host_ready = 0xcc,
384 .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
385 0x65, 0x66, 0x68, 0x69, 0x6a},
386 .dump_reg.reg_table_size = 13,
387 .scratch_reg = 0xe8,
388 .func1_reg_start = 0x10,
389 .func1_reg_end = 0x17,
390 .fw_reset_reg = 0x0EE,
391 .fw_reset_val = 0x99,
392 .slew_rate_reg = 0x90002328,
393 .slew_rate_bit_offset = 12,
394 #endif
395 .sniffer_support = 1,
396 .per_pkt_cfg_support = 1,
397 };
398 #endif
399
400 #ifdef SD9097
401 static struct _card_info card_info_SD9097 = {
402 .embedded_supp = 1,
403 .drcs = 1,
404 .go_noa = 1,
405 .v16_fw_api = 1,
406 .v17_fw_api = 1,
407 .pmic = 1,
408 .cal_data_cfg = 0,
409 .low_power_enable = 0,
410 .rx_rate_max = 412,
411 .histogram_table_num = 3,
412 .feature_control = FEATURE_CTRL_DEFAULT,
413 .rev_id_reg = 0xc8,
414 .host_strap_reg = 0xf4,
415 .magic_reg = 0xf0,
416 .fw_name = SD9097_DEFAULT_COMBO_FW_NAME,
417 .fw_name_wlan = SD9097_DEFAULT_WLAN_FW_NAME,
418 #ifdef SDIO
419 .dump_fw_info = DUMP_FW_SDIO_V3,
420 .dump_fw_ctrl_reg = 0xf9,
421 .dump_fw_start_reg = 0xf1,
422 .dump_fw_end_reg = 0xf8,
423 .dump_fw_host_ready = 0xcc,
424 .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
425 0x65, 0x66, 0x68, 0x69, 0x6a},
426 .dump_reg.reg_table_size = 13,
427 .scratch_reg = 0xe8,
428 .func1_reg_start = 0x10,
429 .func1_reg_end = 0x17,
430 .fw_reset_reg = 0x0EE,
431 .fw_reset_val = 0x99,
432 .slew_rate_reg = 0x90002328,
433 .slew_rate_bit_offset = 12,
434 #endif
435 .sniffer_support = 1,
436 .per_pkt_cfg_support = 1,
437 };
438 #endif
439
440 #ifdef SDNW62X
441 static struct _card_info card_info_SDNW62X = {
442 .embedded_supp = 1,
443 .drcs = 1,
444 .go_noa = 1,
445 .v16_fw_api = 1,
446 .v17_fw_api = 1,
447 .pmic = 1,
448 .cal_data_cfg = 0,
449 .low_power_enable = 0,
450 .rx_rate_max = 412,
451 .histogram_table_num = 3,
452 .feature_control = FEATURE_CTRL_DEFAULT,
453 .rev_id_reg = 0xc8,
454 .host_strap_reg = 0xf4,
455 .magic_reg = 0xf0,
456 .fw_name = SDNW62X_DEFAULT_COMBO_FW_NAME,
457 .fw_name_wlan = SDNW62X_DEFAULT_WLAN_FW_NAME,
458 #ifdef SDIO
459 .dump_fw_info = DUMP_FW_SDIO_V3,
460 .dump_fw_ctrl_reg = 0xf9,
461 .dump_fw_start_reg = 0xf1,
462 .dump_fw_end_reg = 0xf8,
463 .dump_fw_host_ready = 0xcc,
464 .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
465 0x65, 0x66, 0x68, 0x69, 0x6a},
466 .dump_reg.reg_table_size = 13,
467 .scratch_reg = 0xe8,
468 .func1_reg_start = 0x10,
469 .func1_reg_end = 0x17,
470 .fw_reset_reg = 0x0EE,
471 .fw_reset_val = 0x99,
472 .slew_rate_reg = 0x90002328,
473 .slew_rate_bit_offset = 12,
474 #endif
475 .sniffer_support = 1,
476 .per_pkt_cfg_support = 1,
477 };
478 #endif
479
480 #ifdef SD9177
481 static struct _card_info card_info_SD9177 = {
482 .embedded_supp = 1,
483 .drcs = 1,
484 .go_noa = 1,
485 .v16_fw_api = 1,
486 .v17_fw_api = 1,
487 .pmic = 1,
488 .cal_data_cfg = 0,
489 .low_power_enable = 0,
490 .rx_rate_max = 412,
491 .histogram_table_num = 3,
492 .feature_control = FEATURE_CTRL_DEFAULT & (~FEATURE_CTRL_STREAM_2X2),
493 .rev_id_reg = 0xc8,
494 .host_strap_reg = 0xf4,
495 .magic_reg = 0xf0,
496 .fw_name = SD9177_DEFAULT_COMBO_FW_NAME,
497 .fw_name_wlan = SD9177_DEFAULT_WLAN_FW_NAME,
498 #ifdef SDIO
499 .dump_fw_info = DUMP_FW_SDIO_V3,
500 .dump_fw_ctrl_reg = 0xf9,
501 .dump_fw_start_reg = 0xf1,
502 .dump_fw_end_reg = 0xf8,
503 .dump_fw_host_ready = 0xcc,
504 .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
505 0x65, 0x66, 0x68, 0x69, 0x6a},
506 .dump_reg.reg_table_size = 13,
507 .scratch_reg = 0xe8,
508 .func1_reg_start = 0x10,
509 .func1_reg_end = 0x17,
510 .fw_reset_reg = 0x0EE,
511 .fw_reset_val = 0x99,
512 .slew_rate_reg = 0x90002328,
513 .slew_rate_bit_offset = 12,
514 #endif
515 .sniffer_support = 1,
516 .per_pkt_cfg_support = 1,
517 };
518 #endif
519
520 #ifdef PCIE8997
521 static struct _card_info card_info_PCIE8997 = {
522 .embedded_supp = 1,
523 .drcs = 1,
524 .go_noa = 1,
525 .v16_fw_api = 1,
526 .pmic = 1,
527 .cal_data_cfg = 1,
528 .low_power_enable = 0,
529 .rx_rate_max = 196,
530 .histogram_table_num = 3,
531 .feature_control = FEATURE_CTRL_DEFAULT,
532 .rev_id_reg = 0x8,
533 .host_strap_reg = 0x0cd0,
534 .magic_reg = 0x0cd4,
535 .fw_name = PCIE8997_DEFAULT_COMBO_FW_NAME,
536 .fw_name_wlan = PCIE8997_DEFAULT_WLAN_FW_NAME,
537 .sniffer_support = 1,
538 .per_pkt_cfg_support = 1,
539 };
540 #endif
541
542 #ifdef PCIE9097
543 static struct _card_info card_info_PCIE9097 = {
544 .embedded_supp = 1,
545 .drcs = 1,
546 .go_noa = 1,
547 .v16_fw_api = 1,
548 .v17_fw_api = 1,
549 .pmic = 1,
550 .cal_data_cfg = 0,
551 .low_power_enable = 0,
552 .rx_rate_max = 412,
553 .histogram_table_num = 3,
554 .feature_control = FEATURE_CTRL_DEFAULT,
555 .rev_id_reg = 0x8,
556 .host_strap_reg = 0x1c70,
557 .magic_reg = 0x1c74,
558 .fw_name = PCIE9097_DEFAULT_COMBO_FW_NAME,
559 .fw_name_wlan = PCIE9097_DEFAULT_WLAN_FW_NAME,
560 .sniffer_support = 1,
561 .per_pkt_cfg_support = 1,
562 };
563 #endif
564
565 #ifdef PCIE9098
566 static struct _card_info card_info_PCIE9098 = {
567 .embedded_supp = 1,
568 .drcs = 1,
569 .go_noa = 1,
570 .v16_fw_api = 1,
571 .v17_fw_api = 1,
572 .pmic = 1,
573 .cal_data_cfg = 0,
574 .low_power_enable = 0,
575 .rx_rate_max = 412,
576 .histogram_table_num = 3,
577 .feature_control = FEATURE_CTRL_DEFAULT,
578 .rev_id_reg = 0x8,
579 .host_strap_reg = 0x1c70,
580 .magic_reg = 0x1c74,
581 .fw_name = PCIE9098_DEFAULT_COMBO_FW_NAME,
582 .fw_name_wlan = PCIE9098_DEFAULT_WLAN_FW_NAME,
583 .sniffer_support = 1,
584 .per_pkt_cfg_support = 1,
585 };
586 #endif
587
588 #ifdef PCIENW62X
589 static struct _card_info card_info_PCIENW62X = {
590 .embedded_supp = 1,
591 .drcs = 1,
592 .go_noa = 1,
593 .v16_fw_api = 1,
594 .v17_fw_api = 1,
595 .pmic = 1,
596 .cal_data_cfg = 0,
597 .low_power_enable = 0,
598 .rx_rate_max = 412,
599 .histogram_table_num = 3,
600 .feature_control = FEATURE_CTRL_DEFAULT,
601 .rev_id_reg = 0x8,
602 .host_strap_reg = 0x1c70,
603 .magic_reg = 0x1c74,
604 .fw_name = PCIENW62X_DEFAULT_COMBO_FW_NAME,
605 .fw_name_wlan = PCIENW62X_DEFAULT_WLAN_FW_NAME,
606 .sniffer_support = 1,
607 .per_pkt_cfg_support = 1,
608 };
609 #endif
610
611 #ifdef USB8801
612 static struct _card_info card_info_USB8801 = {
613 .embedded_supp = 0,
614 .drcs = 0,
615 .go_noa = 0,
616 .v14_fw_api = 1,
617 .v16_fw_api = 0,
618 .v17_fw_api = 0,
619 .pmic = 0,
620 .cal_data_cfg = 0,
621 .low_power_enable = 1,
622 .rx_rate_max = 76,
623 .feature_control = FEATURE_CTRL_DEFAULT & (~FEATURE_CTRL_STREAM_2X2),
624 .histogram_table_num = 1,
625 .fw_name = USB8801_DEFAULT_WLAN_FW_NAME,
626 .fw_name_wlan = USB8801_DEFAULT_WLAN_FW_NAME,
627 .sniffer_support = 1,
628 .per_pkt_cfg_support = 0,
629 };
630 #endif
631
632 #ifdef USB8978
633 static struct _card_info card_info_USB8978 = {
634 .embedded_supp = 1,
635 .drcs = 1,
636 .go_noa = 1,
637 .v16_fw_api = 1,
638 .pmic = 1,
639 .cal_data_cfg = 1,
640 .low_power_enable = 0,
641 .rx_rate_max = 76,
642 .feature_control = FEATURE_CTRL_DEFAULT & (~FEATURE_CTRL_STREAM_2X2),
643 .histogram_table_num = 1,
644 .fw_name = USB8978_DEFAULT_COMBO_FW_NAME,
645 .fw_name_wlan = USB8978_DEFAULT_WLAN_FW_NAME,
646 .sniffer_support = 1,
647 .per_pkt_cfg_support = 1,
648 };
649 #endif
650
651 #ifdef USB8997
652 static struct _card_info card_info_USB8997 = {
653 .embedded_supp = 1,
654 .drcs = 1,
655 .go_noa = 1,
656 .v16_fw_api = 1,
657 .pmic = 1,
658 .cal_data_cfg = 1,
659 .low_power_enable = 0,
660 .rx_rate_max = 196,
661 .feature_control = FEATURE_CTRL_DEFAULT,
662 .histogram_table_num = 3,
663 .fw_name = USB8997_DEFAULT_COMBO_FW_NAME,
664 .fw_name_wlan = USB8997_DEFAULT_WLAN_FW_NAME,
665 .sniffer_support = 1,
666 .per_pkt_cfg_support = 1,
667 };
668 #endif
669
670 #ifdef USB9098
671 static struct _card_info card_info_USB9098 = {
672 .embedded_supp = 1,
673 .drcs = 1,
674 .go_noa = 1,
675 .v16_fw_api = 1,
676 .v17_fw_api = 1,
677 .pmic = 1,
678 .cal_data_cfg = 0,
679 .low_power_enable = 0,
680 .rx_rate_max = 412,
681 .feature_control = FEATURE_CTRL_DEFAULT,
682 .histogram_table_num = 3,
683 .fw_name = USB9098_DEFAULT_COMBO_FW_NAME,
684 .fw_name_wlan = USB9098_DEFAULT_WLAN_FW_NAME,
685 .sniffer_support = 1,
686 .per_pkt_cfg_support = 1,
687 };
688 #endif
689
690 #ifdef USB9097
691 static struct _card_info card_info_USB9097 = {
692 .embedded_supp = 1,
693 .drcs = 1,
694 .go_noa = 1,
695 .v16_fw_api = 1,
696 .v17_fw_api = 1,
697 .pmic = 1,
698 .cal_data_cfg = 0,
699 .low_power_enable = 0,
700 .rx_rate_max = 412,
701 .feature_control = FEATURE_CTRL_DEFAULT,
702 .histogram_table_num = 3,
703 .fw_name = USBUSB9097_COMBO_V1_FW_NAME,
704 .fw_name_wlan = USB9097_WLAN_V1_FW_NAME,
705 .sniffer_support = 1,
706 .per_pkt_cfg_support = 1,
707 };
708 #endif
709
710 #ifdef USBNW62X
711 static struct _card_info card_info_USBNW62X = {
712 .embedded_supp = 1,
713 .drcs = 1,
714 .go_noa = 1,
715 .v16_fw_api = 1,
716 .v17_fw_api = 1,
717 .pmic = 1,
718 .cal_data_cfg = 0,
719 .low_power_enable = 0,
720 .rx_rate_max = 412,
721 .feature_control = FEATURE_CTRL_DEFAULT,
722 .histogram_table_num = 3,
723 .fw_name = USBNW62X_DEFAULT_COMBO_FW_NAME,
724 .fw_name_wlan = USBNW62X_DEFAULT_WLAN_FW_NAME,
725 .sniffer_support = 1,
726 .per_pkt_cfg_support = 1,
727 };
728 #endif
729
730 #ifdef SD8987
731 static struct _card_info card_info_SD8987 = {
732 .embedded_supp = 1,
733 .drcs = 1,
734 .go_noa = 0,
735 .v16_fw_api = 1,
736 .pmic = 1,
737 .cal_data_cfg = 1,
738 .low_power_enable = 1,
739 .rx_rate_max = 196,
740 .feature_control = FEATURE_CTRL_DEFAULT & (~FEATURE_CTRL_STREAM_2X2),
741 .host_strap_reg = 0xf4,
742 .magic_reg = 0xf0,
743 .histogram_table_num = 3,
744 .fw_name = SD8987_DEFAULT_COMBO_FW_NAME,
745 .fw_name_wlan = SD8987_DEFAULT_WLAN_FW_NAME,
746 #ifdef SDIO
747 .dump_fw_info = DUMP_FW_SDIO_V3,
748 .dump_fw_ctrl_reg = 0xf9,
749 .dump_fw_start_reg = 0xf1,
750 .dump_fw_end_reg = 0xf8,
751 .dump_fw_host_ready = 0xcc,
752 .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
753 0x65, 0x66, 0x68, 0x69, 0x6a},
754 .dump_reg.reg_table_size = 13,
755 .scratch_reg = 0xe8,
756 .func1_reg_start = 0x10,
757 .func1_reg_end = 0x17,
758 .fw_reset_reg = 0x0EE,
759 .fw_reset_val = 0x99,
760 .slew_rate_reg = 0x80002328,
761 .slew_rate_bit_offset = 12,
762 #endif
763 .sniffer_support = 1,
764 .per_pkt_cfg_support = 1,
765 };
766 #endif
767
768 /** Driver version */
769 char driver_version[] =
770 INTF_CARDTYPE KERN_VERSION "--" MLAN_RELEASE_VERSION "-GPL"
771 "-("
772 "FP" FPNUM ")"
773 #ifdef DEBUG_LEVEL2
774 "-dbg"
775 #endif
776 " ";
777
778 /** woal_callbacks */
779 static mlan_callbacks woal_callbacks = {
780 .moal_get_fw_data = moal_get_fw_data,
781 .moal_get_vdll_data = moal_get_vdll_data,
782 .moal_get_hw_spec_complete = moal_get_hw_spec_complete,
783 .moal_init_fw_complete = moal_init_fw_complete,
784 .moal_shutdown_fw_complete = moal_shutdown_fw_complete,
785 .moal_send_packet_complete = moal_send_packet_complete,
786 .moal_recv_packet = moal_recv_packet,
787 .moal_recv_amsdu_packet = moal_recv_amsdu_packet,
788 .moal_recv_event = moal_recv_event,
789 .moal_ioctl_complete = moal_ioctl_complete,
790 .moal_alloc_mlan_buffer = moal_alloc_mlan_buffer,
791 .moal_free_mlan_buffer = moal_free_mlan_buffer,
792 #ifdef USB
793 .moal_recv_complete = moal_recv_complete,
794 .moal_write_data_async = moal_write_data_async,
795 #endif /* USB */
796
797 #if defined(SDIO) || defined(PCIE)
798 .moal_write_reg = moal_write_reg,
799 .moal_read_reg = moal_read_reg,
800 #endif /* SDIO || PCIE */
801 .moal_write_data_sync = moal_write_data_sync,
802 .moal_read_data_sync = moal_read_data_sync,
803 .moal_malloc = moal_malloc,
804 .moal_mfree = moal_mfree,
805 .moal_vmalloc = moal_vmalloc,
806 .moal_vfree = moal_vfree,
807 #ifdef PCIE
808 .moal_malloc_consistent = moal_malloc_consistent,
809 .moal_mfree_consistent = moal_mfree_consistent,
810 .moal_map_memory = moal_map_memory,
811 .moal_unmap_memory = moal_unmap_memory,
812 #endif /* PCIE */
813 .moal_memset = moal_memset,
814 .moal_memcpy = moal_memcpy,
815 .moal_memcpy_ext = moal_memcpy_ext,
816 .moal_memmove = moal_memmove,
817 .moal_memcmp = moal_memcmp,
818 .moal_udelay = moal_udelay,
819 .moal_usleep_range = moal_usleep_range,
820 .moal_get_system_time = moal_get_system_time,
821 .moal_get_boot_ktime = moal_get_boot_ktime,
822 .moal_init_timer = moal_init_timer,
823 .moal_free_timer = moal_free_timer,
824 .moal_start_timer = moal_start_timer,
825 .moal_stop_timer = moal_stop_timer,
826 .moal_init_lock = moal_init_lock,
827 .moal_free_lock = moal_free_lock,
828 .moal_spin_lock = moal_spin_lock,
829 .moal_spin_unlock = moal_spin_unlock,
830 .moal_print = moal_print,
831 .moal_print_netintf = moal_print_netintf,
832 .moal_assert = moal_assert,
833 .moal_hist_data_add = moal_hist_data_add,
834 .moal_updata_peer_signal = moal_updata_peer_signal,
835 .moal_do_div = moal_do_div,
836 #if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
837 .moal_wait_hostcmd_complete = moal_wait_hostcmd_complete,
838 .moal_notify_hostcmd_complete = moal_notify_hostcmd_complete,
839 #endif
840 .moal_tp_accounting = moal_tp_accounting,
841 .moal_tp_accounting_rx_param = moal_tp_accounting_rx_param,
842 .moal_amsdu_tp_accounting = moal_amsdu_tp_accounting,
843 };
844
845 int woal_open(struct net_device *dev);
846 int woal_close(struct net_device *dev);
847 int woal_set_mac_address(struct net_device *dev, void *addr);
848 int woal_change_mtu(struct net_device *dev, int new_mtu);
849 void woal_tx_timeout(struct net_device *dev
850 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
851 ,
852 unsigned int txqueue
853 #endif
854 );
855 struct net_device_stats *woal_get_stats(struct net_device *dev);
856 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
857 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
858 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
859 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
860 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)
861 u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb,
862 struct net_device *sb_dev);
863 #else
864 u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb,
865 struct net_device *sb_dev,
866 select_queue_fallback_t fallback);
867 #endif
868 #else
869 u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb,
870 void *accel_priv, select_queue_fallback_t fallback);
871 #endif
872 #else
873 u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb,
874 void *accel_priv);
875 #endif
876 #else
877 u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb);
878 #endif
879 #endif
880
881 static moal_handle *reset_handle;
882 /** Hang workqueue */
883 static struct workqueue_struct *hang_workqueue;
884 /** Hang work */
885 static struct work_struct hang_work;
886 /** register workqueue */
887 static struct workqueue_struct *register_workqueue;
888 /** register work */
889 static struct work_struct register_work;
890
891 /**
892 * @brief This function send fw dump event to kernel
893 *
894 * @param priv Pointer to structure moal_private
895 *
896 * @return N/A
897 */
woal_send_fw_dump_complete_event(moal_private * priv)898 void woal_send_fw_dump_complete_event(moal_private *priv)
899 {
900 int cfg80211_wext = priv->phandle->params.cfg80211_wext;
901 #ifdef STA_WEXT
902 if (IS_STA_WEXT(cfg80211_wext))
903 woal_send_iwevcustom_event(priv, CUS_EVT_FW_DUMP_DONE);
904 #endif
905 #ifdef STA_CFG80211
906 #if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
907 if (IS_STA_CFG80211(cfg80211_wext))
908 woal_cfg80211_vendor_event_fw_dump(priv);
909 #endif
910 #endif
911 if (MLAN_STATUS_SUCCESS !=
912 woal_broadcast_event(priv, CUS_EVT_FW_DUMP_DONE,
913 strlen(CUS_EVT_FW_DUMP_DONE)))
914 PRINTM(MINFO, "%s: woal_broadcast_event failed \n", __func__);
915
916 return;
917 }
918
919 /**
920 * @brief This function process FW hang
921 *
922 * @param handle Pointer to structure moal_handle
923 *
924 * @return N/A
925 */
woal_hang_work_queue(struct work_struct * work)926 static void woal_hang_work_queue(struct work_struct *work)
927 {
928 int i;
929 moal_private *priv;
930 int cfg80211_wext = 0;
931 int ret = 0;
932 ENTER();
933 if (!reset_handle) {
934 LEAVE();
935 return;
936 }
937
938 mlan_ioctl(reset_handle->pmlan_adapter, NULL);
939 cfg80211_wext = reset_handle->params.cfg80211_wext;
940 // stop pending scan
941 #ifdef STA_CFG80211
942 if (IS_STA_CFG80211(cfg80211_wext) && reset_handle->scan_request &&
943 reset_handle->scan_priv) {
944 moal_private *scan_priv = reset_handle->scan_priv;
945 /** some supplicant can not handle SCAN abort event */
946 if (scan_priv->bss_type == MLAN_BSS_TYPE_STA)
947 woal_cfg80211_scan_done(reset_handle->scan_request,
948 MTRUE);
949 else
950 woal_cfg80211_scan_done(reset_handle->scan_request,
951 MFALSE);
952 reset_handle->scan_request = NULL;
953 reset_handle->scan_priv = NULL;
954 cancel_delayed_work_sync(&reset_handle->scan_timeout_work);
955 reset_handle->scan_pending_on_block = MFALSE;
956 MOAL_REL_SEMAPHORE(&reset_handle->async_sem);
957 }
958 #endif
959
960 for (i = 0; i < reset_handle->priv_num; i++) {
961 if (reset_handle->priv[i]) {
962 priv = reset_handle->priv[i];
963 woal_stop_queue(priv->netdev);
964 if (netif_carrier_ok(priv->netdev))
965 netif_carrier_off(priv->netdev);
966 priv->media_connected = MFALSE;
967 // disconnect
968 moal_connection_status_check_pmqos(priv->phandle);
969 #ifdef STA_CFG80211
970 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
971 if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev &&
972 #if ((CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) || IMX_ANDROID_13)
973 priv->wdev->connected) {
974 #else
975 priv->wdev->current_bss) {
976 #endif
977 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
978 if (priv->host_mlme)
979 woal_host_mlme_disconnect(
980 priv,
981 MLAN_REASON_DEAUTH_LEAVING,
982 NULL);
983 else
984 #endif
985 cfg80211_disconnected(priv->netdev, 0,
986 NULL, 0,
987 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
988 true,
989 #endif
990 GFP_KERNEL);
991 }
992 #endif
993 #endif
994 // stop bgscan
995 #ifdef STA_CFG80211
996 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
997 if (IS_STA_CFG80211(cfg80211_wext) &&
998 priv->sched_scanning) {
999 priv->bg_scan_start = MFALSE;
1000 priv->bg_scan_reported = MFALSE;
1001 cfg80211_sched_scan_stopped(priv->wdev->wiphy
1002 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
1003 ,
1004 priv->bg_scan_reqid
1005 #endif
1006 );
1007 priv->sched_scanning = MFALSE;
1008 }
1009 #endif
1010 #endif
1011 }
1012 }
1013 woal_flush_workqueue(reset_handle);
1014 if (reset_handle->params.auto_fw_reload) {
1015 priv = woal_get_priv(reset_handle, MLAN_BSS_ROLE_ANY);
1016 if (priv) {
1017 woal_broadcast_event(priv, CUS_EVT_FW_RECOVER_START,
1018 strlen(CUS_EVT_FW_RECOVER_START));
1019 #ifdef STA_CFG80211
1020 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1021 if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
1022 woal_cfg80211_vendor_event(
1023 priv, event_fw_reset_start,
1024 CUS_EVT_FW_RECOVER_START,
1025 strlen(CUS_EVT_FW_RECOVER_START));
1026 #endif
1027 #endif
1028 }
1029 if (IS_SD(reset_handle->card_type)) {
1030 PRINTM(MMSG, "WIFI auto_fw_reload: fw_reload=1\n");
1031 ret = woal_request_fw_reload(
1032 reset_handle, FW_RELOAD_SDIO_INBAND_RESET);
1033 }
1034 #ifdef PCIE
1035 else if (IS_PCIE(reset_handle->card_type)) {
1036 reset_handle->init_wait_q_woken = MFALSE;
1037 PRINTM(MMSG, "WIFI auto_fw_reload: fw_reload=4\n");
1038 ret = woal_request_fw_reload(reset_handle,
1039 FW_RELOAD_PCIE_RESET);
1040 if (!ret) {
1041 /* Wait for FLR to complete */
1042 wait_event_timeout(
1043 reset_handle->init_wait_q,
1044 reset_handle->init_wait_q_woken,
1045 10 * HZ);
1046 if (reset_handle->hardware_status !=
1047 HardwareStatusReady)
1048 ret = -1;
1049 }
1050 }
1051 #endif
1052 priv = woal_get_priv(reset_handle, MLAN_BSS_ROLE_ANY);
1053 if (priv) {
1054 if (ret) {
1055 woal_broadcast_event(
1056 priv, CUS_EVT_FW_RECOVER_FAIL,
1057 strlen(CUS_EVT_FW_RECOVER_FAIL));
1058 #ifdef STA_CFG80211
1059 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1060 if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
1061 woal_cfg80211_vendor_event(
1062 priv, event_fw_reset_failure,
1063 CUS_EVT_FW_RECOVER_FAIL,
1064 strlen(CUS_EVT_FW_RECOVER_FAIL));
1065 #endif
1066 #endif
1067 } else {
1068 woal_broadcast_event(
1069 priv, CUS_EVT_FW_RECOVER_SUCCESS,
1070 strlen(CUS_EVT_FW_RECOVER_SUCCESS));
1071 #ifdef STA_CFG80211
1072 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1073 if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
1074 woal_cfg80211_vendor_event(
1075 priv, event_fw_reset_success,
1076 CUS_EVT_FW_RECOVER_SUCCESS,
1077 strlen(CUS_EVT_FW_RECOVER_SUCCESS));
1078 #endif
1079 #endif
1080 }
1081 }
1082 reset_handle = NULL;
1083 LEAVE();
1084 return;
1085 }
1086 priv = woal_get_priv(reset_handle, MLAN_BSS_ROLE_ANY);
1087 if (priv) {
1088 woal_broadcast_event(priv, CUS_EVT_DRIVER_HANG,
1089 strlen(CUS_EVT_DRIVER_HANG));
1090 #ifdef STA_CFG80211
1091 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1092 if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
1093 woal_cfg80211_vendor_event(priv, event_hang,
1094 CUS_EVT_DRIVER_HANG,
1095 strlen(CUS_EVT_DRIVER_HANG));
1096 #endif
1097 #endif
1098 }
1099 reset_handle = NULL;
1100 LEAVE();
1101 }
1102
1103 /**
1104 * @brief This function process FW hang
1105 *
1106 * @param handle Pointer to structure moal_handle
1107 *
1108 * @return N/A
1109 */
1110 void woal_process_hang(moal_handle *handle)
1111 {
1112 ENTER();
1113 if (reset_handle == NULL) {
1114 PRINTM(MMSG, "Start to process hanging\n");
1115 reset_handle = handle;
1116 queue_work(hang_workqueue, &hang_work);
1117 #ifdef ANDROID_KERNEL
1118 #define WAKE_LOCK_HANG 5000
1119 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
1120 __pm_wakeup_event(&reset_handle->ws, WAKE_LOCK_HANG);
1121 #else
1122 wake_lock_timeout(&reset_handle->wake_lock,
1123 msecs_to_jiffies(WAKE_LOCK_HANG));
1124 #endif
1125 #endif
1126 }
1127 LEAVE();
1128 }
1129
1130 /**
1131 * @brief Check if any interface is active
1132 *
1133 * @param handle A pointer to moal_handle
1134 *
1135 *
1136 * @return MTRUE/MFALSE;
1137 */
1138 t_u8 woal_is_any_interface_active(moal_handle *handle)
1139 {
1140 int i;
1141 for (i = 0; i < handle->priv_num; i++) {
1142 if (!handle->priv[i])
1143 continue;
1144 #ifdef STA_SUPPORT
1145 if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) {
1146 if (handle->priv[i]->media_connected == MTRUE)
1147 return MTRUE;
1148 }
1149 #endif
1150 #ifdef UAP_SUPPORT
1151 if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) {
1152 if (handle->priv[i]->bss_started == MTRUE)
1153 return MTRUE;
1154 }
1155 #endif
1156 }
1157 return MFALSE;
1158 }
1159
1160 #ifdef STA_CFG80211
1161 /** @brief This function set/clear pmk to FW
1162 *
1163 * @param priv A Pointer to the moal_private structure
1164 * @param action set/clear action
1165 *
1166 * @return 0: success fail otherwise
1167 */
1168 int woal_set_clear_pmk(moal_private *priv, t_u8 action)
1169 {
1170 mlan_ioctl_req *req;
1171 mlan_ds_sec_cfg *sec;
1172 mlan_status status;
1173 int ret = 0;
1174 t_u8 zero[MLAN_MAX_KEY_LENGTH] = {0};
1175 ENTER();
1176
1177 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
1178
1179 if (req == NULL) {
1180 ret = -ENOMEM;
1181 } else {
1182 sec = (mlan_ds_sec_cfg *)req->pbuf;
1183 sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
1184 req->req_id = MLAN_IOCTL_SEC_CFG;
1185 req->action = action;
1186
1187 if (action == MLAN_ACT_SET) {
1188 sec->param.passphrase.psk_type = MLAN_PSK_PMK;
1189 if (memcmp(priv->pmk.pmk, zero, MLAN_MAX_KEY_LENGTH))
1190 moal_memcpy_ext(
1191 priv->phandle,
1192 &sec->param.passphrase.psk.pmk.pmk,
1193 priv->pmk.pmk, MLAN_MAX_KEY_LENGTH,
1194 sizeof(sec->param.passphrase.psk.pmk
1195 .pmk));
1196 if (memcmp(priv->pmk.pmk_r0, zero,
1197 MLAN_MAX_KEY_LENGTH) &&
1198 memcmp(priv->pmk.pmk_r0_name, zero,
1199 MLAN_MAX_PMKR0_NAME_LENGTH)) {
1200 moal_memcpy_ext(
1201 priv->phandle,
1202 &sec->param.passphrase.psk.pmk.pmk_r0,
1203 priv->pmk.pmk_r0, MLAN_MAX_KEY_LENGTH,
1204 sizeof(sec->param.passphrase.psk.pmk
1205 .pmk_r0));
1206 moal_memcpy_ext(
1207 priv->phandle,
1208 &sec->param.passphrase.psk.pmk
1209 .pmk_r0_name,
1210 priv->pmk.pmk_r0_name,
1211 MLAN_MAX_PMKR0_NAME_LENGTH,
1212 sizeof(sec->param.passphrase.psk.pmk
1213 .pmk_r0_name));
1214 }
1215 }
1216
1217 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1218 if (MLAN_STATUS_SUCCESS != status)
1219 ret = -EFAULT;
1220 if (status != MLAN_STATUS_PENDING)
1221 kfree(req);
1222 }
1223
1224 LEAVE();
1225 return ret;
1226 }
1227 #endif
1228
1229 /**
1230 * @brief This function handle the net interface ipaddr change event
1231 *
1232 * @param nb pointer to the notifier_block
1233 * @param event event type
1234 * @param ptr pointer to event struct
1235 *
1236 * @return NOTIFY_DONE or NOTIFY_OK
1237 */
1238 static int woal_netdevice_event(struct notifier_block *nb, unsigned long event,
1239 void *ptr)
1240 {
1241 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
1242 struct net_device *ndev;
1243 moal_private *priv;
1244
1245 int ret = NOTIFY_OK;
1246 #ifdef STA_CFG80211
1247 char rssi_low[11];
1248 #endif
1249 ENTER();
1250
1251 ndev = ifa->ifa_dev->dev;
1252 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
1253 if (!ndev || ndev->netdev_ops->ndo_open != woal_open)
1254 #else
1255 if (!ndev || ndev->open != woal_open)
1256 #endif
1257 {
1258 PRINTM(MIOCTL, "IP changes not for us, ignore. ndev[%p]\n",
1259 ndev);
1260 if (ndev)
1261 PRINTM(MIOCTL, "changes on %s\n", ndev->name);
1262 ret = NOTIFY_DONE;
1263 goto done;
1264 }
1265 priv = (moal_private *)netdev_priv(ndev);
1266 if (priv->bss_type != MLAN_BSS_TYPE_STA
1267 #ifdef WIFI_DIRECT_SUPPORT
1268 && priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT
1269 #endif
1270 ) {
1271 PRINTM(MIOCTL, "Bss type [%d] is not STA/P2P, ignore\n",
1272 (int)priv->bss_type);
1273 ret = NOTIFY_DONE;
1274 goto done;
1275 }
1276
1277 switch (event) {
1278 case NETDEV_UP:
1279 PRINTM(MIOCTL, "[%s]: New ip addr: 0x%08x\n", ndev->name,
1280 ifa->ifa_address);
1281 /* Save the IP addr now */
1282 moal_memcpy_ext(priv->phandle, priv->ip_addr, &ifa->ifa_address,
1283 sizeof(ifa->ifa_address),
1284 sizeof(priv->ip_addr));
1285 priv->ip_addr_type = IPADDR_TYPE_IPV4;
1286 #ifdef STA_CFG80211
1287 if (!moal_extflg_isset(priv->phandle, EXT_HW_TEST) &&
1288 priv->roaming_enabled) {
1289 snprintf(rssi_low, sizeof(rssi_low), "%d",
1290 priv->rssi_low);
1291 if (MLAN_STATUS_SUCCESS !=
1292 woal_set_rssi_low_threshold(priv, rssi_low,
1293 MOAL_IOCTL_WAIT)) {
1294 PRINTM(MERROR,
1295 "%s: woal_set_rssi_low_threshold failed \n",
1296 __func__);
1297 goto done;
1298 }
1299 }
1300 #endif
1301 #ifdef STA_CFG80211
1302 if (priv->phandle->fw_roam_enable &&
1303 (priv->phandle->fw_roam_enable != AUTO_RECONNECT) &&
1304 !moal_extflg_isset(priv->phandle, EXT_ROAMOFFLOAD_IN_HS)) {
1305 snprintf(rssi_low, sizeof(rssi_low), "%d",
1306 priv->rssi_low);
1307 if (MLAN_STATUS_SUCCESS !=
1308 woal_set_rssi_low_threshold(priv, rssi_low,
1309 MOAL_IOCTL_WAIT)) {
1310 PRINTM(MERROR,
1311 "%s: woal_set_rssi_low_threshold failed \n",
1312 __func__);
1313 goto done;
1314 }
1315 if (priv->pmk_saved) {
1316 woal_set_clear_pmk(priv, MLAN_ACT_SET);
1317 priv->pmk_saved = false;
1318 }
1319 }
1320 #endif
1321 break;
1322 case NETDEV_DOWN:
1323 PRINTM(MIOCTL, "[%s]: Ip addr removed.\n", ndev->name);
1324 priv->ip_addr_type = IPADDR_TYPE_NONE;
1325 memset(priv->ip_addr, 0, sizeof(priv->ip_addr));
1326 break;
1327 default:
1328 PRINTM(MIOCTL, "[%s]: Ignore event: %u\n", ndev->name,
1329 (unsigned int)event);
1330 ret = NOTIFY_DONE;
1331 goto done;
1332 }
1333
1334 done:
1335 LEAVE();
1336 return ret;
1337 }
1338
1339 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
1340 #if IS_ENABLED(CONFIG_IPV6)
1341 /**
1342 * @brief This function handle the net interface ipv6 address change event
1343 *
1344 * @param nb pointer to the notifier_block
1345 * @param event event type
1346 * @param ptr pointer to event struct
1347 *
1348 * @return NOTIFY_DONE or NOTIFY_OK
1349 */
1350 static int woal_inet6_netdeive_event(struct notifier_block *nb,
1351 unsigned long event, void *ptr)
1352 {
1353 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
1354 struct net_device *ndev = ifa->idev->dev;
1355 moal_private *priv;
1356 int ret = NOTIFY_OK;
1357
1358 ENTER();
1359
1360 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
1361 if (!ndev || ndev->netdev_ops->ndo_open != woal_open)
1362 #else
1363 if (!ndev || ndev->open != woal_open)
1364 #endif
1365 {
1366 PRINTM(MIOCTL, "IPV6 changes not for us, ignore. ndev[%p]\n",
1367 ndev);
1368 if (ndev)
1369 PRINTM(MIOCTL, "changes on %s\n", ndev->name);
1370 ret = NOTIFY_DONE;
1371 goto done;
1372 }
1373 priv = (moal_private *)netdev_priv(ndev);
1374 if (!priv) {
1375 PRINTM(MERROR, "Invalid private structure\n");
1376 goto done;
1377 }
1378 if (priv->bss_type != MLAN_BSS_TYPE_STA
1379 #ifdef WIFI_DIRECT_SUPPORT
1380 && priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT
1381 #endif
1382 ) {
1383 PRINTM(MIOCTL, "Bss type [%d] is not STA/P2P, ignore\n",
1384 (int)priv->bss_type);
1385 ret = NOTIFY_DONE;
1386 goto done;
1387 }
1388
1389 switch (event) {
1390 case NETDEV_UP:
1391 PRINTM(MIOCTL, "[%s]: New ipv6 addr\n", ndev->name);
1392 moal_memcpy_ext(priv->phandle, priv->ipv6_addr,
1393 (t_u8 *)&ifa->addr, sizeof(priv->ipv6_addr),
1394 sizeof(priv->ipv6_addr));
1395 priv->ipv6_addr_configured = MTRUE;
1396 break;
1397 case NETDEV_DOWN:
1398 PRINTM(MIOCTL, "[%s]: Ipv6 addr removed.\n", ndev->name);
1399 memset(priv->ipv6_addr, 0, sizeof(priv->ipv6_addr));
1400 priv->ipv6_addr_configured = MFALSE;
1401 break;
1402 default:
1403 PRINTM(MIOCTL, "[%s]: Ignore event: %u\n", ndev->name,
1404 (unsigned int)event);
1405 ret = NOTIFY_DONE;
1406 goto done;
1407 }
1408 done:
1409 LEAVE();
1410 return ret;
1411 }
1412 #endif
1413 #endif
1414
1415 /**
1416 * @brief This function validates a SSID as being able to be printed
1417 *
1418 * @param pssid SSID structure to validate
1419 *
1420 * @return MTRUE or MFALSE
1421 */
1422 BOOLEAN woal_ssid_valid(mlan_802_11_ssid *pssid)
1423 {
1424 #ifdef ASCII_SSID_CHECK
1425 unsigned int ssid_idx;
1426
1427 ENTER();
1428
1429 for (ssid_idx = 0; ssid_idx < pssid->ssid_len; ssid_idx++) {
1430 if ((pssid->ssid[ssid_idx] < 0x20) ||
1431 (pssid->ssid[ssid_idx] > 0x7e)) {
1432 LEAVE();
1433 return MFALSE;
1434 }
1435 }
1436 LEAVE();
1437 #endif
1438 return MTRUE;
1439 }
1440
1441 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
1442 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
1443 /**
1444 * @brief Remain on Channel timeout function
1445 *
1446 * @param context A pointer to context
1447 * @return N/A
1448 */
1449 void woal_remain_timer_func(void *context)
1450 {
1451 moal_handle *handle = (moal_handle *)context;
1452 moal_private *priv = handle->priv[handle->remain_bss_index];
1453
1454 ENTER();
1455
1456 PRINTM(MEVENT, "remain_timer fired.\n");
1457 if (handle->cookie) {
1458 cfg80211_remain_on_channel_expired(
1459 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
1460 priv->netdev,
1461 #else
1462 priv->wdev,
1463 #endif
1464 handle->cookie, &handle->chan,
1465 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
1466 handle->channel_type,
1467 #endif
1468 GFP_ATOMIC);
1469 handle->cookie = 0;
1470 }
1471 handle->is_remain_timer_set = MFALSE;
1472
1473 LEAVE();
1474 return;
1475 }
1476 #endif
1477 #endif
1478
1479 #ifdef WIFI_DIRECT_SUPPORT
1480 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
1481 /**
1482 * @brief GO timeout function
1483 *
1484 * @param context A pointer to context
1485 * @return N/A
1486 */
1487 void woal_go_timer_func(void *context)
1488 {
1489 moal_handle *handle = (moal_handle *)context;
1490
1491 ENTER();
1492
1493 PRINTM(MEVENT, "go_timer fired.\n");
1494 handle->is_go_timer_set = MFALSE;
1495
1496 LEAVE();
1497 return;
1498 }
1499
1500 #endif
1501 #endif
1502
1503 /**
1504 * @brief check if we already connect to the AP.
1505 * @param priv A pointer to moal_private structure
1506 * @param ssid_bssid A pointer to mlan_ssid_bssid structure
1507 *
1508 * @return MTRUE/MFALSE;
1509 */
1510 int woal_is_connected(moal_private *priv, mlan_ssid_bssid *ssid_bssid)
1511 {
1512 mlan_bss_info bss_info;
1513 int ret = MFALSE;
1514 t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
1515 ENTER();
1516 memset(&bss_info, 0, sizeof(bss_info));
1517 if (MLAN_STATUS_SUCCESS !=
1518 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info))
1519 goto done;
1520 if (bss_info.media_connected) {
1521 if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) {
1522 if (ssid_bssid->ssid.ssid_len) { /* compare ssid and
1523 bssid */
1524 if ((ssid_bssid->ssid.ssid_len ==
1525 bss_info.ssid.ssid_len) &&
1526 !memcmp(ssid_bssid->ssid.ssid,
1527 bss_info.ssid.ssid,
1528 bss_info.ssid.ssid_len) &&
1529 !memcmp(ssid_bssid->bssid, bss_info.bssid,
1530 MLAN_MAC_ADDR_LENGTH))
1531 ret = MTRUE;
1532 } else { /* compare bssid */
1533 if (!memcmp(ssid_bssid->bssid, bss_info.bssid,
1534 MLAN_MAC_ADDR_LENGTH)) {
1535 moal_memcpy_ext(
1536 priv->phandle,
1537 &ssid_bssid->ssid,
1538 &bss_info.ssid,
1539 sizeof(bss_info.ssid),
1540 sizeof(ssid_bssid->ssid));
1541 ret = MTRUE;
1542 }
1543 }
1544 } else { /* compare ssid */
1545 if (ssid_bssid->ssid.ssid_len &&
1546 (ssid_bssid->ssid.ssid_len ==
1547 bss_info.ssid.ssid_len) &&
1548 !memcmp(ssid_bssid->ssid.ssid, bss_info.ssid.ssid,
1549 bss_info.ssid.ssid_len)) {
1550 moal_memcpy_ext(priv->phandle,
1551 &ssid_bssid->bssid,
1552 &bss_info.bssid,
1553 MLAN_MAC_ADDR_LENGTH,
1554 sizeof(ssid_bssid->bssid));
1555 ret = MTRUE;
1556 }
1557 }
1558 }
1559 done:
1560 LEAVE();
1561 return ret;
1562 }
1563
1564 /**
1565 * @brief Look up specific IE in a buf
1566 *
1567 * @param ie Pointer to IEs
1568 * @param len Total length of ie
1569 * @param id Element id to lookup
1570 *
1571 * @return Pointer of the specific IE -- success, NULL -- fail
1572 */
1573 const t_u8 *woal_parse_ie_tlv(const t_u8 *ie, int len, t_u8 id)
1574 {
1575 int left_len = len;
1576 const t_u8 *pos = ie;
1577 int length;
1578
1579 /* IE format:
1580 * | u8 | id |
1581 * | u8 | len |
1582 * | var | data |
1583 */
1584 while (left_len >= 2) {
1585 length = *(pos + 1);
1586 if ((*pos == id) && (length + 2) <= left_len)
1587 return pos;
1588 pos += (length + 2);
1589 left_len -= (length + 2);
1590 }
1591
1592 return NULL;
1593 }
1594
1595 /**
1596 * @brief Look up specific IE in Extension IE
1597 *
1598 * @param ie Pointer to IEs
1599 * @param len Total length of ie
1600 * @param ext_id Extended Element id to lookup
1601 *
1602 * @return Pointer of the specific Extended IE -- success, NULL
1603 * -- fail
1604 */
1605 const t_u8 *woal_parse_ext_ie_tlv(const t_u8 *ie, int len, t_u8 ext_id)
1606 {
1607 int left_len = len;
1608 const t_u8 *pos = ie;
1609 int length;
1610
1611 /* Extension IE format:
1612 * | u8 | id |
1613 * | u8 | len |
1614 * | u8 | ext_id |
1615 * | var | data |
1616 */
1617 while (left_len >= 2) {
1618 length = *(pos + 1);
1619 if ((*pos == EXTENSION) && (length + 2) <= left_len) {
1620 if (*(pos + 2) == ext_id)
1621 return pos;
1622 }
1623 pos += (length + 2);
1624 left_len -= (length + 2);
1625 }
1626 return NULL;
1627 }
1628
1629 /**
1630 * @brief Get mode
1631 *
1632 * @param priv A pointer to moal_private structure
1633 * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
1634 *
1635 * @return Wireless mode
1636 */
1637 t_u32 woal_get_mode(moal_private *priv, t_u8 wait_option)
1638 {
1639 mlan_ds_bss *bss = NULL;
1640 mlan_ioctl_req *req = NULL;
1641 mlan_status status = MLAN_STATUS_SUCCESS;
1642 t_u32 mode = 0;
1643
1644 ENTER();
1645
1646 #if defined(STA_WEXT) || defined(UAP_WEXT)
1647 mode = priv->w_stats.status;
1648 #endif
1649 /* Allocate an IOCTL request buffer */
1650 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
1651 if (req == NULL) {
1652 status = MLAN_STATUS_FAILURE;
1653 goto done;
1654 }
1655
1656 /* Fill request buffer */
1657 bss = (mlan_ds_bss *)req->pbuf;
1658 bss->sub_command = MLAN_OID_BSS_MODE;
1659 req->req_id = MLAN_IOCTL_BSS;
1660 req->action = MLAN_ACT_GET;
1661
1662 /* Send IOCTL request to MLAN */
1663 status = woal_request_ioctl(priv, req, wait_option);
1664 if (status == MLAN_STATUS_SUCCESS) {
1665 switch (bss->param.bss_mode) {
1666 case MLAN_BSS_MODE_INFRA:
1667 mode = MW_MODE_INFRA;
1668 break;
1669 case MLAN_BSS_MODE_IBSS:
1670 mode = MW_MODE_ADHOC;
1671 break;
1672 default:
1673 mode = MW_MODE_AUTO;
1674 break;
1675 }
1676 }
1677 done:
1678 if (status != MLAN_STATUS_PENDING)
1679 kfree(req);
1680 LEAVE();
1681 return mode;
1682 }
1683
1684 /********************************************************
1685 Local Functions
1686 ********************************************************/
1687 /**
1688 * @brief This function update the default firmware name
1689 *
1690 * @param handle A pointer to moal_handle structure
1691 *
1692 * @return N/A
1693 */
1694 void woal_update_firmware_name(moal_handle *handle)
1695 {
1696 if (handle->params.fw_name) {
1697 handle->drv_mode.fw_name = handle->params.fw_name;
1698 } else {
1699 if (!moal_extflg_isset(handle, EXT_FW_SERIAL) ||
1700 handle->fw_reload || handle->params.fw_reload) {
1701 handle->drv_mode.fw_name =
1702 handle->card_info->fw_name_wlan;
1703 } else
1704 handle->drv_mode.fw_name = handle->card_info->fw_name;
1705 }
1706 }
1707 /**
1708 * @brief This function dynamically populates the driver mode table
1709 *
1710 * @param handle A pointer to moal_handle structure
1711 * @param drv_mode_local Driver mode
1712 *
1713 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1714 */
1715 mlan_status woal_update_drv_tbl(moal_handle *handle, int drv_mode_local)
1716 {
1717 mlan_status ret = MLAN_STATUS_SUCCESS;
1718 unsigned int intf_num = 0;
1719 int i = 0, j = 0;
1720 mlan_bss_attr *bss_tbl = NULL;
1721 #ifdef WIFI_DIRECT_SUPPORT
1722 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
1723 int last_wfd_index = 0;
1724 int max_vir_bss = handle->params.max_vir_bss;
1725 #endif
1726 #endif
1727 #ifdef STA_SUPPORT
1728 int max_sta_bss = handle->params.max_sta_bss;
1729 #endif
1730 #ifdef UAP_SUPPORT
1731 int max_uap_bss = handle->params.max_uap_bss;
1732 #endif
1733 #ifdef WIFI_DIRECT_SUPPORT
1734 int max_wfd_bss = handle->params.max_wfd_bss;
1735 #endif
1736 int max_dfs_bss = MAX_DFS_BSS;
1737
1738 ENTER();
1739
1740 /* Calculate number of interfaces */
1741 #ifdef STA_SUPPORT
1742 if (drv_mode_local & DRV_MODE_STA) {
1743 if ((max_sta_bss < 1) || (max_sta_bss > MAX_STA_BSS)) {
1744 PRINTM(MWARN,
1745 "Unsupported max_sta_bss (%d), setting to default\n",
1746 max_sta_bss);
1747 max_sta_bss = DEF_STA_BSS;
1748 }
1749 intf_num += max_sta_bss;
1750 handle->params.max_sta_bss = max_sta_bss;
1751 }
1752 #endif /* STA_SUPPORT */
1753
1754 #ifdef UAP_SUPPORT
1755 if (drv_mode_local & DRV_MODE_UAP) {
1756 if ((max_uap_bss < 1) || (max_uap_bss > MAX_UAP_BSS)) {
1757 PRINTM(MWARN,
1758 "Unsupported max_uap_bss (%d), setting to default\n",
1759 max_uap_bss);
1760 max_uap_bss = DEF_UAP_BSS;
1761 }
1762 intf_num += max_uap_bss;
1763 handle->params.max_uap_bss = max_uap_bss;
1764 }
1765 #endif /* UAP_SUPPORT */
1766
1767 #ifdef WIFI_DIRECT_SUPPORT
1768 if (drv_mode_local & DRV_MODE_WIFIDIRECT) {
1769 if ((max_wfd_bss < 1) || (max_wfd_bss > MAX_WIFIDIRECT_BSS)) {
1770 PRINTM(MWARN,
1771 "Unsupported max_wfd_bss (%d), setting to default\n",
1772 max_wfd_bss);
1773 max_wfd_bss = DEF_WIFIDIRECT_BSS;
1774 }
1775 intf_num += max_wfd_bss;
1776 handle->params.max_wfd_bss = max_wfd_bss;
1777 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
1778 intf_num += max_vir_bss;
1779 #endif
1780 }
1781
1782 #endif /* WIFI_DIRECT_SUPPORT */
1783
1784 if (drv_mode_local & DRV_MODE_DFS)
1785 intf_num += max_dfs_bss;
1786 /* Create BSS attribute table */
1787 if ((intf_num == 0) || (intf_num > MLAN_MAX_BSS_NUM)) {
1788 PRINTM(MERROR, "Unsupported number of BSS %d\n", intf_num);
1789 ret = MLAN_STATUS_FAILURE;
1790 goto done;
1791 } else {
1792 /* Create new table */
1793 bss_tbl = kmalloc(sizeof(mlan_bss_attr) * intf_num, GFP_KERNEL);
1794 if (!bss_tbl) {
1795 PRINTM(MERROR,
1796 "Could not create BSS attribute table\n");
1797 ret = MLAN_STATUS_FAILURE;
1798 goto done;
1799 }
1800 }
1801
1802 /* Populate BSS attribute table */
1803 #ifdef STA_SUPPORT
1804 if (drv_mode_local & DRV_MODE_STA) {
1805 for (j = 0; j < max_sta_bss; j++) {
1806 if (i >= (int)intf_num)
1807 break;
1808 bss_tbl[i].bss_type = MLAN_BSS_TYPE_STA;
1809 bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
1810 bss_tbl[i].active = MTRUE;
1811 bss_tbl[i].bss_priority = 0;
1812 bss_tbl[i].bss_num = j;
1813 bss_tbl[i].bss_virtual = MFALSE;
1814 i++;
1815 }
1816 }
1817 #endif /* STA_SUPPORT */
1818
1819 #ifdef UAP_SUPPORT
1820 if (drv_mode_local & DRV_MODE_UAP) {
1821 for (j = 0; j < max_uap_bss; j++) {
1822 if (i >= (int)intf_num)
1823 break;
1824 bss_tbl[i].bss_type = MLAN_BSS_TYPE_UAP;
1825 bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
1826 bss_tbl[i].active = MTRUE;
1827 bss_tbl[i].bss_priority = 0;
1828 bss_tbl[i].bss_num = j;
1829 bss_tbl[i].bss_virtual = MFALSE;
1830 i++;
1831 }
1832 }
1833 #endif /* UAP_SUPPORT */
1834
1835 #ifdef WIFI_DIRECT_SUPPORT
1836 if (drv_mode_local & DRV_MODE_WIFIDIRECT) {
1837 for (j = 0; j < max_wfd_bss; j++) {
1838 if (i >= (int)intf_num)
1839 break;
1840 bss_tbl[i].bss_type = MLAN_BSS_TYPE_WIFIDIRECT;
1841 bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
1842 bss_tbl[i].active = MTRUE;
1843 bss_tbl[i].bss_priority = 0;
1844 bss_tbl[i].bss_num = j;
1845 bss_tbl[i].bss_virtual = MFALSE;
1846 i++;
1847 }
1848 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
1849 last_wfd_index = j;
1850 #endif
1851 }
1852 #endif /* WIFI_DIRECT_SUPPORT */
1853
1854 if (drv_mode_local & DRV_MODE_DFS) {
1855 for (j = 0; j < max_dfs_bss; j++) {
1856 if (i >= (int)intf_num)
1857 break;
1858 bss_tbl[i].bss_type = MLAN_BSS_TYPE_DFS;
1859 bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
1860 bss_tbl[i].active = MTRUE;
1861 bss_tbl[i].bss_priority = 0;
1862 bss_tbl[i].bss_num = j;
1863 bss_tbl[i].bss_virtual = MFALSE;
1864 i++;
1865 }
1866 }
1867
1868 #ifdef WIFI_DIRECT_SUPPORT
1869 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
1870 /** append virtual interface at the end of table */
1871 for (j = 0; j < max_vir_bss; j++) {
1872 if (i >= (int)intf_num)
1873 break;
1874 bss_tbl[i].bss_type = MLAN_BSS_TYPE_WIFIDIRECT;
1875 bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
1876 bss_tbl[i].active = MTRUE;
1877 bss_tbl[i].bss_priority = 0;
1878 bss_tbl[i].bss_num = j + last_wfd_index;
1879 bss_tbl[i].bss_virtual = MTRUE;
1880 i++;
1881 }
1882 #endif
1883 #endif
1884
1885 /* Clear existing table, if any */
1886 kfree(handle->drv_mode.bss_attr);
1887 handle->drv_mode.bss_attr = NULL;
1888
1889 /* Create moal_drv_mode entry */
1890 handle->drv_mode.drv_mode = handle->params.drv_mode;
1891 handle->drv_mode.intf_num = intf_num;
1892 handle->drv_mode.bss_attr = bss_tbl;
1893
1894 /* update default firmware name */
1895 woal_update_firmware_name(handle);
1896 done:
1897 LEAVE();
1898 return ret;
1899 }
1900
1901 /**
1902 * @brief This function initializes software
1903 *
1904 * @param handle A pointer to moal_handle structure
1905 *
1906 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1907 */
1908 mlan_status woal_init_sw(moal_handle *handle)
1909 {
1910 mlan_status ret = MLAN_STATUS_SUCCESS;
1911 unsigned int i;
1912 mlan_device device;
1913 t_void *pmlan;
1914 int cfg80211_wext = handle->params.cfg80211_wext;
1915
1916 ENTER();
1917
1918 /* Initialize moal_handle structure */
1919 handle->hardware_status = HardwareStatusInitializing;
1920 handle->main_state = MOAL_STATE_IDLE;
1921
1922 #ifdef STA_SUPPORT
1923 if ((handle->params.drv_mode & DRV_MODE_STA)
1924 #ifdef STA_WEXT
1925 && !IS_STA_WEXT(cfg80211_wext)
1926 #endif
1927 #ifdef STA_CFG80211
1928 && !IS_STA_CFG80211(cfg80211_wext)
1929 #endif
1930 #ifdef MFG_CMD_SUPPORT
1931 && !handle->params.mfg_mode
1932 #endif
1933 ) {
1934 PRINTM(MERROR,
1935 "STA without WEXT or CFG80211 bit definition!\n");
1936 LEAVE();
1937 return MLAN_STATUS_FAILURE;
1938 }
1939 #endif /* STA_SUPPORT */
1940
1941 #if defined(STA_CFG80211) && defined(STA_SUPPORT)
1942 if (IS_STA_CFG80211(cfg80211_wext))
1943 cfg80211_wext |= STA_CFG80211_MASK | UAP_CFG80211_MASK;
1944 #endif
1945
1946 #if defined(UAP_CFG80211) && defined(UAP_SUPPORT)
1947 if (IS_UAP_CFG80211(cfg80211_wext))
1948 cfg80211_wext |= STA_CFG80211_MASK | UAP_CFG80211_MASK;
1949 #endif
1950 handle->params.cfg80211_wext = cfg80211_wext;
1951 moal_memcpy_ext(handle, handle->driver_version, driver_version,
1952 strlen(driver_version), MLAN_MAX_VER_STR_LEN - 1);
1953
1954 if (woal_update_drv_tbl(handle, handle->params.drv_mode) !=
1955 MLAN_STATUS_SUCCESS) {
1956 PRINTM(MERROR, "Could not update driver mode table\n");
1957 LEAVE();
1958 return MLAN_STATUS_FAILURE;
1959 }
1960
1961 /** user config file */
1962 init_waitqueue_head(&handle->init_user_conf_wait_q);
1963
1964 /* PnP and power profile */
1965 handle->surprise_removed = MFALSE;
1966 init_waitqueue_head(&handle->init_wait_q);
1967 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
1968 spin_lock_init(&handle->queue_lock);
1969 #endif
1970 spin_lock_init(&handle->driver_lock);
1971 spin_lock_init(&handle->ioctl_lock);
1972 spin_lock_init(&handle->scan_req_lock);
1973
1974 handle->is_suspended = MFALSE;
1975 handle->hs_activated = MFALSE;
1976 handle->hs_auto_arp = MTRUE;
1977 handle->suspend_fail = MFALSE;
1978 handle->hs_skip_count = 0;
1979 handle->hs_force_count = 0;
1980 #ifdef SDIO
1981 if (IS_SD(handle->card_type)) {
1982 #ifdef SDIO_SUSPEND_RESUME
1983 handle->suspend_notify_req = MFALSE;
1984 #endif
1985 handle->cmd52_func = 0;
1986 handle->cmd52_reg = 0;
1987 handle->cmd52_val = 0;
1988 }
1989 #endif
1990
1991 if (handle->params.scan_chan_gap &&
1992 (handle->params.scan_chan_gap <= MRVDRV_MAX_SCAN_CHAN_GAP_TIME))
1993 handle->scan_chan_gap = handle->params.scan_chan_gap;
1994 else
1995 handle->scan_chan_gap = DEF_SCAN_CHAN_GAP;
1996
1997 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
1998 #ifdef WIFI_DIRECT_SUPPORT
1999 handle->miracast_scan_time = DEF_MIRACAST_SCAN_TIME;
2000 #define DEF_NOA_DURATION 0
2001 #define DEF_NOA_INTERVAL 100
2002 handle->noa_duration = DEF_NOA_DURATION;
2003 handle->noa_interval = DEF_NOA_INTERVAL;
2004 #endif
2005 #endif
2006
2007 #ifdef STA_CFG80211
2008 handle->scan_timeout = SCAN_TIMEOUT_25S;
2009 #endif
2010 if (IS_USB(handle->card_type))
2011 init_waitqueue_head(&handle->suspend_wait_q);
2012 init_waitqueue_head(&handle->hs_activate_wait_q);
2013
2014 /* Initialize measurement wait queue */
2015 handle->meas_wait_q_woken = MFALSE;
2016 handle->meas_start_jiffies = 0;
2017 handle->cac_period = MFALSE;
2018 handle->delay_bss_start = MFALSE;
2019 init_waitqueue_head(&handle->meas_wait_q);
2020 #if defined(UAP_SUPPORT)
2021 handle->chsw_wait_q_woken = MFALSE;
2022 init_waitqueue_head(&handle->chsw_wait_q);
2023 #endif
2024
2025 handle->cac_period_jiffies = 0;
2026 handle->usr_nop_period_sec = 0;
2027 #ifdef UAP_CFG80211
2028 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
2029 memset(&handle->dfs_channel, 0, sizeof(struct cfg80211_chan_def));
2030 woal_initialize_timer(&handle->cac_timer, woal_cac_timer_func, handle);
2031 handle->is_cac_timer_set = MFALSE;
2032 handle->cac_bss_index = 0xff;
2033 #endif
2034 #endif
2035 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
2036 handle->mon_if = NULL;
2037 #endif
2038
2039 #ifdef REASSOCIATION
2040 MOAL_INIT_SEMAPHORE(&handle->reassoc_sem);
2041 handle->reassoc_on = 0;
2042
2043 /* Initialize the timer for the reassociation */
2044 woal_initialize_timer(&handle->reassoc_timer, woal_reassoc_timer_func,
2045 handle);
2046
2047 handle->is_reassoc_timer_set = MFALSE;
2048 #endif /* REASSOCIATION */
2049
2050 /* Initialize the timer for the FW dump*/
2051 woal_initialize_timer(&handle->fw_dump_timer, woal_fw_dump_timer_func,
2052 handle);
2053 handle->is_fw_dump_timer_set = MFALSE;
2054
2055 #ifdef WIFI_DIRECT_SUPPORT
2056 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
2057 /* Initialize the timer for GO timeout */
2058 woal_initialize_timer(&handle->go_timer, woal_go_timer_func, handle);
2059
2060 handle->is_go_timer_set = MFALSE;
2061 #endif
2062 #endif
2063
2064 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
2065 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
2066 handle->remain_on_channel = MFALSE;
2067
2068 /* Initialize the timer for remain on channel */
2069 woal_initialize_timer(&handle->remain_timer, woal_remain_timer_func,
2070 handle);
2071
2072 handle->is_remain_timer_set = MFALSE;
2073 #endif
2074 #endif
2075
2076 /* Register to MLAN */
2077 memset(&device, 0, sizeof(mlan_device));
2078 device.pmoal_handle = handle;
2079 device.card_type = handle->card_type;
2080 device.card_rev = handle->card_rev;
2081 #ifdef USB
2082 if (IS_USB(handle->card_type)) {
2083 struct usb_card_rec *cardp = handle->card;
2084 device.tx_cmd_ep = cardp->tx_cmd_ep;
2085 device.rx_cmd_ep = cardp->rx_cmd_ep;
2086 device.tx_data_ep = cardp->tx_data_ep;
2087 device.rx_data_ep = cardp->rx_data_ep;
2088 }
2089 #endif
2090 #ifdef MFG_CMD_SUPPORT
2091 device.mfg_mode = (t_u32)handle->params.mfg_mode;
2092 #endif
2093 #ifdef DEBUG_LEVEL1
2094 device.drvdbg = drvdbg;
2095 #endif
2096 device.fixed_beacon_buffer =
2097 (t_u32)moal_extflg_isset(handle, EXT_FIX_BCN_BUF);
2098 device.auto_ds = (t_u32)handle->params.auto_ds;
2099 device.ext_scan = (t_u8)handle->params.ext_scan;
2100 device.ps_mode = (t_u32)handle->params.ps_mode;
2101 device.passive_to_active_scan = (t_u8)handle->params.p2a_scan;
2102 device.max_tx_buf = (t_u32)handle->params.max_tx_buf;
2103 #if defined(STA_SUPPORT)
2104 device.cfg_11d = (t_u32)handle->params.cfg_11d;
2105 #endif
2106 device.indrstcfg = (t_u32)handle->params.indrstcfg;
2107 #ifdef PCIE
2108 if (IS_PCIE(handle->card_type))
2109 device.ring_size = handle->params.ring_size;
2110 #endif
2111 #ifdef SDIO
2112 if (IS_SD(handle->card_type)) {
2113 device.sdio_rx_aggr_enable =
2114 moal_extflg_isset(handle, EXT_SDIO_RX_AGGR);
2115 device.int_mode = (t_u32)moal_extflg_isset(handle, EXT_INTMODE);
2116 device.gpio_pin = (t_u32)handle->params.gpiopin;
2117 #ifdef SDIO_MMC
2118 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)
2119 device.max_segs = ((struct sdio_mmc_card *)handle->card)
2120 ->func->card->host->max_segs;
2121 device.max_seg_size = ((struct sdio_mmc_card *)handle->card)
2122 ->func->card->host->max_seg_size;
2123 #endif
2124 PRINTM(MMSG, "SDIO: max_segs=%d max_seg_size=%d\n",
2125 device.max_segs, device.max_seg_size);
2126 #ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
2127 device.mpa_tx_cfg = MLAN_INIT_PARA_ENABLED;
2128 device.mpa_rx_cfg = MLAN_INIT_PARA_ENABLED;
2129 #else
2130 device.mpa_tx_cfg = MLAN_INIT_PARA_DISABLED;
2131 device.mpa_rx_cfg = MLAN_INIT_PARA_DISABLED;
2132 #endif
2133 #else
2134 device.mpa_tx_cfg = MLAN_INIT_PARA_ENABLED;
2135 device.mpa_rx_cfg = MLAN_INIT_PARA_ENABLED;
2136 #endif /* SDIO_MMC */
2137 }
2138 #endif /* SDIO */
2139 device.feature_control = handle->card_info->feature_control;
2140 handle->feature_control = device.feature_control;
2141
2142 if (handle->params.rx_work == MLAN_INIT_PARA_ENABLED)
2143 device.rx_work = MTRUE;
2144 else if (handle->params.rx_work == MLAN_INIT_PARA_DISABLED)
2145 device.rx_work = MFALSE;
2146 else {
2147 if (num_possible_cpus() > 1)
2148 device.rx_work = MTRUE;
2149 else
2150 device.rx_work = MFALSE;
2151 }
2152 PRINTM(MMSG, "rx_work=%d cpu_num=%d\n", device.rx_work,
2153 num_possible_cpus());
2154 if (moal_extflg_isset(handle, EXT_NAPI))
2155 device.rx_work = MTRUE;
2156
2157 device.dev_cap_mask = handle->params.dev_cap_mask;
2158
2159 device.multi_dtim = handle->params.multi_dtim;
2160
2161 device.inact_tmo = handle->params.inact_tmo;
2162 #ifdef UAP_SUPPORT
2163 device.uap_max_sta = handle->params.uap_max_sta;
2164 #endif
2165 device.mcs32 = handle->params.mcs32;
2166 device.hs_wake_interval = handle->params.hs_wake_interval;
2167 device.indication_gpio = handle->params.indication_gpio;
2168 device.hs_mimo_switch = moal_extflg_isset(handle, EXT_HS_MIMO_SWITCH);
2169
2170 device.dfs53cfg = handle->params.dfs53cfg;
2171 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
2172 device.dfs_offload = moal_extflg_isset(handle, EXT_DFS_OFFLOAD);
2173 #endif
2174
2175 for (i = 0; i < handle->drv_mode.intf_num; i++) {
2176 device.bss_attr[i].bss_type =
2177 handle->drv_mode.bss_attr[i].bss_type;
2178 device.bss_attr[i].frame_type =
2179 handle->drv_mode.bss_attr[i].frame_type;
2180 device.bss_attr[i].active = handle->drv_mode.bss_attr[i].active;
2181 device.bss_attr[i].bss_priority =
2182 handle->drv_mode.bss_attr[i].bss_priority;
2183 device.bss_attr[i].bss_num =
2184 handle->drv_mode.bss_attr[i].bss_num;
2185 device.bss_attr[i].bss_virtual =
2186 handle->drv_mode.bss_attr[i].bss_virtual;
2187 }
2188 moal_memcpy_ext(handle, &device.callbacks, &woal_callbacks,
2189 sizeof(mlan_callbacks), sizeof(mlan_callbacks));
2190 if (!handle->params.amsdu_deaggr)
2191 device.callbacks.moal_recv_amsdu_packet = NULL;
2192 device.drv_mode = handle->params.drv_mode;
2193 if (MLAN_STATUS_SUCCESS == mlan_register(&device, &pmlan))
2194 handle->pmlan_adapter = pmlan;
2195 else
2196 ret = MLAN_STATUS_FAILURE;
2197
2198 LEAVE();
2199 return ret;
2200 }
2201
2202 /**
2203 * @brief This function frees the structure of moal_handle
2204 *
2205 * @param handle A pointer to moal_handle structure
2206 *
2207 * @return N/A
2208 */
2209 void woal_free_moal_handle(moal_handle *handle)
2210 {
2211 moal_handle *ref_handle = NULL;
2212
2213 ENTER();
2214 if (!handle) {
2215 PRINTM(MERROR, "The handle is NULL\n");
2216 LEAVE();
2217 return;
2218 }
2219 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
2220 /* Unregister wiphy device and free */
2221 if (handle->wiphy) {
2222 wiphy_unregister(handle->wiphy);
2223 woal_cfg80211_free_bands(handle->wiphy);
2224 wiphy_free(handle->wiphy);
2225 handle->wiphy = NULL;
2226 }
2227 #endif
2228
2229 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
2230 if ((handle->nl_sk) && ((handle->nl_sk)->sk_socket)) {
2231 sock_release((handle->nl_sk)->sk_socket);
2232 handle->nl_sk = NULL;
2233 }
2234 #else
2235 netlink_kernel_release(handle->nl_sk);
2236 #endif
2237
2238 if (handle->pmlan_adapter) {
2239 mlan_unregister(handle->pmlan_adapter);
2240 handle->pmlan_adapter = NULL;
2241 }
2242
2243 /* Free BSS attribute table */
2244 kfree(handle->drv_mode.bss_attr);
2245 handle->drv_mode.bss_attr = NULL;
2246 PRINTM(MINFO, "Free Adapter\n");
2247 if (atomic_read(&handle->lock_count) ||
2248 atomic_read(&handle->malloc_count) ||
2249 atomic_read(&handle->mbufalloc_count)) {
2250 PRINTM(MERROR,
2251 "mlan has memory leak: lock_count=%d, malloc_count=%d, mbufalloc_count=%d\n",
2252 atomic_read(&handle->lock_count),
2253 atomic_read(&handle->malloc_count),
2254 atomic_read(&handle->mbufalloc_count));
2255 }
2256 #ifdef PCIE
2257 if (IS_PCIE(handle->card_type) &&
2258 atomic_read(&handle->malloc_cons_count)) {
2259 PRINTM(MERROR, "mlan has memory leak: malloc_cons_count=%d\n",
2260 atomic_read(&handle->malloc_cons_count));
2261 }
2262 #endif
2263
2264 /* Free allocated memory for fwdump filename */
2265 kfree(handle->fwdump_fname);
2266 if (fwdump_fname) {
2267 kfree(fwdump_fname);
2268 fwdump_fname = NULL;
2269 }
2270 /* Free module params */
2271 woal_free_module_param(handle);
2272 /** clear pref_mac to avoid later crash */
2273 if (handle->pref_mac) {
2274 ref_handle = (moal_handle *)handle->pref_mac;
2275 if (ref_handle->pref_mac && (ref_handle->pref_mac == handle))
2276 ref_handle->pref_mac = NULL;
2277 }
2278 /* Free the moal handle itself */
2279 kfree(handle);
2280 LEAVE();
2281 }
2282
2283 /**
2284 * @brief WOAL get one line data from ASCII format data
2285 *
2286 * @param data Source data
2287 * @param size Source data length
2288 * @param line_pos Destination data
2289 * @return routnine status
2290 */
2291 static t_size parse_cfg_get_line(t_u8 *data, t_size size, t_u8 *line_pos)
2292 {
2293 t_u8 *src, *dest;
2294 static t_s32 pos;
2295
2296 ENTER();
2297
2298 if (pos >= (t_s32)size) { /* reach the end */
2299 pos = 0; /* Reset position for rfkill */
2300 LEAVE();
2301 return -1;
2302 }
2303 memset(line_pos, 0, MAX_LINE_LEN);
2304 src = data + pos;
2305 dest = line_pos;
2306
2307 while ((dest - line_pos < MAX_LINE_LEN - 1) && pos < (t_s32)size &&
2308 *src != '\x0A' && *src != '\0') {
2309 if (*src != ' ' && *src != '\t') /* parse space */
2310 *dest++ = *src++;
2311 else
2312 src++;
2313 pos++;
2314 }
2315 /* parse new line */
2316 pos++;
2317 *dest = '\0';
2318 LEAVE();
2319 return strlen(line_pos);
2320 }
2321
2322 /**
2323 * @brief Process register access request
2324 * @param type_string String format Register type
2325 * @param offset_string String format Register offset
2326 * @param value_string String format Pointer to value
2327 * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
2328 */
2329 static t_u32 woal_process_regrdwr(moal_handle *handle, t_u8 *type_string,
2330 t_u8 *offset_string, t_u8 *value_string)
2331 {
2332 mlan_status ret = MLAN_STATUS_FAILURE;
2333 int type, offset, value;
2334 pmlan_ioctl_req ioctl_req = NULL;
2335 mlan_ds_reg_mem *reg = NULL;
2336
2337 ENTER();
2338
2339 /* Alloc ioctl_req */
2340 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
2341
2342 if (ioctl_req == NULL) {
2343 PRINTM(MERROR, "Can't alloc memory\n");
2344 goto done;
2345 }
2346
2347 if (MLAN_STATUS_SUCCESS != woal_atoi(&type, type_string))
2348 goto done;
2349 if (MLAN_STATUS_SUCCESS != woal_atoi(&offset, offset_string))
2350 goto done;
2351 if (MLAN_STATUS_SUCCESS != woal_atoi(&value, value_string))
2352 goto done;
2353
2354 ioctl_req->req_id = MLAN_IOCTL_REG_MEM;
2355 ioctl_req->action = MLAN_ACT_SET;
2356
2357 reg = (mlan_ds_reg_mem *)ioctl_req->pbuf;
2358 reg->sub_command = MLAN_OID_REG_RW;
2359 if (type < 5) {
2360 reg->param.reg_rw.type = type;
2361 } else {
2362 PRINTM(MERROR, "Unsupported Type\n");
2363 goto done;
2364 }
2365 reg->param.reg_rw.offset = offset;
2366 reg->param.reg_rw.value = value;
2367
2368 /* request ioctl for STA */
2369 ret = woal_request_ioctl(handle->priv[0], ioctl_req, MOAL_IOCTL_WAIT);
2370 if (ret != MLAN_STATUS_SUCCESS)
2371 goto done;
2372 PRINTM(MINFO, "Register type: %d, offset: 0x%x, value: 0x%x\n", type,
2373 offset, value);
2374 ret = MLAN_STATUS_SUCCESS;
2375
2376 done:
2377 if (ret != MLAN_STATUS_PENDING)
2378 kfree(ioctl_req);
2379 LEAVE();
2380 return ret;
2381 }
2382
2383 #if defined(SDIO)
2384 /**
2385 * @brief Read/Write registers value
2386 *
2387 * @param priv A pointer to moal_private structure
2388 * @param action get / set action
2389 * @param type type of register
2390 * @param offset offset of register
2391 * @param value value of registere
2392 *
2393 * @return 0 --success, otherwise fail
2394 */
2395 static int woal_getset_regrdwr(moal_private *priv, t_u32 action, t_u32 type,
2396 t_u32 offset, t_u32 *value)
2397 {
2398 int ret = 0;
2399 mlan_ioctl_req *req = NULL;
2400 mlan_ds_reg_mem *reg_mem = NULL;
2401 mlan_status status = MLAN_STATUS_SUCCESS;
2402
2403 ENTER();
2404
2405 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
2406 if (req == NULL) {
2407 ret = -ENOMEM;
2408 goto done;
2409 }
2410
2411 reg_mem = (mlan_ds_reg_mem *)req->pbuf;
2412 reg_mem->sub_command = MLAN_OID_REG_RW;
2413 req->req_id = MLAN_IOCTL_REG_MEM;
2414 req->action = action;
2415
2416 reg_mem->param.reg_rw.type = type;
2417 reg_mem->param.reg_rw.offset = offset;
2418 if (req->action == MLAN_ACT_SET)
2419 reg_mem->param.reg_rw.value = *value;
2420
2421 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2422 if (status != MLAN_STATUS_SUCCESS) {
2423 ret = -EFAULT;
2424 goto done;
2425 }
2426
2427 *value = reg_mem->param.reg_rw.value;
2428 PRINTM(MINFO, "woal_getset_regrdwr value=%x\n", *value);
2429
2430 done:
2431 if (status != MLAN_STATUS_PENDING)
2432 kfree(req);
2433 LEAVE();
2434 return ret;
2435 }
2436
2437 /**
2438 * @brief set slew rate mode
2439 *
2440 * @param handle MOAL handle
2441 * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
2442 */
2443 static t_u32 woal_set_sdio_slew_rate(moal_handle *handle)
2444 {
2445 t_u32 value = 0;
2446 mlan_status ret = MLAN_STATUS_SUCCESS;
2447 moal_private *priv = NULL;
2448 t_u32 new_value = 0;
2449 t_u32 reg_type = MLAN_REG_MAC;
2450
2451 priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
2452 if (!priv)
2453 return MLAN_STATUS_FAILURE;
2454
2455 if ((handle->card_info->slew_rate_reg != 0) &&
2456 (handle->params.slew_rate > 3 || handle->params.slew_rate < 0))
2457 return MLAN_STATUS_FAILURE;
2458 #if defined(SD9098) || defined(SD9097) || defined(SDNW62X) || defined(SD9177)
2459 if (IS_SD9098(handle->card_type) || IS_SD9097(handle->card_type) ||
2460 IS_SDNW62X(handle->card_type) || IS_SD9177(handle->card_type))
2461 reg_type = MLAN_REG_CIU;
2462 #endif
2463
2464 ret = woal_getset_regrdwr(priv, MLAN_ACT_GET, reg_type,
2465 handle->card_info->slew_rate_reg, &value);
2466 if (ret < 0) {
2467 PRINTM(MERROR, "woal_getset_regrdwr get REG_MAC failed\n");
2468 ret = MLAN_STATUS_FAILURE;
2469 goto done;
2470 }
2471 new_value = value & ~(0x3 << handle->card_info->slew_rate_bit_offset);
2472 new_value |= (t_u32)handle->params.slew_rate
2473 << handle->card_info->slew_rate_bit_offset;
2474
2475 if (value != new_value) {
2476 PRINTM(MMSG, "Set REG 0x%8x: 0x%x slew_rate=%d\n",
2477 handle->card_info->slew_rate_reg, new_value,
2478 handle->params.slew_rate);
2479 ret = woal_getset_regrdwr(priv, MLAN_ACT_SET, reg_type,
2480 handle->card_info->slew_rate_reg,
2481 &new_value);
2482 if (ret < 0) {
2483 PRINTM(MERROR,
2484 "woal_getset_regrdwr get REG_MAC failed\n");
2485 ret = MLAN_STATUS_FAILURE;
2486 }
2487 }
2488 done:
2489 return ret;
2490 }
2491 #endif /* SDIO */
2492
2493 #ifdef UAP_SUPPORT
2494 /**
2495 * @brief set uap operation contrl value
2496 *
2497 * @param handle MOAL handle
2498 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2499 */
2500 static mlan_status woal_set_uap_operation_ctrl(moal_handle *handle)
2501 {
2502 mlan_status ret = MLAN_STATUS_SUCCESS;
2503 moal_private *priv = NULL;
2504 mlan_ds_bss *bss = NULL;
2505 mlan_ioctl_req *req = NULL;
2506 int uap_oper_ctrl;
2507
2508 ENTER();
2509
2510 priv = woal_get_priv(handle, MLAN_BSS_ROLE_UAP);
2511 if (!priv) {
2512 PRINTM(MERROR,
2513 "woal_set_uap_operation_ctrl failed, no uap interface\n");
2514 LEAVE();
2515 return ret;
2516 }
2517 uap_oper_ctrl = handle->params.uap_oper_ctrl;
2518 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
2519 if (req == NULL) {
2520 ret = MLAN_STATUS_FAILURE;
2521 goto done;
2522 }
2523
2524 bss = (mlan_ds_bss *)req->pbuf;
2525 bss->sub_command = MLAN_OID_UAP_OPER_CTRL;
2526 req->req_id = MLAN_IOCTL_BSS;
2527 req->action = MLAN_ACT_SET;
2528
2529 bss->param.ap_oper_ctrl.ctrl_value =
2530 (t_u16)((uap_oper_ctrl & 0xffff0000) >> 16);
2531 bss->param.ap_oper_ctrl.chan_opt = (t_u16)(uap_oper_ctrl & 0xffff);
2532 PRINTM(MMSG, "Uap oper_ctrl=0x%x chan_opt=0x%x\n",
2533 bss->param.ap_oper_ctrl.ctrl_value,
2534 bss->param.ap_oper_ctrl.chan_opt);
2535 ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2536
2537 done:
2538 if (ret != MLAN_STATUS_PENDING)
2539 kfree(req);
2540
2541 LEAVE();
2542 return ret;
2543 }
2544 #endif
2545
2546 /**
2547 * @brief WOAL parse ASCII format data to MAC address
2548 *
2549 * @param handle MOAL handle
2550 * @param data Source data
2551 * @param size data length
2552 * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
2553 */
2554 static t_u32 woal_process_init_cfg(moal_handle *handle, t_u8 *data, t_size size)
2555 {
2556 mlan_status ret = MLAN_STATUS_FAILURE;
2557 t_u8 *pos;
2558 t_u8 *intf_s, *intf_e;
2559 t_u8 s[MAX_LINE_LEN]; /* 1 line data */
2560 t_size line_len;
2561 t_u8 index = 0;
2562 t_u32 i;
2563 t_u8 bss_mac_addr[MAX_MAC_ADDR_LEN];
2564 t_u8 bss_mac_name[MAX_PARAM_LEN];
2565 t_u8 type[MAX_PARAM_LEN];
2566 t_u8 offset[MAX_PARAM_LEN];
2567 t_u8 value[MAX_PARAM_LEN];
2568
2569 ENTER();
2570
2571 while ((int)(line_len = parse_cfg_get_line(data, size, s)) != -1) {
2572 pos = s;
2573 while (*pos == ' ' || *pos == '\t')
2574 pos++;
2575
2576 if (*pos == '#' || (*pos == '\r' && *(pos + 1) == '\n') ||
2577 *pos == '\n' || *pos == '\0')
2578 continue; /* Needn't process this line */
2579
2580 /* Process MAC addr */
2581 if (strncmp(pos, "mac_addr", 8) == 0) {
2582 intf_s = strchr(pos, '=');
2583 if (intf_s != NULL)
2584 intf_e = strchr(intf_s, ':');
2585 else
2586 intf_e = NULL;
2587 if (intf_s != NULL && intf_e != NULL) {
2588 strncpy(bss_mac_addr, intf_e + 1,
2589 MAX_MAC_ADDR_LEN - 1);
2590 bss_mac_addr[MAX_MAC_ADDR_LEN - 1] = '\0';
2591 if ((intf_e - intf_s) > MAX_PARAM_LEN) {
2592 PRINTM(MERROR,
2593 "Too long interface name %d\n",
2594 __LINE__);
2595 goto done;
2596 }
2597 strncpy(bss_mac_name, intf_s + 1,
2598 intf_e - intf_s - 1);
2599 bss_mac_name[intf_e - intf_s - 1] = '\0';
2600 for (i = 0; i < handle->priv_num; i++) {
2601 if (strcmp(bss_mac_name,
2602 handle->priv[i]
2603 ->netdev->name) ==
2604 0) {
2605 memset(handle->priv[i]
2606 ->current_addr,
2607 0, ETH_ALEN);
2608 PRINTM(MINFO,
2609 "Interface name: %s mac: %s\n",
2610 bss_mac_name,
2611 bss_mac_addr);
2612 woal_mac2u8(
2613 handle->priv[i]
2614 ->current_addr,
2615 bss_mac_addr);
2616 #ifdef WIFI_DIRECT_SUPPORT
2617 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
2618 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
2619 if (handle->priv[i]->bss_type ==
2620 MLAN_BSS_TYPE_WIFIDIRECT) {
2621 handle->priv[i]
2622 ->current_addr[0] |=
2623 0x02;
2624 PRINTM(MCMND,
2625 "Set WFD device addr: " MACSTR
2626 "\n",
2627 MAC2STR(handle->priv[i]
2628 ->current_addr));
2629 }
2630 #endif
2631 #endif
2632 #endif
2633 /* Set WLAN MAC addresses */
2634 if (MLAN_STATUS_SUCCESS !=
2635 woal_request_set_mac_address(
2636 handle->priv[i],
2637 MOAL_IOCTL_WAIT)) {
2638 PRINTM(MERROR,
2639 "Set MAC address failed\n");
2640 goto done;
2641 }
2642 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
2643 eth_hw_addr_set(
2644 handle->priv[i]->netdev,
2645 handle->priv[i]
2646 ->current_addr);
2647 #else
2648 moal_memcpy_ext(
2649 handle,
2650 handle->priv[i]
2651 ->netdev
2652 ->dev_addr,
2653 handle->priv[i]
2654 ->current_addr,
2655 ETH_ALEN, ETH_ALEN);
2656 #endif
2657 index++; /* Mark found one
2658 interface matching
2659 */
2660 }
2661 }
2662 } else {
2663 PRINTM(MERROR, "Wrong config file format %d\n",
2664 __LINE__);
2665 goto done;
2666 }
2667 }
2668 /* Process REG value */
2669 else if (strncmp(pos, "wlan_reg", 8) == 0) {
2670 intf_s = strchr(pos, '=');
2671 if (intf_s != NULL)
2672 intf_e = strchr(intf_s, ',');
2673 else
2674 intf_e = NULL;
2675 if (intf_s != NULL && intf_e != NULL) {
2676 /* Copy type */
2677 strncpy(type, intf_s + 1, 1);
2678 type[1] = '\0';
2679 } else {
2680 PRINTM(MERROR, "Wrong config file format %d\n",
2681 __LINE__);
2682 goto done;
2683 }
2684 intf_s = intf_e + 1;
2685 intf_e = strchr(intf_s, ',');
2686 if (intf_e != NULL) {
2687 if ((intf_e - intf_s) >= MAX_PARAM_LEN) {
2688 PRINTM(MERROR,
2689 "Regsier offset is too long %d\n",
2690 __LINE__);
2691 goto done;
2692 }
2693 /* Copy offset */
2694 strncpy(offset, intf_s, intf_e - intf_s);
2695 offset[intf_e - intf_s] = '\0';
2696 } else {
2697 PRINTM(MERROR, "Wrong config file format %d\n",
2698 __LINE__);
2699 goto done;
2700 }
2701 intf_s = intf_e + 1;
2702 if ((strlen(intf_s) >= MAX_PARAM_LEN)) {
2703 PRINTM(MERROR, "Regsier value is too long %d\n",
2704 __LINE__);
2705 goto done;
2706 }
2707 /* Copy value */
2708 memcpy(value, intf_s,
2709 MIN((MAX_PARAM_LEN - 1), strlen(intf_s)));
2710
2711 if (MLAN_STATUS_SUCCESS !=
2712 woal_process_regrdwr(handle, type, offset, value)) {
2713 PRINTM(MERROR, "Access Reg failed\n");
2714 goto done;
2715 }
2716 PRINTM(MINFO, "Reg type: %s, offset: %s, value: %s\n",
2717 type, offset, value);
2718 }
2719 }
2720
2721 if (index == 0)
2722 PRINTM(MINFO, "Can't find any matching MAC Address");
2723 ret = MLAN_STATUS_SUCCESS;
2724
2725 done:
2726 LEAVE();
2727 return ret;
2728 }
2729
2730 /**
2731 * @brief WOAL parse ASCII format raw data to hex format
2732 *
2733 * @param handle MOAL handle
2734 * @param data Source data
2735 * @param size data length
2736 * @param wait_option wait option
2737 * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
2738 */
2739 static mlan_status woal_process_hostcmd_cfg(moal_handle *handle, t_u8 *data,
2740 t_size size, t_u8 wait_option)
2741 {
2742 mlan_status ret = MLAN_STATUS_SUCCESS;
2743 t_u8 *pos = data;
2744 t_u8 *intf_s, *intf_e;
2745 t_u8 *buf = NULL;
2746 t_u8 *ptr = NULL;
2747 t_u32 cmd_len = 0;
2748 t_u8 start_raw = MFALSE;
2749 gfp_t flag;
2750
2751 #define CMD_STR "MRVL_CMDhostcmd"
2752 #define CMD_BUF_LEN 2048
2753
2754 ENTER();
2755 flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
2756 buf = kzalloc(CMD_BUF_LEN, flag);
2757 if (!buf) {
2758 PRINTM(MERROR, "Could not allocate buffer space!\n");
2759 ret = MLAN_STATUS_FAILURE;
2760 goto done;
2761 }
2762 ptr = buf;
2763 strcpy(ptr, CMD_STR);
2764 ptr = buf + strlen(CMD_STR) + sizeof(t_u32);
2765 while ((pos - data) < size) {
2766 while (*pos == ' ' || *pos == '\t')
2767 pos++;
2768 if (*pos == '#') { /* Line comment */
2769 while (*pos != '\n')
2770 pos++;
2771 pos++;
2772 }
2773 if ((*pos == '\r' && *(pos + 1) == '\n') || *pos == '\n' ||
2774 *pos == '\0') {
2775 pos++;
2776 continue; /* Needn't process this line */
2777 }
2778
2779 if (*pos == '}') {
2780 cmd_len = *((t_u16 *)(buf + strlen(CMD_STR) +
2781 sizeof(t_u32) + sizeof(t_u16)));
2782 moal_memcpy_ext(handle, buf + strlen(CMD_STR), &cmd_len,
2783 sizeof(t_u32),
2784 CMD_BUF_LEN - strlen(CMD_STR));
2785
2786 /* fire the hostcommand from here */
2787 woal_priv_hostcmd(handle->priv[0], buf, CMD_BUF_LEN,
2788 wait_option);
2789 memset(buf + strlen(CMD_STR), 0,
2790 CMD_BUF_LEN - strlen(CMD_STR));
2791 ptr = buf + strlen(CMD_STR) + sizeof(t_u32);
2792 start_raw = MFALSE;
2793 pos++;
2794 continue;
2795 }
2796
2797 if (start_raw == MFALSE) {
2798 intf_s = strchr(pos, '=');
2799 if (intf_s)
2800 intf_e = strchr(intf_s, '{');
2801 else
2802 intf_e = NULL;
2803
2804 if (intf_s && intf_e) {
2805 start_raw = MTRUE;
2806 pos = intf_e + 1;
2807 continue;
2808 }
2809 }
2810
2811 if (start_raw) {
2812 /* Raw data block exists */
2813 while (*pos != '\n') {
2814 if ((*pos <= 'f' && *pos >= 'a') ||
2815 (*pos <= 'F' && *pos >= 'A') ||
2816 (*pos <= '9' && *pos >= '0')) {
2817 *ptr++ = woal_atox(pos);
2818 pos += 2;
2819 } else
2820 pos++;
2821 }
2822 }
2823 }
2824
2825 done:
2826 kfree(buf);
2827 LEAVE();
2828 return ret;
2829 }
2830 #define INIT_CFG_DATA 0x00
2831 #define INIT_HOSTCMD_CFG_DATA 0x02
2832 #define COUNTRY_POWER_TABLE 0x04
2833 #define BAND_STEER_CFG_DATA 0x08
2834
2835 /**
2836 * @brief Request init conf firmware callback
2837 * This function is invoked by request_firmware_nowait system call
2838 *
2839 * @param firmware A pointer to firmware image
2840 * @param context A pointer to moal_handle structure
2841 *
2842 * @return N/A
2843 */
2844 static void
2845 woal_request_init_user_conf_callback(const struct firmware *firmware,
2846 void *context)
2847 {
2848 moal_handle *handle;
2849
2850 ENTER();
2851
2852 handle = (moal_handle *)context;
2853 if (!handle) {
2854 LEAVE();
2855 return;
2856 }
2857 if (firmware)
2858 handle->user_data = firmware;
2859 else
2860 PRINTM(MERROR, "User init config request firmware failed\n");
2861
2862 handle->init_user_conf_wait_flag = MTRUE;
2863 wake_up_interruptible(&handle->init_user_conf_wait_q);
2864
2865 LEAVE();
2866 return;
2867 }
2868
2869 /**
2870 * @brief Request init conf firmware callback
2871 * This function is invoked by request_firmware_nowait system call
2872 *
2873 * @param firmware A pointer to firmware image
2874 * @param context A pointer to moal_handle structure
2875 *
2876 * @return N/A
2877 */
2878 static void woal_request_init_dpd_conf_callback(const struct firmware *firmware,
2879 void *context)
2880 {
2881 moal_handle *handle;
2882
2883 ENTER();
2884
2885 handle = (moal_handle *)context;
2886 if (!handle) {
2887 LEAVE();
2888 return;
2889 }
2890 if (firmware && handle)
2891 handle->dpd_data = firmware;
2892 else
2893 PRINTM(MERROR, "User init cfg data request firmware failed\n");
2894
2895 handle->init_user_conf_wait_flag = MTRUE;
2896 wake_up_interruptible(&handle->init_user_conf_wait_q);
2897
2898 LEAVE();
2899 return;
2900 }
2901
2902 /**
2903 * @brief Request init conf firmware callback
2904 * This function is invoked by request_firmware_nowait system call
2905 *
2906 * @param firmware A pointer to firmware image
2907 * @param context A pointer to moal_handle structure
2908 *
2909 * @return N/A
2910 */
2911 static void woal_request_vdll_fw_callback(const struct firmware *firmware,
2912 void *context)
2913 {
2914 moal_handle *handle;
2915
2916 ENTER();
2917
2918 handle = (moal_handle *)context;
2919 if (!handle) {
2920 LEAVE();
2921 return;
2922 }
2923 if (firmware && handle)
2924 handle->firmware = firmware;
2925 else
2926 PRINTM(MERROR, "VDLL: Request firmware failed\n");
2927
2928 handle->init_user_conf_wait_flag = MTRUE;
2929 wake_up_interruptible(&handle->init_user_conf_wait_q);
2930
2931 LEAVE();
2932 return;
2933 }
2934
2935 /**
2936 * @brief Request firmware image for VDLL
2937 *
2938 * @param handle A pointer to moal_handle structure
2939 *
2940 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2941 */
2942 mlan_status woal_vdll_req_fw(moal_handle *handle)
2943 {
2944 int ret = MLAN_STATUS_SUCCESS;
2945 t_u8 req_fw_nowait = moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT);
2946 char *vdll_fw = handle->drv_mode.fw_name;
2947
2948 ENTER();
2949 if (vdll_fw) {
2950 PRINTM(MMSG, "VDLL: Request firmware: %s\n", vdll_fw);
2951 if (req_fw_nowait) {
2952 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
2953 if ((request_firmware_nowait(
2954 THIS_MODULE, FW_ACTION_UEVENT, vdll_fw,
2955 handle->hotplug_device, GFP_KERNEL, handle,
2956 woal_request_vdll_fw_callback)) < 0) {
2957 #else
2958 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
2959 if ((request_firmware_nowait(
2960 THIS_MODULE, FW_ACTION_HOTPLUG, vdll_fw,
2961 handle->hotplug_device, GFP_KERNEL, handle,
2962 woal_request_vdll_fw_callback)) < 0) {
2963 #else
2964 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
2965 if ((request_firmware_nowait(
2966 THIS_MODULE, FW_ACTION_HOTPLUG, vdll_fw,
2967 handle->hotplug_device, handle,
2968 woal_request_vdll_fw_callback)) < 0) {
2969 #else
2970 if ((request_firmware_nowait(
2971 THIS_MODULE, vdll_fw,
2972 handle->hotplug_device, handle,
2973 woal_request_vdll_fw_callback)) < 0) {
2974 #endif
2975 #endif
2976 #endif
2977 PRINTM(MERROR,
2978 "VDLL: request_firmware_nowait() failed\n");
2979 ret = MLAN_STATUS_FAILURE;
2980 goto done;
2981 }
2982 handle->init_user_conf_wait_flag = MFALSE;
2983 wait_event_interruptible(
2984 handle->init_user_conf_wait_q,
2985 handle->init_user_conf_wait_flag);
2986 } else {
2987 if ((request_firmware(&handle->firmware, vdll_fw,
2988 handle->hotplug_device)) < 0) {
2989 PRINTM(MERROR,
2990 "VDLL: request_firmware() failed\n");
2991 ret = MLAN_STATUS_FAILURE;
2992 goto done;
2993 }
2994 }
2995 }
2996 done:
2997 LEAVE();
2998 return ret;
2999 }
3000
3001 /**
3002 * @brief Request init conf firmware callback
3003 * This function is invoked by request_firmware_nowait system call
3004 *
3005 * @param firmware A pointer to firmware image
3006 * @param context A pointer to moal_handle structure
3007 *
3008 * @return N/A
3009 */
3010 static void
3011 woal_request_init_txpwr_conf_callback(const struct firmware *firmware,
3012 void *context)
3013 {
3014 moal_handle *handle;
3015
3016 ENTER();
3017
3018 handle = (moal_handle *)context;
3019 if (!handle) {
3020 LEAVE();
3021 return;
3022 }
3023 if (firmware && handle)
3024 handle->txpwr_data = firmware;
3025 else
3026 PRINTM(MERROR, "User init cfg data request firmware failed\n");
3027
3028 handle->init_user_conf_wait_flag = MTRUE;
3029 wake_up_interruptible(&handle->init_user_conf_wait_q);
3030
3031 LEAVE();
3032 return;
3033 }
3034
3035 /**
3036 * @brief Request init conf firmware callback
3037 * This function is invoked by request_firmware_nowait system call
3038 *
3039 * @param firmware A pointer to firmware image
3040 * @param context A pointer to moal_handle structure
3041 *
3042 * @return N/A
3043 */
3044 static void woal_request_init_cfg_data_callback(const struct firmware *firmware,
3045 void *context)
3046 {
3047 moal_handle *handle;
3048
3049 ENTER();
3050
3051 handle = (moal_handle *)context;
3052 if (!handle) {
3053 LEAVE();
3054 return;
3055 }
3056 if (firmware && handle)
3057 handle->init_cfg_data = firmware;
3058 else
3059 PRINTM(MERROR, "User init cfg data request firmware failed\n");
3060
3061 handle->init_user_conf_wait_flag = MTRUE;
3062 wake_up_interruptible(&handle->init_user_conf_wait_q);
3063
3064 LEAVE();
3065 return;
3066 }
3067
3068 /**
3069 * @brief WOAL set user defined init data and param
3070 *
3071 * @param handle MOAL handle structure
3072 * @param type type argument
3073 * @param wait_option wait option
3074 * @param country_txpwrlimit Configure Tx Power Limit
3075 * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
3076 */
3077 static t_u32 woal_set_user_init_data(moal_handle *handle, int type,
3078 t_u8 wait_option, char *country_txpwrlimit)
3079 {
3080 mlan_status ret = MLAN_STATUS_FAILURE;
3081 t_u8 *cfg_data = NULL;
3082 t_size len;
3083 t_u8 req_fw_nowait = moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT);
3084 char *init_cfg = handle->params.init_cfg;
3085 char *init_hostcmd_cfg = handle->params.init_hostcmd_cfg;
3086 char *band_steer_cfg = handle->params.band_steer_cfg;
3087
3088 ENTER();
3089
3090 if (type == INIT_CFG_DATA) {
3091 PRINTM(MMSG, "Request firmware: %s\n", init_cfg);
3092 if (req_fw_nowait) {
3093 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
3094 if ((request_firmware_nowait(
3095 THIS_MODULE, FW_ACTION_UEVENT, init_cfg,
3096 handle->hotplug_device, GFP_KERNEL, handle,
3097 woal_request_init_cfg_data_callback)) < 0) {
3098 #else
3099 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
3100 if ((request_firmware_nowait(
3101 THIS_MODULE, FW_ACTION_HOTPLUG, init_cfg,
3102 handle->hotplug_device, GFP_KERNEL, handle,
3103 woal_request_init_cfg_data_callback)) < 0) {
3104 #else
3105 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
3106 if ((request_firmware_nowait(
3107 THIS_MODULE, FW_ACTION_HOTPLUG, init_cfg,
3108 handle->hotplug_device, handle,
3109 woal_request_init_cfg_data_callback)) < 0) {
3110 #else
3111 if ((request_firmware_nowait(
3112 THIS_MODULE, init_cfg,
3113 handle->hotplug_device, handle,
3114 woal_request_init_cfg_data_callback)) < 0) {
3115 #endif
3116 #endif
3117 #endif
3118 PRINTM(MERROR,
3119 "Init config file request_firmware_nowait() failed\n");
3120 goto done;
3121 }
3122 handle->init_user_conf_wait_flag = MFALSE;
3123 wait_event_interruptible(
3124 handle->init_user_conf_wait_q,
3125 handle->init_user_conf_wait_flag);
3126 } else {
3127 if ((request_firmware(&handle->init_cfg_data, init_cfg,
3128 handle->hotplug_device)) < 0) {
3129 PRINTM(MERROR,
3130 "Init config file request_firmware() failed\n");
3131 goto done;
3132 }
3133 }
3134 } else if (type == COUNTRY_POWER_TABLE) {
3135 if (country_txpwrlimit == NULL) {
3136 PRINTM(MERROR,
3137 "The parameter 'country_txpwrlimit' is NULL\n");
3138 ret = MLAN_STATUS_FAILURE;
3139 goto done;
3140 }
3141 PRINTM(MMSG, "Request firmware: %s\n", country_txpwrlimit);
3142 /* 'country_txpwrlimit' holds the value of Configured Tx Power
3143 * Limit */
3144 if (req_fw_nowait) {
3145 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
3146 if ((request_firmware_nowait(
3147 THIS_MODULE, FW_ACTION_UEVENT,
3148 country_txpwrlimit, handle->hotplug_device,
3149 GFP_KERNEL, handle,
3150 woal_request_init_user_conf_callback)) <
3151 0) {
3152 #else
3153 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
3154 if ((request_firmware_nowait(
3155 THIS_MODULE, FW_ACTION_HOTPLUG,
3156 country_txpwrlimit, handle->hotplug_device,
3157 GFP_KERNEL, handle,
3158 woal_request_init_user_conf_callback)) <
3159 0) {
3160 #else
3161 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
3162 if ((request_firmware_nowait(
3163 THIS_MODULE, FW_ACTION_HOTPLUG,
3164 country_txpwrlimit, handle->hotplug_device,
3165 handle,
3166 woal_request_init_user_conf_callback)) <
3167 0) {
3168 #else
3169 if ((request_firmware_nowait(
3170 THIS_MODULE, country_txpwrlimit,
3171 handle->hotplug_device, handle,
3172 woal_request_init_user_conf_callback)) <
3173 0) {
3174 #endif
3175 #endif
3176 #endif
3177 PRINTM(MERROR,
3178 "country txpwrlimit config file request_firmware_nowait() failed\n");
3179 goto done;
3180 }
3181 handle->init_user_conf_wait_flag = MFALSE;
3182 wait_event_interruptible(
3183 handle->init_user_conf_wait_q,
3184 handle->init_user_conf_wait_flag);
3185 } else {
3186 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
3187 int status =
3188 request_firmware_direct(&handle->user_data,
3189 country_txpwrlimit,
3190 handle->hotplug_device);
3191 #else
3192 int status = request_firmware(&handle->user_data,
3193 country_txpwrlimit,
3194 handle->hotplug_device);
3195 #endif
3196 /* File does not exist, skip download */
3197 if (status == -ENOENT) {
3198 ret = MLAN_STATUS_FILE_ERR;
3199 PRINTM(MIOCTL,
3200 "Country power table file does not exist\n");
3201 goto done;
3202 } else if (status) {
3203 PRINTM(MERROR,
3204 "country txpwrlimit config file request_firmware() failed\n");
3205 goto done;
3206 }
3207 }
3208 } else if (type == INIT_HOSTCMD_CFG_DATA) {
3209 PRINTM(MMSG, "Request firmware: %s\n", init_hostcmd_cfg);
3210 if (req_fw_nowait) {
3211 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
3212 if ((request_firmware_nowait(
3213 THIS_MODULE, FW_ACTION_UEVENT,
3214 init_hostcmd_cfg, handle->hotplug_device,
3215 GFP_KERNEL, handle,
3216 woal_request_init_user_conf_callback)) <
3217 0) {
3218 #else
3219 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
3220 if ((request_firmware_nowait(
3221 THIS_MODULE, FW_ACTION_HOTPLUG,
3222 init_hostcmd_cfg, handle->hotplug_device,
3223 GFP_KERNEL, handle,
3224 woal_request_init_user_conf_callback)) <
3225 0) {
3226 #else
3227 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
3228 if ((request_firmware_nowait(
3229 THIS_MODULE, FW_ACTION_HOTPLUG,
3230 init_hostcmd_cfg, handle->hotplug_device,
3231 handle,
3232 woal_request_init_user_conf_callback)) <
3233 0) {
3234 #else
3235 if ((request_firmware_nowait(
3236 THIS_MODULE, init_hostcmd_cfg,
3237 handle->hotplug_device, handle,
3238 woal_request_init_user_conf_callback)) <
3239 0) {
3240 #endif
3241 #endif
3242 #endif
3243 PRINTM(MERROR,
3244 "Init hostcmd config file request_firmware_nowait() failed\n");
3245 goto done;
3246 }
3247 handle->init_user_conf_wait_flag = MFALSE;
3248 wait_event_interruptible(
3249 handle->init_user_conf_wait_q,
3250 handle->init_user_conf_wait_flag);
3251 } else {
3252 if ((request_firmware(&handle->user_data,
3253 init_hostcmd_cfg,
3254 handle->hotplug_device)) < 0) {
3255 PRINTM(MERROR,
3256 "Init hostcmd config file request_firmware() failed\n");
3257 goto done;
3258 }
3259 }
3260 }
3261 if (type == BAND_STEER_CFG_DATA) {
3262 PRINTM(MMSG, "Request firmware: %s\n", band_steer_cfg);
3263 if (req_fw_nowait) {
3264 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
3265 if ((request_firmware_nowait(
3266 THIS_MODULE, FW_ACTION_UEVENT,
3267 band_steer_cfg, handle->hotplug_device,
3268 GFP_KERNEL, handle,
3269 woal_request_init_user_conf_callback)) <
3270 0) {
3271 #else
3272 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
3273 if ((request_firmware_nowait(
3274 THIS_MODULE, FW_ACTION_HOTPLUG,
3275 band_steer_cfg, handle->hotplug_device,
3276 GFP_KERNEL, handle,
3277 woal_request_init_user_conf_callback)) <
3278 0) {
3279 #else
3280 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
3281 if ((request_firmware_nowait(
3282 THIS_MODULE, FW_ACTION_HOTPLUG,
3283 band_steer_cfg, handle->hotplug_device,
3284 handle,
3285 woal_request_init_user_conf_callback)) <
3286 0) {
3287 #else
3288 if ((request_firmware_nowait(
3289 THIS_MODULE, band_steer_cfg,
3290 handle->hotplug_device, handle,
3291 woal_request_init_user_conf_callback)) <
3292 0) {
3293 #endif
3294 #endif
3295 #endif
3296 PRINTM(MERROR,
3297 "band_steer_cfg request_firmware_nowait() failed\n");
3298 goto done;
3299 }
3300 handle->init_user_conf_wait_flag = MFALSE;
3301 wait_event_interruptible(
3302 handle->init_user_conf_wait_q,
3303 handle->init_user_conf_wait_flag);
3304 } else {
3305 if ((request_firmware(&handle->user_data,
3306 band_steer_cfg,
3307 handle->hotplug_device)) < 0) {
3308 PRINTM(MERROR,
3309 "band_steer_cfg file request_firmware() failed\n");
3310 goto done;
3311 }
3312 }
3313 }
3314 if (handle->user_data) {
3315 cfg_data = (t_u8 *)(handle->user_data)->data;
3316 len = (handle->user_data)->size;
3317 if (type == INIT_HOSTCMD_CFG_DATA ||
3318 type == BAND_STEER_CFG_DATA ||
3319 type == COUNTRY_POWER_TABLE) {
3320 if (MLAN_STATUS_SUCCESS !=
3321 woal_process_hostcmd_cfg(handle, cfg_data, len,
3322 wait_option)) {
3323 PRINTM(MERROR,
3324 "Can't process hostcmd config file\n");
3325 goto done;
3326 }
3327 }
3328 ret = MLAN_STATUS_SUCCESS;
3329 } else if (type == INIT_CFG_DATA && handle->init_cfg_data) {
3330 PRINTM(MIOCTL, "Load init_cfg success\n");
3331 ret = MLAN_STATUS_SUCCESS;
3332 }
3333 done:
3334 if (handle->user_data) {
3335 release_firmware(handle->user_data);
3336 handle->user_data = NULL;
3337 }
3338
3339 LEAVE();
3340 return ret;
3341 }
3342
3343 static int woal_netdevice_event(struct notifier_block *nb, unsigned long event,
3344 void *ptr);
3345
3346 #ifdef UAP_SUPPORT
3347 /**
3348 * @brief Configure WACP Mode
3349 *
3350 * @param priv A pointer to moal_private structure
3351 * @param wait_option Wait option
3352 *
3353 * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
3354 * otherwise fail
3355 */
3356 mlan_status woal_set_wacp_mode(moal_private *priv, t_u8 wait_option)
3357 {
3358 // moal_private *priv = NULL;
3359 mlan_ioctl_req *req = NULL;
3360 mlan_ds_misc_cfg *pcfg_misc = NULL;
3361 mlan_status status;
3362
3363 ENTER();
3364
3365 /* Allocate an IOCTL request buffer */
3366 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3367 if (req == NULL) {
3368 status = MLAN_STATUS_FAILURE;
3369 goto done;
3370 }
3371
3372 /* Fill request buffer */
3373 pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
3374 pcfg_misc->sub_command = MLAN_OID_MISC_WACP_MODE;
3375 req->req_id = MLAN_IOCTL_MISC_CFG;
3376 req->action = MLAN_ACT_SET;
3377 pcfg_misc->param.wacp_mode = priv->phandle->params.wacp_mode;
3378
3379 /* Send IOCTL request to MLAN */
3380 status = woal_request_ioctl(priv, req, wait_option);
3381 done:
3382 if (status != MLAN_STATUS_PENDING)
3383 kfree(req);
3384 LEAVE();
3385 return status;
3386 }
3387 #endif
3388
3389 /**
3390 * @brief Configure aggrctrl
3391 *
3392 * @param priv A pointer to moal_private structure
3393 * @param wait_option Wait option
3394 *
3395 * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
3396 * otherwise fail
3397 */
3398 mlan_status woal_init_aggr_ctrl(moal_handle *handle, t_u8 wait_option)
3399 {
3400 moal_private *priv = NULL;
3401 mlan_ioctl_req *req = NULL;
3402 mlan_ds_misc_cfg *pcfg_misc = NULL;
3403 mlan_status status;
3404
3405 ENTER();
3406
3407 priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
3408 if (!priv) {
3409 LEAVE();
3410 return MLAN_STATUS_FAILURE;
3411 }
3412 /* Allocate an IOCTL request buffer */
3413 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3414 if (req == NULL) {
3415 status = MLAN_STATUS_FAILURE;
3416 goto done;
3417 }
3418
3419 /* Fill request buffer */
3420 pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
3421 pcfg_misc->sub_command = MLAN_OID_MISC_AGGR_CTRL;
3422 req->req_id = MLAN_IOCTL_MISC_CFG;
3423
3424 req->action = MLAN_ACT_SET;
3425 pcfg_misc->param.aggr_params.tx.enable = MTRUE;
3426
3427 /* Send IOCTL request to MLAN */
3428 status = woal_request_ioctl(priv, req, wait_option);
3429 done:
3430 if (status != MLAN_STATUS_PENDING)
3431 kfree(req);
3432 LEAVE();
3433 return status;
3434 }
3435
3436 /**
3437 * @brief Add interfaces DPC
3438 *
3439 * @param handle A pointer to moal_handle structure
3440 *
3441 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3442 */
3443 static mlan_status woal_add_card_dpc(moal_handle *handle)
3444 {
3445 mlan_status ret = MLAN_STATUS_SUCCESS;
3446 int i;
3447 char str_buf[MLAN_MAX_VER_STR_LEN];
3448
3449 ENTER();
3450
3451 #if defined(USB)
3452 if (IS_USB(handle->card_type) && handle->boot_state == USB_FW_DNLD) {
3453 /* Return now */
3454 LEAVE();
3455 return ret;
3456 }
3457 #endif /* USB_NEW_FW_DNLD */
3458
3459 #ifdef CONFIG_PROC_FS
3460 /* Initialize proc fs */
3461 woal_proc_init(handle);
3462 #endif /* CONFIG_PROC_FS */
3463
3464 /* Add interfaces */
3465 for (i = 0; i < handle->drv_mode.intf_num; i++) {
3466 if (handle->drv_mode.bss_attr[i].bss_virtual)
3467 continue;
3468 if (!woal_add_interface(handle, handle->priv_num,
3469 handle->drv_mode.bss_attr[i].bss_type)) {
3470 ret = MLAN_STATUS_FAILURE;
3471 goto err;
3472 }
3473 }
3474 woal_get_version(handle, str_buf, sizeof(str_buf) - 1);
3475 PRINTM(MMSG, "wlan: version = %s\n", str_buf);
3476
3477 handle->woal_notifier.notifier_call = woal_netdevice_event;
3478 if (register_inetaddr_notifier(&handle->woal_notifier)) {
3479 PRINTM(MFATAL,
3480 "Error registering register_inetaddr_notifier\n");
3481 goto err;
3482 }
3483 #ifdef MFG_CMD_SUPPORT
3484 if (handle->params.mfg_mode == MLAN_INIT_PARA_ENABLED)
3485 goto done;
3486 #endif
3487
3488 if (handle->params.init_cfg && handle->init_cfg_data) {
3489 if (MLAN_STATUS_SUCCESS !=
3490 woal_process_init_cfg(handle,
3491 (t_u8 *)(handle->init_cfg_data)->data,
3492 (handle->init_cfg_data)->size)) {
3493 PRINTM(MERROR, "Can't process init config file\n");
3494 ret = MLAN_STATUS_FAILURE;
3495 goto err;
3496 }
3497 }
3498
3499 if (moal_extflg_isset(handle, EXT_AGGR_CTRL)) {
3500 /* Enable aggregation in FW */
3501 if (woal_init_aggr_ctrl(handle, MOAL_IOCTL_WAIT)) {
3502 ret = MLAN_STATUS_FAILURE;
3503 goto err;
3504 }
3505 }
3506
3507 #ifdef USB
3508 if (handle->params.usb_aggr == 1) {
3509 /* Enable USB aggregation in FW */
3510 if (woal_usb_aggr_init(handle)) {
3511 ret = MLAN_STATUS_FAILURE;
3512 goto err;
3513 }
3514 }
3515 #endif
3516 /* Add low power mode check */
3517 if (moal_extflg_isset(handle, EXT_LOW_PW_MODE) &&
3518 handle->card_info->low_power_enable &&
3519 woal_set_low_pwr_mode(handle, MOAL_IOCTL_WAIT)) {
3520 /* Proceed with Warning */
3521 PRINTM(MERROR, "Unable to set Low Power Mode\n");
3522 }
3523
3524 /* Add channel tracking check */
3525 woal_set_chan_track_mode(handle, MOAL_IOCTL_WAIT);
3526
3527 #if defined(SDIO)
3528 if (IS_SD(handle->card_type))
3529 woal_set_sdio_slew_rate(handle);
3530 #endif
3531
3532 if (moal_extflg_isset(handle, EXT_PMIC) && handle->card_info->pmic) {
3533 if (MLAN_STATUS_SUCCESS !=
3534 woal_pmic_configure(handle, MOAL_IOCTL_WAIT)) {
3535 PRINTM(MFATAL, "Failed to configure PMIC\n");
3536 ret = MLAN_STATUS_FAILURE;
3537 goto err;
3538 }
3539 }
3540
3541 if (handle->params.antcfg) {
3542 if (MLAN_STATUS_SUCCESS !=
3543 woal_set_user_antcfg(handle, MOAL_IOCTL_WAIT)) {
3544 PRINTM(MFATAL, "Set user antcfg data failed\n");
3545 ret = MLAN_STATUS_FAILURE;
3546 goto err;
3547 }
3548 }
3549
3550 #ifdef UAP_SUPPORT
3551 if (handle->params.uap_oper_ctrl)
3552 woal_set_uap_operation_ctrl(handle);
3553 #endif
3554
3555 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
3556 #if IS_ENABLED(CONFIG_IPV6)
3557 handle->woal_inet6_notifier.notifier_call = woal_inet6_netdeive_event;
3558 if (register_inet6addr_notifier(&handle->woal_inet6_notifier)) {
3559 PRINTM(MFATAL,
3560 "Error registering register_inet6addr_notifier\n");
3561 goto err;
3562 }
3563 #endif
3564 #endif
3565
3566 #ifdef MFG_CMD_SUPPORT
3567 done:
3568 #endif
3569 err:
3570 if (handle->params.init_cfg && handle->init_cfg_data) {
3571 release_firmware(handle->init_cfg_data);
3572 handle->init_cfg_data = NULL;
3573 }
3574 if (ret != MLAN_STATUS_SUCCESS) {
3575 PRINTM(MERROR, "Failed to add interface\n");
3576 unregister_inetaddr_notifier(&handle->woal_notifier);
3577 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
3578 #if IS_ENABLED(CONFIG_IPV6)
3579 unregister_inet6addr_notifier(&handle->woal_inet6_notifier);
3580 #endif
3581 #endif
3582
3583 for (i = 0; i < MIN(MLAN_MAX_BSS_NUM, handle->priv_num); i++)
3584 woal_remove_interface(handle, i);
3585 handle->priv_num = 0;
3586 #ifdef CONFIG_PROC_FS
3587 woal_proc_exit(handle);
3588 #endif
3589 }
3590 LEAVE();
3591 return ret;
3592 }
3593
3594 /**
3595 * @brief Request dpd data
3596 *
3597 * @param handle A pointer to moal_handle structure
3598 *
3599 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3600 */
3601 static mlan_status woal_req_dpd_data(moal_handle *handle,
3602 mlan_init_param *param)
3603 {
3604 int ret = MLAN_STATUS_SUCCESS;
3605 t_u8 req_fw_nowait = moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT);
3606 char *dpd_data_cfg = handle->params.dpd_data_cfg;
3607 mlan_status status = MLAN_STATUS_SUCCESS;
3608
3609 ENTER();
3610
3611 if (dpd_data_cfg && strncmp(dpd_data_cfg, "none", strlen("none"))) {
3612 PRINTM(MMSG, "Request firmware: %s\n", dpd_data_cfg);
3613 if (req_fw_nowait) {
3614 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
3615 if ((request_firmware_nowait(
3616 THIS_MODULE, FW_ACTION_UEVENT, dpd_data_cfg,
3617 handle->hotplug_device, GFP_KERNEL, handle,
3618 woal_request_init_dpd_conf_callback)) < 0) {
3619 #else
3620 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
3621 if ((request_firmware_nowait(
3622 THIS_MODULE, FW_ACTION_HOTPLUG,
3623 dpd_data_cfg, handle->hotplug_device,
3624 GFP_KERNEL, handle,
3625 woal_request_init_dpd_conf_callback)) < 0) {
3626 #else
3627 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
3628 if ((request_firmware_nowait(
3629 THIS_MODULE, FW_ACTION_HOTPLUG,
3630 dpd_data_cfg, handle->hotplug_device,
3631 handle,
3632 woal_request_init_dpd_conf_callback)) < 0) {
3633 #else
3634 if ((request_firmware_nowait(
3635 THIS_MODULE, dpd_data_cfg,
3636 handle->hotplug_device, handle,
3637 woal_request_init_dpd_conf_callback)) < 0) {
3638 #endif
3639 #endif
3640 #endif
3641 PRINTM(MERROR,
3642 "DPD data request_firmware_nowait() failed\n");
3643 ret = MLAN_STATUS_FAILURE;
3644 goto done;
3645 }
3646 handle->init_user_conf_wait_flag = MFALSE;
3647 wait_event_interruptible(
3648 handle->init_user_conf_wait_q,
3649 handle->init_user_conf_wait_flag);
3650 } else {
3651 status = request_firmware(&handle->dpd_data,
3652 dpd_data_cfg,
3653 handle->hotplug_device);
3654 if (status < 0 && status != -ENOENT) {
3655 PRINTM(MERROR,
3656 "DPD data request_firmware() failed\n");
3657 ret = MLAN_STATUS_FAILURE;
3658 goto done;
3659 }
3660 }
3661 if (handle->dpd_data) {
3662 param->pdpd_data_buf = (t_u8 *)handle->dpd_data->data;
3663 param->dpd_data_len = handle->dpd_data->size;
3664 } else {
3665 param->dpd_data_len = UNKNOW_DPD_LENGTH;
3666 }
3667 }
3668
3669 done:
3670 LEAVE();
3671 return ret;
3672 }
3673
3674 /**
3675 * @brief Request TX Power data
3676 *
3677 * @param handle A pointer to moal_handle structure
3678 *
3679 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3680 */
3681 static mlan_status woal_req_txpwr_data(moal_handle *handle,
3682 mlan_init_param *param)
3683 {
3684 int ret = MLAN_STATUS_SUCCESS;
3685 t_u8 req_fw_nowait = moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT);
3686 char *txpwrlimit_cfg = handle->params.txpwrlimit_cfg;
3687
3688 ENTER();
3689
3690 if (txpwrlimit_cfg && strncmp(txpwrlimit_cfg, "none", strlen("none"))) {
3691 PRINTM(MMSG, "Download txpwrlimit_cfg=%s\n",
3692 handle->params.txpwrlimit_cfg);
3693 if (req_fw_nowait) {
3694 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
3695 if ((request_firmware_nowait(
3696 THIS_MODULE, FW_ACTION_UEVENT,
3697 txpwrlimit_cfg, handle->hotplug_device,
3698 GFP_KERNEL, handle,
3699 woal_request_init_txpwr_conf_callback)) <
3700 0) {
3701 #else
3702 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
3703 if ((request_firmware_nowait(
3704 THIS_MODULE, FW_ACTION_HOTPLUG,
3705 txpwrlimit_cfg, handle->hotplug_device,
3706 GFP_KERNEL, handle,
3707 woal_request_init_txpwr_conf_callback)) <
3708 0) {
3709 #else
3710 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
3711 if ((request_firmware_nowait(
3712 THIS_MODULE, FW_ACTION_HOTPLUG,
3713 txpwrlimit_cfg, handle->hotplug_device,
3714 handle,
3715 woal_request_init_txpwr_conf_callback)) <
3716 0) {
3717 #else
3718 if ((request_firmware_nowait(
3719 THIS_MODULE, txpwrlimit_cfg,
3720 handle->hotplug_device, handle,
3721 woal_request_init_txpwr_conf_callback)) <
3722 0) {
3723 #endif
3724 #endif
3725 #endif
3726 PRINTM(MERROR,
3727 "Region txpwrlimit cfg data "
3728 "request_firmware_nowait() failed\n");
3729 ret = MLAN_STATUS_FAILURE;
3730 goto done;
3731 }
3732 handle->init_user_conf_wait_flag = MFALSE;
3733 wait_event_interruptible(
3734 handle->init_user_conf_wait_q,
3735 handle->init_user_conf_wait_flag);
3736 } else {
3737 if ((request_firmware(&handle->txpwr_data,
3738 txpwrlimit_cfg,
3739 handle->hotplug_device)) < 0) {
3740 PRINTM(MERROR, "Region txpwrlimit cfg data "
3741 "request_firmware() failed\n");
3742 ret = MLAN_STATUS_FAILURE;
3743 goto done;
3744 }
3745 }
3746 if (handle->txpwr_data) {
3747 param->ptxpwr_data_buf =
3748 (t_u8 *)handle->txpwr_data->data;
3749 param->txpwr_data_len = handle->txpwr_data->size;
3750 }
3751 }
3752
3753 done:
3754 LEAVE();
3755 return ret;
3756 }
3757
3758 /**
3759 * @brief Request Cal data
3760 *
3761 * @param handle A pointer to moal_handle structure
3762 *
3763 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3764 */
3765 static mlan_status woal_req_cal_data(moal_handle *handle,
3766 mlan_init_param *param)
3767 {
3768 int ret = MLAN_STATUS_SUCCESS;
3769 t_u8 req_fw_nowait = moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT);
3770 char *cal_data_cfg = handle->params.cal_data_cfg;
3771
3772 ENTER();
3773 /** Cal data request */
3774 if (cal_data_cfg && strncmp(cal_data_cfg, "none", strlen("none"))) {
3775 PRINTM(MMSG, "Request firmware: %s\n", cal_data_cfg);
3776 if (req_fw_nowait) {
3777 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
3778 if ((request_firmware_nowait(
3779 THIS_MODULE, FW_ACTION_UEVENT, cal_data_cfg,
3780 handle->hotplug_device, GFP_KERNEL, handle,
3781 woal_request_init_user_conf_callback)) <
3782 0) {
3783 #else
3784 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
3785 if ((request_firmware_nowait(
3786 THIS_MODULE, FW_ACTION_HOTPLUG,
3787 cal_data_cfg, handle->hotplug_device,
3788 GFP_KERNEL, handle,
3789 woal_request_init_user_conf_callback)) <
3790 0) {
3791 #else
3792 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
3793 if ((request_firmware_nowait(
3794 THIS_MODULE, FW_ACTION_HOTPLUG,
3795 cal_data_cfg, handle->hotplug_device,
3796 handle,
3797 woal_request_init_user_conf_callback)) <
3798 0) {
3799 #else
3800 if ((request_firmware_nowait(
3801 THIS_MODULE, cal_data_cfg,
3802 handle->hotplug_device, handle,
3803 woal_request_init_user_conf_callback)) <
3804 0) {
3805 #endif
3806 #endif
3807 #endif
3808 PRINTM(MERROR,
3809 "Cal data request_firmware_nowait() failed\n");
3810 ret = MLAN_STATUS_FAILURE;
3811 goto done;
3812 }
3813 handle->init_user_conf_wait_flag = MFALSE;
3814 wait_event_interruptible(
3815 handle->init_user_conf_wait_q,
3816 handle->init_user_conf_wait_flag);
3817 } else {
3818 if ((request_firmware(&handle->user_data, cal_data_cfg,
3819 handle->hotplug_device)) < 0) {
3820 PRINTM(MERROR,
3821 "Cal data request_firmware() failed\n");
3822 ret = MLAN_STATUS_FAILURE;
3823 goto done;
3824 }
3825 }
3826 } else if (!cal_data_cfg && handle->card_info->cal_data_cfg) {
3827 PRINTM(MERROR,
3828 "Please add cal_data_cfg for 8887/8977/8997/8987/8978\n");
3829 ret = MLAN_STATUS_FAILURE;
3830 goto done;
3831 }
3832 if (handle->user_data) {
3833 param->pcal_data_buf = (t_u8 *)handle->user_data->data;
3834 param->cal_data_len = handle->user_data->size;
3835 }
3836 done:
3837 return ret;
3838 }
3839
3840 #if defined(USB)
3841 /**
3842 * @brief Download and Initialize firmware DPC
3843 *
3844 * @param handle A pointer to moal_handle structure
3845 *
3846 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3847 */
3848 static mlan_status woal_reset_usb_dev(moal_handle *handle)
3849 {
3850 int ret = MLAN_STATUS_SUCCESS;
3851 struct usb_device *udev = ((struct usb_card_rec *)(handle->card))->udev;
3852 int usbRstDev_ret = 0;
3853
3854 ENTER();
3855
3856 /* Return now */
3857 PRINTM(MMSG, "WLAN FW is downloaded\n");
3858
3859 /* Reset USB device to get re-enumeration */
3860 if (udev) {
3861 #define USB_WAIT_FW_READY (500)
3862 mdelay(USB_WAIT_FW_READY);
3863 usbRstDev_ret = usb_reset_device(udev);
3864 if ((usbRstDev_ret == 0) ||
3865 (usbRstDev_ret == -ENODEV) || /* expected
3866 since
3867 chip
3868 re-enumerates
3869 */
3870 (usbRstDev_ret == -EINVAL)) { /* expected if USB FW detaches
3871 first */
3872 PRINTM(MMSG, "usb_reset_device() successful.\n");
3873 } else {
3874 PRINTM(MERROR,
3875 "usb_reset_device() failed with error code =%d\n",
3876 usbRstDev_ret);
3877 ret = MLAN_STATUS_FAILURE;
3878 }
3879 } else {
3880 PRINTM(MERROR, "ERR: No handle to call usb_reset_device()!\n");
3881 ret = MLAN_STATUS_FAILURE;
3882 }
3883
3884 LEAVE();
3885 return ret;
3886 }
3887 #endif
3888
3889 /**
3890 * @brief Download and Initialize firmware DPC
3891 *
3892 * @param handle A pointer to moal_handle structure
3893 *
3894 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3895 */
3896 static mlan_status woal_init_fw_dpc(moal_handle *handle)
3897 {
3898 mlan_status ret = MLAN_STATUS_SUCCESS;
3899 mlan_fw_image fw;
3900 mlan_init_param param;
3901
3902 ENTER();
3903
3904 if (handle->firmware) {
3905 memset(&fw, 0, sizeof(mlan_fw_image));
3906 fw.pfw_buf = (t_u8 *)handle->firmware->data;
3907 fw.fw_len = handle->firmware->size;
3908 if (handle->params.fw_reload == FW_RELOAD_SDIO_INBAND_RESET)
3909 fw.fw_reload = handle->params.fw_reload;
3910 else
3911 fw.fw_reload = 0;
3912 wifi_status = WIFI_STATUS_FW_DNLD;
3913 ret = mlan_dnld_fw(handle->pmlan_adapter, &fw);
3914 if (ret == MLAN_STATUS_FAILURE) {
3915 wifi_status = WIFI_STATUS_DNLD_FW_FAIL;
3916 PRINTM(MERROR,
3917 "WLAN: Fail download FW with nowwait: %u\n",
3918 moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT));
3919 if (handle->ops.reg_dbg)
3920 handle->ops.reg_dbg(handle);
3921 goto done;
3922 }
3923 wifi_status = WIFI_STATUS_FW_DNLD_COMPLETE;
3924
3925 #if defined(USB)
3926 if (handle->boot_state == USB_FW_DNLD) {
3927 if (!IS_USB8997(handle->card_type) &&
3928 !IS_USB9098(handle->card_type) &&
3929 !IS_USB9097(handle->card_type) &&
3930 !IS_USBNW62X(handle->card_type) &&
3931 !IS_USB8978(handle->card_type))
3932 ret = woal_reset_usb_dev(handle);
3933 goto done;
3934 }
3935 #endif /* USB_NEW_FW_DNLD */
3936 PRINTM(MMSG, "WLAN FW is active\n");
3937 if (!handle->fw_reload)
3938 handle->driver_status = MFALSE;
3939 }
3940
3941 moal_get_boot_ktime(handle, &handle->on_time);
3942 PRINTM(MMSG, "on_time is %llu\n", handle->on_time);
3943
3944 /** data request */
3945 memset(¶m, 0, sizeof(mlan_init_param));
3946
3947 ret = woal_req_dpd_data(handle, ¶m);
3948 if (ret != MLAN_STATUS_SUCCESS)
3949 goto done;
3950
3951 ret = woal_req_txpwr_data(handle, ¶m);
3952 if (ret != MLAN_STATUS_SUCCESS)
3953 goto done;
3954
3955 ret = woal_req_cal_data(handle, ¶m);
3956 if (ret != MLAN_STATUS_SUCCESS)
3957 goto done;
3958
3959 handle->hardware_status = HardwareStatusFwReady;
3960 #ifdef USB
3961 if (IS_USB(handle->card_type) && !handle->fw_reload) {
3962 if (handle->skip_fw_dnld != MTRUE) {
3963 ret = woal_usb_rx_init(handle);
3964 if (ret == MLAN_STATUS_SUCCESS)
3965 ret = woal_usb_tx_init(handle);
3966 }
3967 if (ret != MLAN_STATUS_SUCCESS)
3968 goto done;
3969 }
3970 #endif /* USB */
3971 ret = mlan_set_init_param(handle->pmlan_adapter, ¶m);
3972 if (handle->fw_reload) {
3973 LEAVE();
3974 return ret;
3975 }
3976 handle->init_wait_q_woken = MFALSE;
3977 wifi_status = WIFI_STATUS_INIT_FW;
3978 ret = mlan_init_fw(handle->pmlan_adapter);
3979 if (ret == MLAN_STATUS_FAILURE) {
3980 wifi_status = WIFI_STATUS_INIT_FW_FAIL;
3981 goto done;
3982 } else if (ret == MLAN_STATUS_SUCCESS) {
3983 wifi_status = WIFI_STATUS_OK;
3984 handle->hardware_status = HardwareStatusReady;
3985 goto done;
3986 }
3987 /* Wait for mlan_init to complete */
3988 wait_event_timeout(handle->init_wait_q, handle->init_wait_q_woken,
3989 10 * HZ);
3990 if (handle->hardware_status != HardwareStatusReady) {
3991 wifi_status = WIFI_STATUS_INIT_FW_FAIL;
3992 if (handle->ops.reg_dbg)
3993 handle->ops.reg_dbg(handle);
3994 #ifdef DEBUG_LEVEL1
3995 if (drvdbg & MFW_D) {
3996 drvdbg &= ~MFW_D;
3997 if (handle->ops.dump_fw_info)
3998 handle->ops.dump_fw_info(handle);
3999 }
4000 #endif
4001 ret = MLAN_STATUS_FAILURE;
4002 goto done;
4003 }
4004 wifi_status = WIFI_STATUS_OK;
4005 ret = MLAN_STATUS_SUCCESS;
4006 done:
4007 if (handle->dpd_data) {
4008 release_firmware(handle->dpd_data);
4009 handle->dpd_data = NULL;
4010 }
4011 if (handle->txpwr_data) {
4012 release_firmware(handle->txpwr_data);
4013 handle->txpwr_data = NULL;
4014 }
4015 if (handle->user_data) {
4016 release_firmware(handle->user_data);
4017 handle->user_data = NULL;
4018 }
4019
4020 LEAVE();
4021 return ret;
4022 }
4023
4024 /**
4025 * @brief Request firmware DPC
4026 *
4027 * @param handle A pointer to moal_handle structure
4028 * @param firmware A pointer to firmware image
4029 *
4030 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
4031 */
4032 static mlan_status woal_request_fw_dpc(moal_handle *handle,
4033 const struct firmware *firmware)
4034 {
4035 mlan_status ret = MLAN_STATUS_SUCCESS;
4036 wifi_timeval tstamp;
4037 ENTER();
4038
4039 if (!firmware) {
4040 woal_get_monotonic_time(&tstamp);
4041 if (tstamp.time_sec >
4042 (handle->req_fw_time.time_sec + REQUEST_FW_TIMEOUT)) {
4043 PRINTM(MERROR,
4044 "No firmware image found. Skipping download\n");
4045 ret = MLAN_STATUS_FAILURE;
4046 goto done;
4047 }
4048 PRINTM(MERROR,
4049 "request_firmware_nowait failed for %s. Retrying..\n",
4050 handle->drv_mode.fw_name);
4051 woal_sched_timeout(MOAL_TIMER_1S);
4052 ret = woal_request_fw(handle);
4053 if (ret != MLAN_STATUS_SUCCESS)
4054 PRINTM(MERROR, "%s: woal_request_fw failed!\n",
4055 __func__);
4056 LEAVE();
4057 return ret;
4058 }
4059 handle->firmware = firmware;
4060
4061 ret = woal_init_fw_dpc(handle);
4062 if (ret)
4063 goto done;
4064 ret = woal_add_card_dpc(handle);
4065 if (ret)
4066 goto done;
4067
4068 done:
4069 /* We should hold the semaphore until callback finishes execution */
4070 MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
4071 LEAVE();
4072 return ret;
4073 }
4074
4075 /**
4076 * @brief Request firmware callback
4077 * This function is invoked by request_firmware_nowait system call
4078 *
4079 * @param firmware A pointer to firmware image
4080 * @param context A pointer to moal_handle structure
4081 *
4082 * @return N/A
4083 */
4084 static void woal_request_fw_callback(const struct firmware *firmware,
4085 void *context)
4086 {
4087 moal_handle *handle;
4088
4089 ENTER();
4090
4091 handle = (moal_handle *)context;
4092 handle->firmware = firmware;
4093 if (MLAN_STATUS_SUCCESS !=
4094 woal_request_fw_dpc((moal_handle *)context, firmware))
4095 PRINTM(MERROR, "woal_request_fw_dpc failed\n");
4096 if (firmware) {
4097 release_firmware(firmware);
4098 handle->firmware = NULL;
4099 }
4100 LEAVE();
4101 return;
4102 }
4103
4104 /**
4105 * @brief Download firmware using helper
4106 *
4107 * @param handle A pointer to moal_handle structure
4108 *
4109 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
4110 */
4111 mlan_status woal_request_fw(moal_handle *handle)
4112 {
4113 int err;
4114 mlan_status ret = MLAN_STATUS_SUCCESS;
4115 t_u8 req_fw_nowait = moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT);
4116
4117 ENTER();
4118
4119 PRINTM(MMSG, "Request firmware: %s\n", handle->drv_mode.fw_name);
4120
4121 if (req_fw_nowait && !handle->fw_reload) {
4122 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
4123 err = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
4124 handle->drv_mode.fw_name,
4125 handle->hotplug_device,
4126 GFP_KERNEL, handle,
4127 woal_request_fw_callback);
4128 #else
4129 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
4130 err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
4131 handle->drv_mode.fw_name,
4132 handle->hotplug_device,
4133 GFP_KERNEL, handle,
4134 woal_request_fw_callback);
4135 #else
4136 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
4137 err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
4138 handle->drv_mode.fw_name,
4139 handle->hotplug_device, handle,
4140 woal_request_fw_callback);
4141 #else
4142 err = request_firmware_nowait(THIS_MODULE,
4143 handle->drv_mode.fw_name,
4144 handle->hotplug_device, handle,
4145 woal_request_fw_callback);
4146 #endif
4147 #endif
4148 #endif
4149 if (err < 0) {
4150 PRINTM(MFATAL,
4151 "WLAN: request_firmware_nowait() failed, error code = %d\n",
4152 err);
4153 ret = MLAN_STATUS_FAILURE;
4154 }
4155 } else {
4156 err = request_firmware(&handle->firmware,
4157 handle->drv_mode.fw_name,
4158 handle->hotplug_device);
4159 if (err < 0) {
4160 PRINTM(MFATAL,
4161 "WLAN: request_firmware() failed, error code = %d\n",
4162 err);
4163 ret = MLAN_STATUS_FAILURE;
4164 } else {
4165 if (handle->fw_reload)
4166 ret = woal_init_fw_dpc(handle);
4167 else
4168 ret = woal_request_fw_dpc(handle,
4169 handle->firmware);
4170 release_firmware(handle->firmware);
4171 handle->firmware = NULL;
4172 }
4173 }
4174 LEAVE();
4175 return ret;
4176 }
4177
4178 /**
4179 * @brief This function initializes firmware
4180 *
4181 * @param handle A pointer to moal_handle structure
4182 *
4183 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
4184 */
4185 mlan_status woal_init_fw(moal_handle *handle)
4186 {
4187 mlan_status ret = MLAN_STATUS_SUCCESS;
4188
4189 ENTER();
4190
4191 #ifdef USB
4192 if (IS_USB(handle->card_type)) {
4193 if (MFALSE || (handle->skip_fw_dnld == MTRUE)
4194 #if defined(USB)
4195 || (handle->boot_state == USB_FW_READY)
4196 #endif /* USB_NEW_FW_DNLD */
4197 ) {
4198 PRINTM(MMSG, "WLAN FW is active\n");
4199 /* Set it to NULL to skip downloading firmware to card
4200 */
4201 handle->firmware = NULL;
4202 ret = woal_init_fw_dpc(handle);
4203 if (ret)
4204 goto done;
4205 ret = woal_add_card_dpc(handle);
4206 if (ret)
4207 goto done;
4208 /* Release semaphore if download is not required */
4209 MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
4210 done:
4211 LEAVE();
4212 return ret;
4213 }
4214 }
4215 #endif /* USB */
4216
4217 woal_get_monotonic_time(&handle->req_fw_time);
4218 ret = woal_request_fw(handle);
4219 if (ret == MLAN_STATUS_FAILURE) {
4220 PRINTM(MFATAL, "woal_request_fw failed\n");
4221 }
4222
4223 LEAVE();
4224 return ret;
4225 }
4226
4227 /**
4228 * @brief This function will fill in the mlan_buffer
4229 *
4230 * @param pmbuf A pointer to mlan_buffer
4231 * @param skb A pointer to struct sk_buff
4232 *
4233 * @return N/A
4234 */
4235 void woal_fill_mlan_buffer(moal_private *priv, mlan_buffer *pmbuf,
4236 struct sk_buff *skb)
4237 {
4238 wifi_timeval tstamp;
4239 struct ethhdr *eth;
4240 dot11_txcontrol *txcontrol;
4241 t_u8 tx_ctrl_flag = MFALSE;
4242 int i = 0;
4243 ENTER();
4244
4245 eth = (struct ethhdr *)skb->data;
4246
4247 switch (eth->h_proto) {
4248 case __constant_htons(ETH_P_IP):
4249 PRINTM(MINFO, "packet type ETH_P_IP: %04x, prio=%#x\n",
4250 eth->h_proto, skb->priority);
4251 break;
4252 case __constant_htons(ETH_P_IPV6):
4253 PRINTM(MINFO, "packet type ETH_P_IPV6: %04x, prio=%#x\n",
4254 eth->h_proto, skb->priority);
4255 break;
4256 case __constant_htons(ETH_P_ARP):
4257 skb->priority = 0;
4258 PRINTM(MINFO, "ARP packet %04x prio=%#x\n", eth->h_proto,
4259 skb->priority);
4260 break;
4261 default:
4262 skb->priority = 0;
4263 if (priv->tx_protocols.protocol_num) {
4264 for (i = 0; i < priv->tx_protocols.protocol_num; i++) {
4265 if (eth->h_proto ==
4266 __constant_htons(
4267 priv->tx_protocols.protocols[i]))
4268 tx_ctrl_flag = MTRUE;
4269 }
4270 }
4271 if (tx_ctrl_flag) {
4272 txcontrol = (dot11_txcontrol *)(skb->data +
4273 sizeof(struct ethhdr));
4274 pmbuf->u.tx_info.data_rate = txcontrol->datarate;
4275 pmbuf->u.tx_info.channel = txcontrol->channel;
4276 pmbuf->u.tx_info.bw = txcontrol->bw;
4277 pmbuf->u.tx_info.tx_power.val = txcontrol->power;
4278 pmbuf->u.tx_info.retry_limit = txcontrol->retry_limit;
4279 skb->priority = txcontrol->priority;
4280 memmove(skb->data + sizeof(dot11_txcontrol), skb->data,
4281 sizeof(struct ethhdr));
4282 skb_pull(skb, sizeof(dot11_txcontrol));
4283 pmbuf->flags |= MLAN_BUF_FLAG_TX_CTRL;
4284 }
4285 break;
4286 }
4287 PRINTM(MDAT_D, "packet %04x prio=%#x\n", eth->h_proto, skb->priority);
4288
4289 if (priv->enable_mc_aggr && priv->num_mcast_addr) {
4290 if (woal_find_mcast_node_tx(priv, skb)) {
4291 mc_txcontrol *tx_ctrl =
4292 (mc_txcontrol *)(skb->data + skb->len -
4293 sizeof(mc_txcontrol));
4294 moal_memcpy_ext(priv->phandle,
4295 (t_u8 *)&pmbuf->u.mc_tx_info,
4296 (t_u8 *)tx_ctrl, sizeof(mc_txcontrol),
4297 sizeof(mc_txcontrol));
4298 pmbuf->flags |= MLAN_BUF_FLAG_MC_AGGR_PKT;
4299 // use AC_VO
4300 skb->priority = 6;
4301 }
4302 }
4303
4304 /* Record the current time the packet was queued; used to determine
4305 * the amount of time the packet was queued in the driver before it
4306 * was sent to the firmware. The delay is then sent along with the
4307 * packet to the firmware for aggregate delay calculation for stats
4308 * and MSDU lifetime expiry.
4309 */
4310 woal_get_monotonic_time(&tstamp);
4311 skb->tstamp = ktime_get_real();
4312
4313 pmbuf->pdesc = skb;
4314 pmbuf->pbuf = skb->head + sizeof(mlan_buffer);
4315 #ifdef PCIE
4316 if (IS_PCIE(priv->phandle->card_type)) {
4317 pmbuf->buf_pa = 0;
4318 }
4319 #endif
4320 pmbuf->data_offset = skb->data - (skb->head + sizeof(mlan_buffer));
4321 pmbuf->data_len = skb->len;
4322 pmbuf->priority = skb->priority;
4323 pmbuf->buf_type = 0;
4324 pmbuf->in_ts_sec = tstamp.time_sec;
4325 pmbuf->in_ts_usec = tstamp.time_usec;
4326
4327 LEAVE();
4328 return;
4329 }
4330
4331 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
4332 /**
4333 * @brief This function opens the network device for monitor interface
4334 *
4335 * @param dev A pointer to net_device structure
4336 *
4337 * @return 0 -- success, otherwise fail
4338 */
4339 static int woal_mon_open(struct net_device *ndev)
4340 {
4341 ENTER();
4342 LEAVE();
4343 return 0;
4344 }
4345
4346 /**
4347 * @brief This function closes the network device for monitor interface
4348 *
4349 * @param dev A pointer to net_device structure
4350 *
4351 * @return 0 -- success, otherwise fail
4352 */
4353 static int woal_mon_close(struct net_device *ndev)
4354 {
4355 ENTER();
4356 LEAVE();
4357 return 0;
4358 }
4359
4360 /**
4361 * @brief This function sets the MAC address to firmware for monitor interface
4362 *
4363 * @param dev A pointer to net_device structure
4364 * @param addr MAC address to set
4365 *
4366 * @return 0 -- success, otherwise fail
4367 */
4368 static int woal_mon_set_mac_address(struct net_device *ndev, void *addr)
4369 {
4370 ENTER();
4371 LEAVE();
4372 return 0;
4373 }
4374
4375 /**
4376 * @brief This function sets multicast address to firmware for monitor interface
4377 *
4378 * @param dev A pointer to net_device structure
4379 *
4380 * @return 0 -- success, otherwise fail
4381 */
4382 static void woal_mon_set_multicast_list(struct net_device *ndev)
4383 {
4384 ENTER();
4385 LEAVE();
4386 }
4387
4388 /**
4389 * @brief This function handles packet transmission for monitor interface
4390 *
4391 * @param skb A pointer to sk_buff structure
4392 * @param dev A pointer to net_device structure
4393 *
4394 * @return 0 -- success, otherwise fail
4395 */
4396 static netdev_tx_t woal_mon_hard_start_xmit(struct sk_buff *skb,
4397 struct net_device *ndev)
4398 {
4399 int len_rthdr;
4400 int qos_len = 0;
4401 int dot11_hdr_len = 24;
4402 int snap_len = 6;
4403 unsigned char *pdata;
4404 unsigned short fc;
4405 unsigned char src_mac_addr[6];
4406 unsigned char dst_mac_addr[6];
4407 struct ieee80211_hdr *dot11_hdr;
4408 struct ieee80211_radiotap_header *prthdr =
4409 (struct ieee80211_radiotap_header *)skb->data;
4410 monitor_iface *mon_if = netdev_priv(ndev);
4411
4412 ENTER();
4413
4414 if (mon_if == NULL || mon_if->base_ndev == NULL) {
4415 goto fail;
4416 }
4417
4418 /* check for not even having the fixed radiotap header part */
4419 if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) {
4420 PRINTM(MERROR,
4421 "Invalid radiotap hdr length,"
4422 "skb->len: %d\n",
4423 skb->len);
4424 goto fail; /* too short to be possibly valid */
4425 }
4426
4427 /* is it a header version we can trust to find length from? */
4428 if (unlikely(prthdr->it_version))
4429 goto fail; /* only version 0 is supported */
4430
4431 /* then there must be a radiotap header with a length we can use */
4432 len_rthdr = ieee80211_get_radiotap_len(skb->data);
4433
4434 /* does the skb contain enough to deliver on the alleged length? */
4435 if (unlikely((int)skb->len < len_rthdr)) {
4436 PRINTM(MERROR,
4437 "Invalid data length,"
4438 "skb->len: %d\n",
4439 skb->len);
4440 goto fail; /* skb too short for claimed rt header extent */
4441 }
4442
4443 /* Skip the ratiotap header */
4444 skb_pull(skb, len_rthdr);
4445
4446 dot11_hdr = (struct ieee80211_hdr *)skb->data;
4447 fc = le16_to_cpu(dot11_hdr->frame_control);
4448 if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
4449 /* Check if this ia a Wireless Distribution System (WDS) frame
4450 * which has 4 MAC addresses
4451 */
4452 if (dot11_hdr->frame_control & (__force __le16)0x0080)
4453 qos_len = 2;
4454 if ((dot11_hdr->frame_control & (__force __le16)0x0300) ==
4455 (__force __le16)0x0300)
4456 dot11_hdr_len += 6;
4457
4458 moal_memcpy_ext(NULL, dst_mac_addr, dot11_hdr->addr1,
4459 sizeof(dst_mac_addr), sizeof(dst_mac_addr));
4460 moal_memcpy_ext(NULL, src_mac_addr, dot11_hdr->addr2,
4461 sizeof(src_mac_addr), sizeof(src_mac_addr));
4462
4463 /* Skip the 802.11 header, QoS (if any) and SNAP, but leave
4464 * spaces for for two MAC addresses
4465 */
4466 skb_pull(skb, dot11_hdr_len + qos_len + snap_len -
4467 sizeof(src_mac_addr) * 2);
4468 pdata = (unsigned char *)skb->data;
4469 moal_memcpy_ext(NULL, pdata, dst_mac_addr, sizeof(dst_mac_addr),
4470 (t_u32)skb->len);
4471 moal_memcpy_ext(NULL, pdata + sizeof(dst_mac_addr),
4472 src_mac_addr, sizeof(src_mac_addr),
4473 (t_u32)skb->len - sizeof(dst_mac_addr));
4474
4475 LEAVE();
4476 return woal_hard_start_xmit(skb, mon_if->base_ndev);
4477 }
4478
4479 fail:
4480 dev_kfree_skb(skb);
4481 LEAVE();
4482 return NETDEV_TX_OK;
4483 }
4484
4485 /**
4486 * @brief This function returns the network statistics
4487 *
4488 * @param dev A pointer to net_device structure
4489 *
4490 * @return A pointer to net_device_stats structure
4491 */
4492 static struct net_device_stats *woal_mon_get_stats(struct net_device *dev)
4493 {
4494 monitor_iface *mon_if = (monitor_iface *)netdev_priv(dev);
4495 return &mon_if->stats;
4496 }
4497
4498 static const struct net_device_ops woal_cfg80211_mon_if_ops = {
4499 .ndo_open = woal_mon_open,
4500 .ndo_start_xmit = woal_mon_hard_start_xmit,
4501 .ndo_stop = woal_mon_close,
4502 .ndo_get_stats = woal_mon_get_stats,
4503 .ndo_set_mac_address = woal_mon_set_mac_address,
4504 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
4505 .ndo_set_rx_mode = woal_mon_set_multicast_list,
4506 #else
4507 .ndo_set_multicast_list = woal_mon_set_multicast_list,
4508 #endif
4509 };
4510
4511 /**
4512 * @brief This function setup monitor interface
4513 *
4514 * @param dev A pointer to net_device structure
4515 *
4516 * @return 0 -- success, otherwise fail
4517 */
4518 static void woal_mon_if_setup(struct net_device *dev)
4519 {
4520 ENTER();
4521 ether_setup(dev);
4522 dev->netdev_ops = &woal_cfg80211_mon_if_ops;
4523 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 11, 9)
4524 dev->needs_free_netdev = true;
4525 #else
4526 dev->destructor = free_netdev;
4527 #endif
4528 LEAVE();
4529 }
4530
4531 /**
4532 * @brief Request the driver to add a monitor interface
4533 *
4534 * @param priv A pointer to moal_private
4535 * @param name Virtual interface name
4536 * @param name_assign_type Interface name assignment type
4537 * @param sniffer_mode Sniffer mode
4538 *
4539 * @return A pointer to monitor_iface
4540 */
4541 monitor_iface *woal_prepare_mon_if(moal_private *priv, const char *name,
4542 unsigned char name_assign_type,
4543 int sniffer_mode)
4544 {
4545 int ret = 0;
4546 moal_handle *handle = priv->phandle;
4547 struct net_device *ndev = NULL;
4548 monitor_iface *mon_if = NULL;
4549
4550 ENTER();
4551
4552 if (sniffer_mode != CHANNEL_SPEC_SNIFFER_MODE) {
4553 PRINTM(MERROR, "Sniffer mode is not valid\n");
4554 ret = -EFAULT;
4555 goto fail;
4556 }
4557 if ((sniffer_mode == CHANNEL_SPEC_SNIFFER_MODE) &&
4558 woal_is_any_interface_active(handle)) {
4559 PRINTM(MERROR,
4560 "Cannot start channel specified net monitor when Interface Active\n");
4561 ret = -EFAULT;
4562 goto fail;
4563 }
4564
4565 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
4566 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
4567 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
4568 ndev = alloc_netdev_mq(sizeof(*mon_if), name, name_assign_type,
4569 woal_mon_if_setup, 1);
4570 #else
4571 ndev = alloc_netdev_mq(sizeof(*mon_if), name, NET_NAME_UNKNOWN,
4572 woal_mon_if_setup, 1);
4573 #endif
4574 #else
4575 ndev = alloc_netdev_mq(sizeof(*mon_if), name, woal_mon_if_setup, 1);
4576 #endif
4577 #else
4578 ndev = alloc_netdev_mq(sizeof(*mon_if), name, woal_mon_if_setup);
4579 #endif
4580 if (!ndev) {
4581 PRINTM(MFATAL, "Init virtual ethernet device failed\n");
4582 ret = -EFAULT;
4583 goto fail;
4584 }
4585
4586 ret = dev_alloc_name(ndev, ndev->name);
4587 if (ret < 0) {
4588 PRINTM(MFATAL, "Net device alloc name fail.\n");
4589 ret = -EFAULT;
4590 goto fail;
4591 }
4592
4593 //?memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
4594
4595 mon_if = netdev_priv(ndev);
4596 moal_memcpy_ext(handle, mon_if->ifname, ndev->name, IFNAMSIZ, IFNAMSIZ);
4597
4598 ndev->type = ARPHRD_IEEE80211_RADIOTAP;
4599 ndev->netdev_ops = &woal_cfg80211_mon_if_ops;
4600
4601 mon_if->priv = priv;
4602 mon_if->mon_ndev = ndev;
4603 mon_if->base_ndev = priv->netdev;
4604 mon_if->sniffer_mode = sniffer_mode;
4605 mon_if->radiotap_enabled = 1;
4606 mon_if->flag = 1;
4607
4608 fail:
4609 if (ret) {
4610 if (ndev)
4611 free_netdev(ndev);
4612 LEAVE();
4613 return NULL;
4614 }
4615
4616 LEAVE();
4617 return mon_if;
4618 }
4619 #endif
4620
4621 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
4622 static struct device_type wlan_type = {
4623 .name = "wlan",
4624 };
4625 #endif
4626
4627 #ifdef STA_SUPPORT
4628 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
4629 /** Network device handlers */
4630 const struct net_device_ops woal_netdev_ops = {
4631 .ndo_open = woal_open,
4632 .ndo_start_xmit = woal_hard_start_xmit,
4633 .ndo_stop = woal_close,
4634 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
4635 .ndo_siocdevprivate = woal_do_ioctl,
4636 #else
4637 .ndo_do_ioctl = woal_do_ioctl,
4638 #endif
4639 .ndo_set_mac_address = woal_set_mac_address,
4640 .ndo_change_mtu = woal_change_mtu,
4641 .ndo_tx_timeout = woal_tx_timeout,
4642 .ndo_get_stats = woal_get_stats,
4643 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
4644 .ndo_set_rx_mode = woal_set_multicast_list,
4645 #else
4646 .ndo_set_multicast_list = woal_set_multicast_list,
4647 #endif
4648 .ndo_select_queue = woal_select_queue,
4649 .ndo_validate_addr = eth_validate_addr,
4650 };
4651 #endif
4652
4653 #define MAX_MTU_SIZE 2000
4654 /**
4655 * @brief This function initializes the private structure
4656 * and dev structure for station mode
4657 *
4658 * @param dev A pointer to net_device structure
4659 * @param priv A pointer to moal_private structure
4660 *
4661 * @return MLAN_STATUS_SUCCESS
4662 */
4663 mlan_status woal_init_sta_dev(struct net_device *dev, moal_private *priv)
4664 {
4665 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
4666 mlan_fw_info fw_info;
4667 #endif
4668 ENTER();
4669 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
4670 #ifdef MFG_CMD_SUPPORT
4671 if (priv->phandle->params.mfg_mode != MLAN_INIT_PARA_ENABLED) {
4672 #endif
4673 memset(&fw_info, 0, sizeof(mlan_fw_info));
4674 if (MLAN_STATUS_SUCCESS !=
4675 woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info)) {
4676 PRINTM(MERROR, "%s: get_fw_info failed \n", __func__);
4677 return MLAN_STATUS_FAILURE;
4678 }
4679 if (fw_info.tx_buf_size >
4680 (MAX_MTU_SIZE + MLAN_MIN_DATA_HEADER_LEN +
4681 priv->extra_tx_head_len)) {
4682 dev->max_mtu = MAX_MTU_SIZE;
4683 PRINTM(MINFO, "wlan: %s set max_mtu %d\n", dev->name,
4684 dev->max_mtu);
4685 }
4686 #ifdef MFG_CMD_SUPPORT
4687 }
4688 #endif
4689 #endif
4690 /* Setup the OS Interface to our functions */
4691 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
4692 dev->open = woal_open;
4693 dev->hard_start_xmit = woal_hard_start_xmit;
4694 dev->stop = woal_close;
4695 dev->do_ioctl = woal_do_ioctl;
4696 dev->set_mac_address = woal_set_mac_address;
4697 dev->tx_timeout = woal_tx_timeout;
4698 dev->get_stats = woal_get_stats;
4699 dev->set_multicast_list = woal_set_multicast_list;
4700 #else
4701 dev->netdev_ops = &woal_netdev_ops;
4702 #endif
4703 dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
4704 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
4705 dev->needed_headroom += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
4706 priv->extra_tx_head_len;
4707 #else
4708 dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
4709 priv->extra_tx_head_len;
4710 #endif
4711 #ifdef STA_WEXT
4712 if (IS_STA_WEXT(priv->phandle->params.cfg80211_wext)) {
4713 #if WIRELESS_EXT < 21
4714 dev->get_wireless_stats = woal_get_wireless_stats;
4715 #endif
4716 dev->wireless_handlers =
4717 (struct iw_handler_def *)&woal_handler_def;
4718 }
4719 #endif
4720 dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
4721
4722 #ifdef STA_CFG80211
4723 if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext))
4724 init_waitqueue_head(&priv->ft_wait_q);
4725 #endif
4726 LEAVE();
4727 return MLAN_STATUS_SUCCESS;
4728 }
4729 #endif /* STA_SUPPORT */
4730
4731 #ifdef UAP_SUPPORT
4732 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
4733 /** Network device handlers */
4734 const struct net_device_ops woal_uap_netdev_ops = {
4735 .ndo_open = woal_open,
4736 .ndo_start_xmit = woal_hard_start_xmit,
4737 .ndo_stop = woal_close,
4738 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
4739 .ndo_siocdevprivate = woal_uap_do_ioctl,
4740 #else
4741 .ndo_do_ioctl = woal_uap_do_ioctl,
4742 #endif
4743 .ndo_set_mac_address = woal_set_mac_address,
4744 .ndo_change_mtu = woal_change_mtu,
4745 .ndo_tx_timeout = woal_tx_timeout,
4746 .ndo_get_stats = woal_get_stats,
4747 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
4748 .ndo_set_rx_mode = woal_uap_set_multicast_list,
4749 #else
4750 .ndo_set_multicast_list = woal_uap_set_multicast_list,
4751 #endif
4752 .ndo_select_queue = woal_select_queue,
4753 .ndo_validate_addr = eth_validate_addr,
4754 };
4755 #endif
4756
4757 /**
4758 * @brief This function initializes the private structure
4759 * and dev structure for uap mode
4760 *
4761 * @param dev A pointer to net_device structure
4762 * @param priv A pointer to moal_private structure
4763 *
4764 * @return MLAN_STATUS_SUCCESS
4765 */
4766 mlan_status woal_init_uap_dev(struct net_device *dev, moal_private *priv)
4767 {
4768 mlan_status status = MLAN_STATUS_SUCCESS;
4769 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
4770 mlan_fw_info fw_info;
4771 #endif
4772
4773 ENTER();
4774 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
4775 memset(&fw_info, 0, sizeof(mlan_fw_info));
4776 if (MLAN_STATUS_SUCCESS !=
4777 woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info)) {
4778 PRINTM(MERROR, "%s: get_fw_info failed \n", __func__);
4779 return MLAN_STATUS_FAILURE;
4780 }
4781 if (fw_info.tx_buf_size > (MAX_MTU_SIZE + MLAN_MIN_DATA_HEADER_LEN +
4782 priv->extra_tx_head_len)) {
4783 dev->max_mtu = MAX_MTU_SIZE;
4784 PRINTM(MMSG, "wlan: %s set max_mtu %d\n", dev->name,
4785 dev->max_mtu);
4786 }
4787 #endif
4788 /* Setup the OS Interface to our functions */
4789 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
4790 dev->open = woal_open;
4791 dev->hard_start_xmit = woal_hard_start_xmit;
4792 dev->stop = woal_close;
4793 dev->set_mac_address = woal_set_mac_address;
4794 dev->tx_timeout = woal_tx_timeout;
4795 dev->get_stats = woal_get_stats;
4796 dev->do_ioctl = woal_uap_do_ioctl;
4797 dev->set_multicast_list = woal_uap_set_multicast_list;
4798 #else
4799 dev->netdev_ops = &woal_uap_netdev_ops;
4800 #endif
4801 dev->watchdog_timeo = MRVDRV_DEFAULT_UAP_WATCHDOG_TIMEOUT;
4802 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
4803 dev->needed_headroom += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
4804 priv->extra_tx_head_len;
4805 #else
4806 dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
4807 priv->extra_tx_head_len;
4808 #endif
4809 /** don't need register to wext */
4810 if (priv->bss_type == MLAN_BSS_TYPE_DFS) {
4811 LEAVE();
4812 return status;
4813 }
4814 #ifdef UAP_WEXT
4815 if (IS_UAP_WEXT(priv->phandle->params.cfg80211_wext)) {
4816 #if WIRELESS_EXT < 21
4817 dev->get_wireless_stats = woal_get_uap_wireless_stats;
4818 #endif
4819 dev->wireless_handlers =
4820 (struct iw_handler_def *)&woal_uap_handler_def;
4821 }
4822 #endif /* UAP_WEXT */
4823 dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
4824
4825 LEAVE();
4826 return status;
4827 }
4828 #endif /* UAP_SUPPORT */
4829
4830 /**
4831 * @brief This function adds a new interface. It will
4832 * allocate, initialize and register the device.
4833 *
4834 * @param handle A pointer to moal_handle structure
4835 * @param bss_index BSS index number
4836 * @param bss_type BSS type
4837 *
4838 * @return A pointer to the new priv structure
4839 */
4840 moal_private *woal_add_interface(moal_handle *handle, t_u8 bss_index,
4841 t_u8 bss_type)
4842 {
4843 struct net_device *dev = NULL;
4844 moal_private *priv = NULL;
4845 char name[256];
4846 int i = 0;
4847 #ifdef UAP_CFG80211
4848 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
4849 char csa_str[256];
4850 #endif
4851 #endif
4852 ENTER();
4853
4854 memset(name, 0, sizeof(name));
4855 switch (bss_type) {
4856 #ifdef STA_SUPPORT
4857 case MLAN_BSS_TYPE_STA:
4858 if (handle->params.sta_name)
4859 snprintf(name, sizeof(name), "%s%%d",
4860 handle->params.sta_name);
4861 else if (handle->second_mac)
4862 snprintf(name, sizeof(name), "m%s", default_mlan_name);
4863 else
4864 snprintf(name, sizeof(name), "%s", default_mlan_name);
4865 break;
4866 #endif
4867 #ifdef UAP_SUPPORT
4868 case MLAN_BSS_TYPE_UAP:
4869 if (handle->params.uap_name)
4870 snprintf(name, sizeof(name), "%s%%d",
4871 handle->params.uap_name);
4872 else if (handle->second_mac)
4873 snprintf(name, sizeof(name), "m%s", default_uap_name);
4874 else
4875 snprintf(name, sizeof(name), "%s", default_uap_name);
4876 break;
4877 #endif
4878 #ifdef WIFI_DIRECT_SUPPORT
4879 case MLAN_BSS_TYPE_WIFIDIRECT:
4880 if (handle->params.wfd_name)
4881 snprintf(name, sizeof(name), "%s%%d",
4882 handle->params.wfd_name);
4883 else if (handle->second_mac)
4884 snprintf(name, sizeof(name), "m%s", default_wfd_name);
4885 else
4886 snprintf(name, sizeof(name), "%s", default_wfd_name);
4887 break;
4888 #endif
4889 case MLAN_BSS_TYPE_DFS:
4890 if (handle->second_mac)
4891 snprintf(name, sizeof(name), "m%s", default_dfs_name);
4892 else
4893 snprintf(name, sizeof(name), "%s", default_dfs_name);
4894 break;
4895 default:
4896 PRINTM(MERROR, "woal_add_interface: invalid bss_type=%d\n",
4897 bss_type);
4898 return NULL;
4899 }
4900
4901 #define MAX_WMM_QUEUE 4
4902 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
4903 /* Allocate an net device */
4904 dev = alloc_netdev_mq(sizeof(moal_private), name, NET_NAME_UNKNOWN,
4905 ether_setup, MAX_WMM_QUEUE);
4906 #else
4907 dev = alloc_netdev_mq(sizeof(moal_private), name, ether_setup,
4908 MAX_WMM_QUEUE);
4909 #endif
4910
4911 if (!dev) {
4912 PRINTM(MERROR, "alloc_netdev failed\n");
4913 goto error;
4914 }
4915 priv = (moal_private *)netdev_priv(dev);
4916 /* Save the priv to handle */
4917 handle->priv[bss_index] = priv;
4918
4919 /* Use the same handle structure */
4920 priv->phandle = handle;
4921 priv->netdev = dev;
4922 priv->bss_index = bss_index;
4923 priv->bss_type = bss_type;
4924 priv->extra_tx_head_len = 0;
4925 if (bss_type == MLAN_BSS_TYPE_STA) {
4926 priv->bss_role = MLAN_BSS_ROLE_STA;
4927 } else if (bss_type == MLAN_BSS_TYPE_UAP) {
4928 priv->bss_role = MLAN_BSS_ROLE_UAP;
4929 }
4930 #ifdef WIFI_DIRECT_SUPPORT
4931 else if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
4932 priv->bss_role = MLAN_BSS_ROLE_STA;
4933 #endif
4934 else if (bss_type == MLAN_BSS_TYPE_DFS)
4935 priv->bss_role = MLAN_BSS_ROLE_UAP;
4936
4937 INIT_LIST_HEAD(&priv->tcp_sess_queue);
4938 spin_lock_init(&priv->tcp_sess_lock);
4939 #ifdef STA_SUPPORT
4940 INIT_LIST_HEAD(&priv->tdls_list);
4941 spin_lock_init(&priv->tdls_lock);
4942 #endif
4943
4944 INIT_LIST_HEAD(&priv->tx_stat_queue);
4945 spin_lock_init(&priv->tx_stat_lock);
4946 INIT_LIST_HEAD(&priv->mcast_list);
4947 spin_lock_init(&priv->mcast_lock);
4948
4949 #ifdef STA_CFG80211
4950 #ifdef STA_SUPPORT
4951 spin_lock_init(&priv->connect_lock);
4952 #endif
4953 #endif
4954
4955 #ifdef STA_SUPPORT
4956 INIT_LIST_HEAD(&priv->pmksa_cache_list);
4957 if (bss_type == MLAN_BSS_TYPE_STA) {
4958 init_waitqueue_head(&priv->okc_wait_q);
4959 spin_lock_init(&priv->pmksa_list_lock);
4960 priv->okc_roaming_ie = NULL;
4961 priv->okc_ie_len = 0;
4962 }
4963 #endif
4964 #if defined(DRV_EMBEDDED_AUTHENTICATOR)
4965 init_waitqueue_head(&priv->hostcmd_wait_q);
4966 #endif
4967 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
4968 SET_MODULE_OWNER(dev);
4969 #endif
4970 #ifdef STA_SUPPORT
4971 if (bss_type == MLAN_BSS_TYPE_STA
4972 #ifdef WIFI_DIRECT_SUPPORT
4973 || bss_type == MLAN_BSS_TYPE_WIFIDIRECT
4974 #endif
4975 )
4976 woal_init_sta_dev(dev, priv);
4977 #endif
4978 #ifdef UAP_SUPPORT
4979 if (bss_type == MLAN_BSS_TYPE_UAP || bss_type == MLAN_BSS_TYPE_DFS) {
4980 if (MLAN_STATUS_SUCCESS != woal_init_uap_dev(dev, priv))
4981 goto error;
4982 }
4983 #endif
4984 if (!handle->priv_num
4985 #ifdef MFG_CMD_SUPPORT
4986 && (handle->params.mfg_mode != MLAN_INIT_PARA_ENABLED)
4987 #endif
4988 ) {
4989 if (handle->params.init_cfg) {
4990 if (MLAN_STATUS_SUCCESS !=
4991 woal_set_user_init_data(handle, INIT_CFG_DATA,
4992 MOAL_IOCTL_WAIT, NULL)) {
4993 PRINTM(MFATAL,
4994 "Set user init data and param failed\n");
4995 goto error;
4996 }
4997 }
4998 if (handle->params.init_hostcmd_cfg) {
4999 if (MLAN_STATUS_SUCCESS !=
5000 woal_set_user_init_data(handle,
5001 INIT_HOSTCMD_CFG_DATA,
5002 MOAL_IOCTL_WAIT, NULL)) {
5003 PRINTM(MFATAL,
5004 "Set user init hostcmd data and param failed\n");
5005 goto error;
5006 }
5007 }
5008 }
5009 #ifdef MFG_CMD_SUPPORT
5010 if (handle->params.mfg_mode != MLAN_INIT_PARA_ENABLED) {
5011 #endif
5012 if (bss_type == MLAN_BSS_TYPE_UAP &&
5013 priv->phandle->params.band_steer_cfg) {
5014 if (MLAN_STATUS_SUCCESS !=
5015 woal_set_user_init_data(priv->phandle,
5016 BAND_STEER_CFG_DATA,
5017 MOAL_IOCTL_WAIT, NULL)) {
5018 PRINTM(MFATAL,
5019 "Set band steering configure param failed\n");
5020 }
5021 }
5022 #ifdef MFG_CMD_SUPPORT
5023 }
5024 #endif
5025
5026 handle->priv_num++;
5027 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
5028 if (!priv->phandle->wiphy &&
5029 IS_STA_OR_UAP_CFG80211(handle->params.cfg80211_wext)) {
5030 if (woal_register_cfg80211(priv)) {
5031 PRINTM(MERROR, "Cannot register with cfg80211\n");
5032 goto error;
5033 }
5034 }
5035 #endif
5036
5037 #ifdef STA_CFG80211
5038 #ifdef STA_SUPPORT
5039 if ((priv->bss_role == MLAN_BSS_ROLE_STA) &&
5040 IS_STA_CFG80211(handle->params.cfg80211_wext)) {
5041 if (bss_type == MLAN_BSS_TYPE_STA
5042 #ifdef WIFI_DIRECT_SUPPORT
5043 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
5044 || bss_type == MLAN_BSS_TYPE_WIFIDIRECT
5045 #endif
5046 #endif
5047 )
5048 /* Register cfg80211 for STA or Wifi direct */
5049 if (woal_register_sta_cfg80211(dev, bss_type)) {
5050 PRINTM(MERROR,
5051 "Cannot register STA with cfg80211\n");
5052 goto error;
5053 }
5054 }
5055
5056 #endif /* STA_SUPPORT */
5057 #endif /* STA_CFG80211 */
5058 #ifdef UAP_CFG80211
5059 #ifdef UAP_SUPPORT
5060 if ((priv->bss_role == MLAN_BSS_ROLE_UAP) &&
5061 IS_UAP_CFG80211(handle->params.cfg80211_wext) &&
5062 bss_type != MLAN_BSS_TYPE_DFS) {
5063 /* Register cfg80211 for UAP */
5064 if (woal_register_uap_cfg80211(dev, bss_type)) {
5065 PRINTM(MERROR, "Cannot register UAP with cfg80211\n");
5066 goto error;
5067 }
5068 }
5069 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
5070 strcpy(csa_str, "CSA");
5071 strcat(csa_str, name);
5072 priv->csa_workqueue = alloc_workqueue(
5073 csa_str, WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
5074 if (!priv->csa_workqueue) {
5075 PRINTM(MERROR, "cannot alloc csa workqueue \n");
5076 goto error;
5077 }
5078 INIT_DELAYED_WORK(&priv->csa_work, woal_csa_work_queue);
5079 #endif
5080 #endif
5081 #endif /*UAP_CFG80211 */
5082
5083 /* Create workqueue for main process */
5084 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
5085 priv->mclist_workqueue =
5086 alloc_workqueue("MCLIST_WORK_QUEUE",
5087 WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
5088 #else
5089 priv->mclist_workqueue = create_workqueue("MCLIST_WORK_QUEUE");
5090 #endif
5091 if (!priv->mclist_workqueue) {
5092 PRINTM(MERROR, "cannot alloc mclist workqueue \n");
5093 goto error;
5094 }
5095 MLAN_INIT_WORK(&priv->mclist_work, woal_mclist_work_queue);
5096
5097 /* Initialize priv structure */
5098 woal_init_priv(priv, MOAL_IOCTL_WAIT);
5099
5100 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
5101 SET_NETDEV_DEV(dev, handle->hotplug_device);
5102 #endif
5103
5104 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
5105 SET_NETDEV_DEVTYPE(dev, &wlan_type);
5106 #endif
5107
5108 /* Register network device */
5109 if (register_netdev(dev)) {
5110 PRINTM(MERROR, "Cannot register virtual network device\n");
5111 goto error;
5112 }
5113 netif_carrier_off(dev);
5114 woal_stop_queue(dev);
5115
5116 PRINTM(MMSG, "Register NXP 802.11 Adapter %s\n", dev->name);
5117
5118 if (bss_type == MLAN_BSS_TYPE_STA ||
5119 priv->bss_type == MLAN_BSS_TYPE_UAP) {
5120 #if defined(SD8887) || defined(SD8987)
5121 mlan_fw_info fw_info;
5122 memset(&fw_info, 0, sizeof(mlan_fw_info));
5123 if (MLAN_STATUS_SUCCESS !=
5124 woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info)) {
5125 PRINTM(MERROR, "%s: get_fw_info failed \n", __func__);
5126 goto error;
5127 }
5128 if (MFALSE
5129 #ifdef SD8887
5130 || IS_SD8887(handle->card_type)
5131 #endif
5132 #ifdef SD8987
5133 || IS_SD8987(handle->card_type)
5134 #endif
5135 ) {
5136 if ((fw_info.antinfo & ANT_DIVERSITY_2G) &&
5137 (fw_info.antinfo & ANT_DIVERSITY_5G))
5138 handle->card_info->histogram_table_num = 4;
5139 }
5140 #endif
5141
5142 for (i = 0; i < handle->card_info->histogram_table_num; i++) {
5143 priv->hist_data[i] =
5144 kmalloc(sizeof(hgm_data) +
5145 handle->card_info->rx_rate_max *
5146 sizeof(atomic_t),
5147 GFP_KERNEL);
5148 if (!(priv->hist_data[i])) {
5149 PRINTM(MERROR,
5150 "kmalloc priv->hist_data[%d] failed\n",
5151 i);
5152 goto error;
5153 }
5154 }
5155 woal_hist_data_reset(priv);
5156 }
5157 #ifdef CONFIG_PROC_FS
5158 woal_create_proc_entry(priv);
5159 woal_debug_entry(priv);
5160 #endif /* CONFIG_PROC_FS */
5161
5162 LEAVE();
5163 return priv;
5164 error:
5165 handle->priv_num = bss_index;
5166 /* Unregister wiphy device and free */
5167 if (priv) {
5168 if (priv->mclist_workqueue) {
5169 flush_workqueue(priv->mclist_workqueue);
5170 destroy_workqueue(priv->mclist_workqueue);
5171 priv->mclist_workqueue = NULL;
5172 }
5173 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
5174 if (priv->wdev &&
5175 IS_STA_OR_UAP_CFG80211(handle->params.cfg80211_wext))
5176 priv->wdev = NULL;
5177 #ifdef UAP_CFG80211
5178 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
5179 if (priv->csa_workqueue) {
5180 destroy_workqueue(priv->csa_workqueue);
5181 priv->csa_workqueue = NULL;
5182 }
5183 #endif
5184 #endif
5185 #endif
5186 }
5187 if (dev && dev->reg_state == NETREG_REGISTERED)
5188 unregister_netdev(dev);
5189 if (dev)
5190 free_netdev(dev);
5191 LEAVE();
5192 return NULL;
5193 }
5194
5195 /**
5196 * @brief This function removes an interface.
5197 *
5198 * @param handle A pointer to the moal_handle structure
5199 * @param bss_index BSS index number
5200 *
5201 * @return N/A
5202 */
5203 void woal_remove_interface(moal_handle *handle, t_u8 bss_index)
5204 {
5205 struct net_device *dev = NULL;
5206 moal_private *priv = handle->priv[bss_index];
5207 #if defined(STA_WEXT) || defined(UAP_WEXT)
5208 union iwreq_data wrqu;
5209 #endif
5210 int i = 0;
5211
5212 ENTER();
5213
5214 if (!priv || !priv->netdev)
5215 goto error;
5216 dev = priv->netdev;
5217
5218 if (priv->media_connected == MTRUE) {
5219 priv->media_connected = MFALSE;
5220 moal_connection_status_check_pmqos(handle);
5221 #if defined(STA_WEXT) || defined(UAP_WEXT)
5222 if (IS_STA_OR_UAP_WEXT(handle->params.cfg80211_wext) &&
5223 GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
5224 memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
5225 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
5226 wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu,
5227 NULL);
5228 }
5229 #endif
5230 }
5231 woal_flush_tcp_sess_queue(priv);
5232
5233 woal_flush_tx_stat_queue(priv);
5234
5235 #ifdef STA_CFG80211
5236 if (priv->bss_type == MLAN_BSS_TYPE_STA)
5237 woal_flush_tdls_list(priv);
5238 #endif
5239 woal_flush_mcast_list(priv);
5240
5241 #ifdef STA_CFG80211
5242 if (priv->bss_type == MLAN_BSS_TYPE_STA &&
5243 IS_STA_CFG80211(handle->params.cfg80211_wext)) {
5244 if (woal_flush_pmksa_list(priv))
5245 PRINTM(MERROR, "%s: woal_flush_pmksa_list failed!\n",
5246 __func__);
5247 if (priv->okc_roaming_ie) {
5248 kfree(priv->okc_roaming_ie);
5249 priv->okc_roaming_ie = NULL;
5250 priv->okc_ie_len = 0;
5251 }
5252 }
5253 #endif
5254
5255 if (priv->bss_type == MLAN_BSS_TYPE_STA ||
5256 priv->bss_type == MLAN_BSS_TYPE_UAP) {
5257 for (i = 0; i < handle->card_info->histogram_table_num; i++) {
5258 kfree(priv->hist_data[i]);
5259 priv->hist_data[i] = NULL;
5260 }
5261 }
5262 #ifdef CONFIG_PROC_FS
5263 /* Remove proc debug */
5264 woal_debug_remove(priv);
5265 woal_proc_remove(priv);
5266 #endif /* CONFIG_PROC_FS */
5267 /* Last reference is our one */
5268 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
5269 PRINTM(MINFO, "refcnt = %d\n", atomic_read(&dev->refcnt));
5270 #else
5271 PRINTM(MINFO, "refcnt = %d\n", netdev_refcnt_read(dev));
5272 #endif
5273
5274 PRINTM(MINFO, "netdev_finish_unregister: %s\n", dev->name);
5275
5276 if (dev->reg_state == NETREG_REGISTERED)
5277 unregister_netdev(dev);
5278
5279 if (priv->mclist_workqueue) {
5280 flush_workqueue(priv->mclist_workqueue);
5281 destroy_workqueue(priv->mclist_workqueue);
5282 priv->mclist_workqueue = NULL;
5283 }
5284
5285 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
5286 /* Unregister wiphy device and free */
5287 if (priv->wdev && IS_STA_OR_UAP_CFG80211(handle->params.cfg80211_wext))
5288 priv->wdev = NULL;
5289 #ifdef UAP_CFG80211
5290 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
5291 if (priv->csa_workqueue) {
5292 flush_workqueue(priv->csa_workqueue);
5293 destroy_workqueue(priv->csa_workqueue);
5294 priv->csa_workqueue = NULL;
5295 }
5296 #endif
5297 #endif
5298 #endif
5299 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
5300 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
5301 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA ||
5302 GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
5303 woal_deinit_wifi_hal(priv);
5304 #endif
5305 #endif
5306
5307 /* Clear the priv in handle */
5308 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
5309 #if LINUX_VERSION_CODE > KERNEL_VERSION(3, 8, 13)
5310 if (IS_STA_OR_UAP_CFG80211(handle->params.cfg80211_wext))
5311 priv->phandle->wiphy->extended_capabilities = NULL;
5312 #endif
5313 #endif
5314 priv->phandle->priv[priv->bss_index] = NULL;
5315 priv->phandle = NULL;
5316 priv->netdev = NULL;
5317 free_netdev(dev);
5318 error:
5319 LEAVE();
5320 return;
5321 }
5322
5323 /**
5324 * @brief Configure pmic in firmware
5325 *
5326 * @param handle A pointer to moal_handle
5327 * @param wait_option Wait option
5328 *
5329 * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
5330 * otherwise fail
5331 */
5332 mlan_status woal_pmic_configure(moal_handle *handle, t_u8 wait_option)
5333 {
5334 moal_private *priv = NULL;
5335 mlan_ioctl_req *req = NULL;
5336 mlan_ds_misc_cfg *misc = NULL;
5337 mlan_status status;
5338
5339 ENTER();
5340
5341 priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
5342 if (!priv) {
5343 LEAVE();
5344 return MLAN_STATUS_FAILURE;
5345 }
5346
5347 /* Allocate an IOCTL request buffer */
5348 req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
5349 sizeof(mlan_ds_misc_cfg));
5350 if (req == NULL) {
5351 status = MLAN_STATUS_FAILURE;
5352 goto done;
5353 }
5354
5355 /* Fill request buffer */
5356 misc = (mlan_ds_misc_cfg *)req->pbuf;
5357 misc->sub_command = MLAN_OID_MISC_PMIC_CFG;
5358 req->req_id = MLAN_IOCTL_MISC_CFG;
5359 req->action = MLAN_ACT_SET;
5360
5361 /* Send IOCTL request to MLAN */
5362 status = woal_request_ioctl(priv, req, wait_option);
5363 done:
5364 kfree(req);
5365 LEAVE();
5366 return status;
5367 }
5368
5369 /**
5370 * @brief Configure antcfg
5371 *
5372 * @param handle A pointer to moal_handle
5373 * @param wait_option Wait option
5374 *
5375 * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
5376 * otherwise fail
5377 */
5378 mlan_status woal_set_user_antcfg(moal_handle *handle, t_u8 wait_option)
5379 {
5380 moal_private *priv = NULL;
5381 mlan_ioctl_req *req = NULL;
5382 mlan_ds_radio_cfg *radio = NULL;
5383 mlan_status status;
5384 int antcfg;
5385
5386 ENTER();
5387 priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
5388 if (!priv) {
5389 LEAVE();
5390 return MLAN_STATUS_FAILURE;
5391 }
5392 antcfg = handle->params.antcfg;
5393 /* Allocate an IOCTL request buffer */
5394 req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
5395 sizeof(mlan_ds_radio_cfg));
5396 if (req == NULL) {
5397 status = MLAN_STATUS_FAILURE;
5398 goto done;
5399 }
5400
5401 /* Fill request buffer */
5402 radio = (mlan_ds_radio_cfg *)req->pbuf;
5403 radio->sub_command = MLAN_OID_ANT_CFG;
5404 req->req_id = MLAN_IOCTL_RADIO_CFG;
5405 req->action = MLAN_ACT_SET;
5406
5407 if (handle->feature_control & FEATURE_CTRL_STREAM_2X2) {
5408 if (IS_CARD9098(handle->card_type) ||
5409 IS_CARD9097(handle->card_type)) {
5410 radio->param.ant_cfg.tx_antenna =
5411 radio->param.ant_cfg.rx_antenna = antcfg;
5412 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
5413 woal_cfg80211_notify_antcfg(priv, priv->phandle->wiphy,
5414 radio);
5415 #endif
5416 } else {
5417 radio->param.ant_cfg.tx_antenna =
5418 (antcfg & 0x0030) >> 4;
5419 radio->param.ant_cfg.rx_antenna = antcfg & 0x0003;
5420 }
5421 } else
5422 radio->param.ant_cfg_1x1.antenna = antcfg;
5423 /* Send IOCTL request to MLAN */
5424 status = woal_request_ioctl(priv, req, wait_option);
5425 done:
5426 kfree(req);
5427 LEAVE();
5428 return status;
5429 }
5430
5431 /**
5432 * @brief Configure MLAN for low power mode
5433 *
5434 * @param priv A pointer to moal_private structure
5435 * @param wait_option Wait option
5436 *
5437 * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
5438 * otherwise fail
5439 */
5440 mlan_status woal_set_low_pwr_mode(moal_handle *handle, t_u8 wait_option)
5441 {
5442 moal_private *priv = NULL;
5443 mlan_ioctl_req *req = NULL;
5444 mlan_ds_misc_cfg *misc = NULL;
5445 mlan_status status;
5446
5447 ENTER();
5448
5449 priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
5450 if (!priv) {
5451 LEAVE();
5452 return MLAN_STATUS_FAILURE;
5453 }
5454
5455 /* Allocate an IOCTL request buffer */
5456 req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
5457 sizeof(mlan_ds_misc_cfg));
5458 if (req == NULL) {
5459 status = MLAN_STATUS_FAILURE;
5460 goto done;
5461 }
5462
5463 /* Fill request buffer */
5464 misc = (mlan_ds_misc_cfg *)req->pbuf;
5465 misc->sub_command = MLAN_OID_MISC_LOW_PWR_MODE;
5466 misc->param.low_pwr_mode = moal_extflg_isset(handle, EXT_LOW_PW_MODE);
5467 req->req_id = MLAN_IOCTL_MISC_CFG;
5468 req->action = MLAN_ACT_SET;
5469
5470 /* Send IOCTL request to MLAN */
5471 status = woal_request_ioctl(priv, req, wait_option);
5472 done:
5473 kfree(req);
5474 LEAVE();
5475 return status;
5476 }
5477
5478 /**
5479 * @brief Configure MLAN for channel tracking mode
5480 *
5481 * @param priv A pointer to moal_private structure
5482 * @param wait_option Wait option
5483 *
5484 * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
5485 * otherwise fail
5486 */
5487 mlan_status woal_set_chan_track_mode(moal_handle *handle, t_u8 wait_option)
5488 {
5489 moal_private *priv = NULL;
5490 mlan_ioctl_req *req = NULL;
5491 mlan_ds_snmp_mib *mib = NULL;
5492 mlan_status status;
5493
5494 ENTER();
5495
5496 priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
5497 if (!priv) {
5498 LEAVE();
5499 return MLAN_STATUS_FAILURE;
5500 }
5501
5502 /* Allocate an IOCTL request buffer */
5503 req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
5504 sizeof(mlan_ds_snmp_mib));
5505 if (req == NULL) {
5506 status = MLAN_STATUS_FAILURE;
5507 goto done;
5508 }
5509
5510 /* Fill request buffer */
5511 mib = (mlan_ds_snmp_mib *)req->pbuf;
5512 mib->sub_command = MLAN_OID_SNMP_MIB_CHAN_TRACK;
5513 mib->param.chan_track = moal_extflg_isset(handle, EXT_CHAN_TRACK);
5514 req->req_id = MLAN_IOCTL_SNMP_MIB;
5515 req->action = MLAN_ACT_SET;
5516
5517 /* Send IOCTL request to MLAN */
5518 status = woal_request_ioctl(priv, req, wait_option);
5519 done:
5520 kfree(req);
5521 LEAVE();
5522 return status;
5523 }
5524
5525 /**
5526 * @brief Send FW shutdown command to MLAN
5527 *
5528 * @param priv A pointer to moal_private structure
5529 * @param wait_option Wait option
5530 *
5531 * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
5532 * otherwise fail
5533 */
5534 mlan_status woal_shutdown_fw(moal_private *priv, t_u8 wait_option)
5535 {
5536 mlan_ioctl_req *req = NULL;
5537 mlan_ds_misc_cfg *misc = NULL;
5538 mlan_status status;
5539
5540 ENTER();
5541
5542 /* Allocate an IOCTL request buffer */
5543 req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
5544 sizeof(mlan_ds_misc_cfg));
5545 if (req == NULL) {
5546 status = MLAN_STATUS_FAILURE;
5547 goto done;
5548 }
5549
5550 /* Fill request buffer */
5551 misc = (mlan_ds_misc_cfg *)req->pbuf;
5552 misc->sub_command = MLAN_OID_MISC_INIT_SHUTDOWN;
5553 misc->param.func_init_shutdown = MLAN_FUNC_SHUTDOWN;
5554 req->req_id = MLAN_IOCTL_MISC_CFG;
5555 req->action = MLAN_ACT_SET;
5556
5557 /* Send IOCTL request to MLAN */
5558 status = woal_request_ioctl(priv, req, wait_option);
5559 /* add 100 ms delay to avoid back to back init/shutdown */
5560 mdelay(100);
5561 done:
5562 if (status != MLAN_STATUS_PENDING)
5563 kfree(req);
5564 LEAVE();
5565 return status;
5566 }
5567
5568 /**
5569 * @brief Return hex value of a give character
5570 *
5571 * @param chr Character to be converted
5572 *
5573 * @return The converted character if chr is a valid hex, else 0
5574 */
5575 int woal_hexval(char chr)
5576 {
5577 if (chr >= '0' && chr <= '9')
5578 return chr - '0';
5579 if (chr >= 'A' && chr <= 'F')
5580 return chr - 'A' + 10;
5581 if (chr >= 'a' && chr <= 'f')
5582 return chr - 'a' + 10;
5583
5584 return 0;
5585 }
5586
5587 #ifdef STA_SUPPORT
5588 #endif
5589
5590 /**
5591 * @brief This function flush event queue
5592 *
5593 * @param priv A pointer to moal_private structure
5594 *
5595 * @return N/A
5596 */
5597 static void woal_flush_evt_queue(moal_handle *handle)
5598 {
5599 struct woal_event *evt = NULL, *tmp_node;
5600 unsigned long flags;
5601 spin_lock_irqsave(&handle->evt_lock, flags);
5602 list_for_each_entry_safe (evt, tmp_node, &handle->evt_queue, link) {
5603 list_del(&evt->link);
5604 spin_unlock_irqrestore(&handle->evt_lock, flags);
5605 kfree(evt);
5606 spin_lock_irqsave(&handle->evt_lock, flags);
5607 }
5608 INIT_LIST_HEAD(&handle->evt_queue);
5609 spin_unlock_irqrestore(&handle->evt_lock, flags);
5610 }
5611
5612 /**
5613 * @brief This function flush all works in the queue
5614 *
5615 * @param handle A pointer to moal_handle
5616 *
5617 * @return N/A
5618 */
5619 void woal_flush_workqueue(moal_handle *handle)
5620 {
5621 ENTER();
5622
5623 /* Terminate main workqueue */
5624 if (handle->workqueue)
5625 flush_workqueue(handle->workqueue);
5626 if (handle->rx_workqueue)
5627 flush_workqueue(handle->rx_workqueue);
5628 if (handle->evt_workqueue)
5629 flush_workqueue(handle->evt_workqueue);
5630 if (handle->tx_workqueue)
5631 flush_workqueue(handle->tx_workqueue);
5632 LEAVE();
5633 }
5634
5635 /**
5636 * @brief This function cancel all works in the queue
5637 * and destroy the main workqueue.
5638 *
5639 * @param handle A pointer to moal_handle
5640 *
5641 * @return N/A
5642 */
5643 void woal_terminate_workqueue(moal_handle *handle)
5644 {
5645 ENTER();
5646
5647 /* Terminate main workqueue */
5648 if (handle->workqueue) {
5649 flush_workqueue(handle->workqueue);
5650 destroy_workqueue(handle->workqueue);
5651 handle->workqueue = NULL;
5652 }
5653 if (handle->rx_workqueue) {
5654 flush_workqueue(handle->rx_workqueue);
5655 destroy_workqueue(handle->rx_workqueue);
5656 handle->rx_workqueue = NULL;
5657 }
5658 if (handle->evt_workqueue) {
5659 woal_flush_evt_queue(handle);
5660 flush_workqueue(handle->evt_workqueue);
5661 destroy_workqueue(handle->evt_workqueue);
5662 handle->evt_workqueue = NULL;
5663 }
5664 if (handle->tx_workqueue) {
5665 flush_workqueue(handle->tx_workqueue);
5666 destroy_workqueue(handle->tx_workqueue);
5667 handle->tx_workqueue = NULL;
5668 }
5669 LEAVE();
5670 }
5671
5672 /********************************************************
5673 Global Functions
5674 ********************************************************/
5675
5676 /**
5677 * @brief This function opens the network device
5678 *
5679 * @param dev A pointer to net_device structure
5680 *
5681 * @return 0 --success, otherwise fail
5682 */
5683 int woal_open(struct net_device *dev)
5684 {
5685 moal_private *priv = (moal_private *)netdev_priv(dev);
5686 #if defined(USB)
5687 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
5688 struct usb_interface *intf =
5689 ((struct usb_card_rec *)priv->phandle->card)->intf;
5690 #else
5691 // struct usb_device *udev = ((struct usb_card_rec
5692 // *)(priv->phandle->card))->udev;
5693 #endif /* < 2.6.34 */
5694 #endif /* USB_SUSPEND_RESUME */
5695 t_u8 carrier_on = MFALSE;
5696
5697 ENTER();
5698
5699 if (priv->phandle->surprise_removed == MTRUE) {
5700 PRINTM(MERROR,
5701 "open is not allowed in surprise remove state.\n");
5702 LEAVE();
5703 return -EFAULT;
5704 }
5705 #if defined(USB)
5706 if (IS_USB(priv->phandle->card_type)) {
5707 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
5708 /* Error enabling PM on interface */
5709 if (usb_autopm_get_interface(intf)) {
5710 LEAVE();
5711 return -EIO;
5712 }
5713 #else
5714 // atomic_set(&udev->dev.power.usage_count, 1);
5715 #endif /* < 2.6.34 */
5716 }
5717 #endif /* USB_SUSPEND_RESUME */
5718
5719 #if defined(USB) || defined(SYSKT)
5720 /* On some systems the device open handler will be called before HW
5721 ready.
5722 Use the following flag check and wait function to work around
5723 the issue. */
5724 if (MTRUE
5725 #ifdef SDIO
5726 && !IS_SD(priv->phandle->card_type)
5727 #endif
5728 #ifdef PCIE
5729 && !IS_PCIE(priv->phandle->card_type)
5730 #endif
5731 ) {
5732 int i = 0;
5733
5734 while ((priv->phandle->hardware_status !=
5735 HardwareStatusReady) &&
5736 (i < MAX_WAIT_DEVICE_READY_COUNT)) {
5737 i++;
5738 woal_sched_timeout(100);
5739 }
5740 if (i >= MAX_WAIT_DEVICE_READY_COUNT) {
5741 PRINTM(MFATAL,
5742 "HW not ready, wlan_open() return failure\n");
5743 LEAVE();
5744 return -EFAULT;
5745 }
5746 }
5747 #endif /* USB || SYSKT || SYSKT_MULTI */
5748 if (!MODULE_GET) {
5749 LEAVE();
5750 return -EFAULT;
5751 }
5752 #ifdef UAP_SUPPORT
5753 if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
5754 (priv->media_connected))
5755 carrier_on = MTRUE;
5756 #endif
5757 #ifdef STA_SUPPORT
5758 if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
5759 (priv->media_connected || priv->is_adhoc_link_sensed))
5760 carrier_on = MTRUE;
5761 #endif
5762
5763 if (carrier_on == MTRUE) {
5764 if (!netif_carrier_ok(priv->netdev))
5765 netif_carrier_on(priv->netdev);
5766 woal_wake_queue(priv->netdev);
5767 } else {
5768 if (netif_carrier_ok(priv->netdev))
5769 netif_carrier_off(priv->netdev);
5770 }
5771
5772 LEAVE();
5773 return 0;
5774 }
5775
5776 /**
5777 * @brief This function closes the network device
5778 *
5779 * @param dev A pointer to net_device structure
5780 *
5781 * @return 0
5782 */
5783 int woal_close(struct net_device *dev)
5784 {
5785 moal_private *priv = (moal_private *)netdev_priv(dev);
5786 #if defined(USB)
5787 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
5788 struct usb_interface *intf =
5789 ((struct usb_card_rec *)priv->phandle->card)->intf;
5790 #else
5791 // struct usb_device *udev = ((struct usb_card_rec
5792 // *)(priv->phandle->card))->udev;
5793 #endif /* < 2.6.34 */
5794 #endif /* USB_SUSPEND_RESUME */
5795 #ifdef STA_CFG80211
5796 int cfg80211_wext = priv->phandle->params.cfg80211_wext;
5797 #endif
5798 ENTER();
5799
5800 woal_flush_tx_stat_queue(priv);
5801
5802 #ifdef STA_SUPPORT
5803 #ifdef STA_CFG80211
5804 if (IS_STA_CFG80211(cfg80211_wext))
5805 woal_clear_conn_params(priv);
5806 woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
5807
5808 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
5809 #if ((CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) || IMX_ANDROID_13)
5810 if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev->connected) {
5811 #else
5812 if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev->current_bss) {
5813 #endif
5814 priv->cfg_disconnect = MTRUE;
5815 cfg80211_disconnected(priv->netdev, 0, NULL, 0,
5816 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
5817 true,
5818 #endif
5819 GFP_KERNEL);
5820 }
5821 #endif
5822
5823 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
5824 if (IS_STA_CFG80211(cfg80211_wext) && priv->sched_scanning) {
5825 woal_stop_bg_scan(priv, MOAL_IOCTL_WAIT);
5826 priv->bg_scan_start = MFALSE;
5827 priv->bg_scan_reported = MFALSE;
5828 cfg80211_sched_scan_stopped(priv->wdev->wiphy
5829 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
5830 ,
5831 priv->bg_scan_reqid
5832 #endif
5833 );
5834 priv->sched_scanning = MFALSE;
5835 }
5836 #endif
5837 #endif
5838 #endif
5839 if (!priv->bss_virtual)
5840 woal_stop_queue(priv->netdev);
5841 MODULE_PUT;
5842 #if defined(USB)
5843 if (IS_USB(priv->phandle->card_type)) {
5844 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
5845 usb_autopm_put_interface(intf);
5846 #else
5847 // atomic_set(&udev->dev.power.usage_count, 0);
5848 #endif /* < 2.6.34 */
5849 }
5850 #endif /* USB_SUSPEND_RESUME */
5851
5852 LEAVE();
5853 return 0;
5854 }
5855
5856 #define DEF_MTU_SIZE 1500
5857 /**
5858 * @brief This function disable the ampdu
5859 *
5860 * @param priv A pointer to mlan_private structure
5861 * @param new_mtu new mtu size
5862 *
5863 * @return 0 --success, otherwise fail
5864 */
5865 void woal_disable_ampdu(moal_private *priv)
5866 {
5867 mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl;
5868 int i;
5869 memset(&aggr_prio_tbl, 0, sizeof(aggr_prio_tbl));
5870 if (MLAN_STATUS_SUCCESS !=
5871 woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_GET, &aggr_prio_tbl)) {
5872 goto done;
5873 }
5874 for (i = 0; i < MAX_NUM_TID; i++)
5875 aggr_prio_tbl.ampdu[i] = 0xff;
5876 if (MLAN_STATUS_SUCCESS !=
5877 woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_SET, &aggr_prio_tbl)) {
5878 goto done;
5879 }
5880 done:
5881 return;
5882 }
5883
5884 /**
5885 * @brief This function change the MTU size
5886 *
5887 * @param dev A pointer to mlan_private structure
5888 * @param new_mtu new mtu size
5889 *
5890 * @return 0 --success, otherwise fail
5891 */
5892 int woal_change_mtu(struct net_device *dev, int new_mtu)
5893 {
5894 moal_private *priv = (moal_private *)netdev_priv(dev);
5895 dev->mtu = new_mtu;
5896 // disable AMPDU with mtu size > 1500
5897 if (new_mtu > DEF_MTU_SIZE)
5898 woal_disable_ampdu(priv);
5899 PRINTM(MCMND, "wlan: change_mtu to %d\n", new_mtu);
5900
5901 return 0;
5902 }
5903
5904 /**
5905 * @brief This function sets the MAC address to firmware.
5906 *
5907 * @param dev A pointer to mlan_private structure
5908 * @param addr MAC address to set
5909 *
5910 * @return 0 --success, otherwise fail
5911 */
5912 int woal_set_mac_address(struct net_device *dev, void *addr)
5913 {
5914 int ret = 0;
5915 moal_private *priv = (moal_private *)netdev_priv(dev);
5916 struct sockaddr *phw_addr = (struct sockaddr *)addr;
5917 t_u8 prev_addr[ETH_ALEN];
5918
5919 ENTER();
5920
5921 if (priv->phandle->surprise_removed == MTRUE) {
5922 PRINTM(MERROR,
5923 "Set mac address is not allowed in surprise remove state.\n");
5924 LEAVE();
5925 return -EFAULT;
5926 }
5927
5928 moal_memcpy_ext(priv->phandle, prev_addr, priv->current_addr, ETH_ALEN,
5929 ETH_ALEN);
5930 memset(priv->current_addr, 0, ETH_ALEN);
5931 /* dev->dev_addr is 6 bytes */
5932 HEXDUMP("dev->dev_addr:", (t_u8 *)dev->dev_addr, ETH_ALEN);
5933
5934 HEXDUMP("addr:", (t_u8 *)phw_addr->sa_data, ETH_ALEN);
5935 moal_memcpy_ext(priv->phandle, priv->current_addr, phw_addr->sa_data,
5936 ETH_ALEN, ETH_ALEN);
5937 #ifdef WIFI_DIRECT_SUPPORT
5938 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
5939 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
5940 if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
5941 priv->current_addr[0] |= 0x02;
5942 PRINTM(MCMND, "Set WFD device addr: " MACSTR "\n",
5943 MAC2STR(priv->current_addr));
5944 }
5945 #endif
5946 #endif
5947 #endif
5948 if (MLAN_STATUS_SUCCESS !=
5949 woal_request_set_mac_address(priv, MOAL_IOCTL_WAIT)) {
5950 PRINTM(MERROR, "Set MAC address failed\n");
5951 /* For failure restore the MAC address */
5952 moal_memcpy_ext(priv->phandle, priv->current_addr, prev_addr,
5953 ETH_ALEN, ETH_ALEN);
5954 ret = -EFAULT;
5955 goto done;
5956 }
5957 HEXDUMP("priv->MacAddr:", priv->current_addr, ETH_ALEN);
5958 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
5959 eth_hw_addr_set(dev, priv->current_addr);
5960 #else
5961 moal_memcpy_ext(priv->phandle, dev->dev_addr, priv->current_addr,
5962 ETH_ALEN, ETH_ALEN);
5963 #endif
5964 done:
5965 LEAVE();
5966 return ret;
5967 }
5968
5969 /**
5970 * @brief Check driver status
5971 *
5972 * @param handle A pointer to moal_handle
5973 *
5974 * @return MTRUE/MFALSE
5975 */
5976 t_u8 woal_check_driver_status(moal_handle *handle)
5977 {
5978 moal_private *priv = NULL;
5979 wifi_timeval t;
5980 int i = 0;
5981 mlan_debug_info *info = &(handle->debug_info);
5982
5983 ENTER();
5984
5985 priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
5986 if (!priv || woal_get_debug_info(priv, MOAL_IOCTL_WAIT, info)) {
5987 PRINTM(MERROR,
5988 "Could not retrieve debug information from MLAN\n");
5989 LEAVE();
5990 return MTRUE;
5991 }
5992 #define MOAL_CMD_TIMEOUT_MAX 9
5993 #define MOAL_CMD_TIMEOUT 20
5994 woal_get_monotonic_time(&t);
5995 if (info->dnld_cmd_in_secs && info->pending_cmd &&
5996 (t.time_sec > (info->dnld_cmd_in_secs + MOAL_CMD_TIMEOUT_MAX))) {
5997 if (t.time_sec > (info->dnld_cmd_in_secs + MOAL_CMD_TIMEOUT) &&
5998 !info->num_cmd_timeout) {
5999 PRINTM(MERROR, "Ignore invalid time, wait=%d\n",
6000 (int)(t.time_sec - info->dnld_cmd_in_secs));
6001 } else {
6002 PRINTM(MERROR, "Timeout cmd id = 0x%x wait=%d\n",
6003 info->pending_cmd,
6004 (int)(t.time_sec - info->dnld_cmd_in_secs));
6005 LEAVE();
6006 return MTRUE;
6007 }
6008 }
6009 if (info->num_cmd_timeout) {
6010 PRINTM(MERROR, "num_cmd_timeout = %d\n", info->num_cmd_timeout);
6011 PRINTM(MERROR, "Timeout cmd id = 0x%x, act = 0x%x\n",
6012 info->timeout_cmd_id, info->timeout_cmd_act);
6013 LEAVE();
6014 return MTRUE;
6015 }
6016 if (info->num_cmd_host_to_card_failure) {
6017 PRINTM(MERROR, "num_cmd_host_to_card_failure = %d\n",
6018 info->num_cmd_host_to_card_failure);
6019 LEAVE();
6020 return MTRUE;
6021 }
6022 if (info->num_no_cmd_node) {
6023 PRINTM(MERROR, "num_no_cmd_node = %d\n", info->num_no_cmd_node);
6024 LEAVE();
6025 return MTRUE;
6026 }
6027 for (i = 0; i < handle->priv_num; i++) {
6028 priv = handle->priv[i];
6029 if (priv) {
6030 if (priv->num_tx_timeout >= NUM_TX_TIMEOUT_THRESHOLD) {
6031 PRINTM(MERROR, "num_tx_timeout = %d\n",
6032 priv->num_tx_timeout);
6033 LEAVE();
6034 return MTRUE;
6035 }
6036 }
6037 }
6038 if (info->pm_wakeup_card_req && info->pm_wakeup_fw_try) {
6039 #define MAX_WAIT_TIME 3
6040 if (t.time_sec > (info->pm_wakeup_in_secs + MAX_WAIT_TIME)) {
6041 PRINTM(MERROR,
6042 "wakeup_dev_req=%d wakeup_tries=%d wait=%d\n",
6043 info->pm_wakeup_card_req, info->pm_wakeup_fw_try,
6044 (int)(t.time_sec - info->pm_wakeup_in_secs));
6045 LEAVE();
6046 return MTRUE;
6047 }
6048 }
6049 if (info->fw_hang_report) {
6050 PRINTM(MERROR, "fw_hang_report = %d\n", info->fw_hang_report);
6051 LEAVE();
6052 return MTRUE;
6053 }
6054
6055 if (priv && priv->phandle->driver_status) {
6056 LEAVE();
6057 return MTRUE;
6058 }
6059
6060 LEAVE();
6061 return MFALSE;
6062 }
6063
6064 /**
6065 * @brief Display MLAN debug information
6066 *
6067 * @param priv A pointer to moal_private
6068 *
6069 * @return N/A
6070 */
6071 void woal_mlan_debug_info(moal_private *priv)
6072 {
6073 int i;
6074 #ifdef SDIO
6075 int j;
6076 t_u8 mp_aggr_pkt_limit = 0;
6077 #endif
6078 char str[512] = {0};
6079 char *s;
6080 mlan_debug_info *info = NULL;
6081
6082 ENTER();
6083
6084 if (!priv || !priv->phandle) {
6085 PRINTM(MERROR, "priv or priv->phandle is null\n");
6086 LEAVE();
6087 return;
6088 }
6089
6090 info = &(priv->phandle->debug_info);
6091
6092 if (woal_get_debug_info(priv, MOAL_IOCTL_WAIT, info)) {
6093 PRINTM(MERROR,
6094 "Could not retrieve debug information from MLAN\n");
6095 LEAVE();
6096 return;
6097 }
6098 PRINTM(MERROR, "------------mlan_debug_info-------------\n");
6099 PRINTM(MERROR, "mlan_processing =%d\n", info->mlan_processing);
6100 PRINTM(MERROR, "main_lock_flag =%d\n", info->main_lock_flag);
6101 PRINTM(MERROR, "main_process_cnt =%d\n", info->main_process_cnt);
6102 PRINTM(MERROR, "delay_task_flag =%d\n", info->delay_task_flag);
6103 PRINTM(MERROR, "mlan_rx_processing =%d\n", info->mlan_rx_processing);
6104 PRINTM(MERROR, "rx_pkts_queued=%d\n", info->rx_pkts_queued);
6105 PRINTM(MERROR, "tx_pkts_queued=%d\n", info->tx_pkts_queued);
6106 PRINTM(MERROR, "fw_hang_report = %d\n", info->fw_hang_report);
6107 PRINTM(MERROR, "num_cmd_timeout = %d\n", info->num_cmd_timeout);
6108 PRINTM(MERROR, "Timeout cmd id = 0x%x, act = 0x%x\n",
6109 info->timeout_cmd_id, info->timeout_cmd_act);
6110
6111 PRINTM(MERROR, "last_cmd_index = %d\n", info->last_cmd_index);
6112 for (s = str, i = 0; i < DBG_CMD_NUM; i++)
6113 s += sprintf(s, "0x%x ", info->last_cmd_id[i]);
6114 PRINTM(MERROR, "last_cmd_id = %s\n", str);
6115 for (s = str, i = 0; i < DBG_CMD_NUM; i++)
6116 s += sprintf(s, "0x%x ", info->last_cmd_act[i]);
6117 PRINTM(MERROR, "last_cmd_act = %s\n", str);
6118 PRINTM(MERROR, "last_cmd_resp_index = %d\n", info->last_cmd_resp_index);
6119 for (s = str, i = 0; i < DBG_CMD_NUM; i++)
6120 s += sprintf(s, "0x%x ", info->last_cmd_resp_id[i]);
6121 PRINTM(MERROR, "last_cmd_resp_id = %s\n", str);
6122 PRINTM(MERROR, "last_event_index = %d\n", info->last_event_index);
6123 for (s = str, i = 0; i < DBG_CMD_NUM; i++)
6124 s += sprintf(s, "0x%x ", info->last_event[i]);
6125 PRINTM(MERROR, "last_event = %s", str);
6126
6127 PRINTM(MERROR, "num_data_h2c_failure = %d\n",
6128 info->num_tx_host_to_card_failure);
6129 PRINTM(MERROR, "num_cmd_h2c_failure = %d\n",
6130 info->num_cmd_host_to_card_failure);
6131 PRINTM(MERROR, "num_alloc_buffer_failure = %d\n",
6132 info->num_alloc_buffer_failure);
6133 PRINTM(MERROR, "num_pkt_dropped = %d\n", info->num_pkt_dropped);
6134
6135 #ifdef SDIO
6136 if (IS_SD(priv->phandle->card_type)) {
6137 PRINTM(MERROR, "num_data_c2h_failure = %d\n",
6138 info->num_rx_card_to_host_failure);
6139 PRINTM(MERROR, "num_cmdevt_c2h_failure = %d\n",
6140 info->num_cmdevt_card_to_host_failure);
6141 PRINTM(MERROR, "num_int_read_failure = %d\n",
6142 info->num_int_read_failure);
6143 PRINTM(MERROR, "last_int_status = %d\n", info->last_int_status);
6144
6145 PRINTM(MERROR, "mp_rd_bitmap=0x%x curr_rd_port=0x%x\n",
6146 (unsigned int)info->mp_rd_bitmap, info->curr_rd_port);
6147 PRINTM(MERROR, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n",
6148 (unsigned int)info->mp_wr_bitmap, info->curr_wr_port);
6149 PRINTM(MERROR, "mp_data_port_mask=0x%x\n",
6150 info->mp_data_port_mask);
6151 PRINTM(MERROR,
6152 "last_recv_rd_bitmap=0x%x mp_invalid_update=%d\n",
6153 info->last_recv_rd_bitmap, info->mp_invalid_update);
6154 mp_aggr_pkt_limit = info->mp_aggr_pkt_limit;
6155 PRINTM(MERROR, "last_recv_wr_bitmap=0x%x last_mp_index = %d\n",
6156 info->last_recv_wr_bitmap, info->last_mp_index);
6157 for (i = 0; i < SDIO_MP_DBG_NUM; i++) {
6158 for (s = str, j = 0; j < mp_aggr_pkt_limit; j++)
6159 s += sprintf(
6160 s, "0x%02x ",
6161 info->last_mp_wr_info
6162 [i * mp_aggr_pkt_limit + j]);
6163
6164 PRINTM(MERROR,
6165 "mp_wr_bitmap: 0x%x mp_wr_ports=0x%x len=%d curr_wr_port=0x%x\n%s\n",
6166 info->last_mp_wr_bitmap[i],
6167 info->last_mp_wr_ports[i],
6168 info->last_mp_wr_len[i],
6169 info->last_curr_wr_port[i], str);
6170 }
6171 }
6172 #endif
6173 #ifdef PCIE
6174 if (IS_PCIE(priv->phandle->card_type)) {
6175 PRINTM(MERROR, "txbd_rdptr=0x%x txbd_wrptr=0x%x\n",
6176 info->txbd_rdptr, info->txbd_wrptr);
6177 PRINTM(MERROR, "rxbd_rdptr=0x%x rxbd_wrptr=0x%x\n",
6178 info->rxbd_rdptr, info->rxbd_wrptr);
6179 PRINTM(MERROR, "eventbd_rdptr=0x%x event_wrptr=0x%x\n",
6180 info->eventbd_rdptr, info->eventbd_wrptr);
6181 PRINTM(MERROR, "last_wr_index:%d\n",
6182 info->txbd_wrptr & (info->txrx_bd_size - 1));
6183 PRINTM(MERROR, "TxRx BD size:%d\n", info->txrx_bd_size);
6184 }
6185 #endif
6186 PRINTM(MERROR, "num_event_deauth = %d\n", info->num_event_deauth);
6187 PRINTM(MERROR, "num_event_disassoc = %d\n", info->num_event_disassoc);
6188 PRINTM(MERROR, "num_event_link_lost = %d\n", info->num_event_link_lost);
6189 PRINTM(MERROR, "num_cmd_deauth = %d\n", info->num_cmd_deauth);
6190 PRINTM(MERROR, "num_cmd_assoc_success = %d\n",
6191 info->num_cmd_assoc_success);
6192 PRINTM(MERROR, "num_cmd_assoc_failure = %d\n",
6193 info->num_cmd_assoc_failure);
6194 PRINTM(MERROR, "num_cons_assoc_failure = %d\n",
6195 info->num_cons_assoc_failure);
6196 PRINTM(MERROR, "cmd_resp_received = %d\n", info->cmd_resp_received);
6197 PRINTM(MERROR, "event_received = %d\n", info->event_received);
6198
6199 PRINTM(MERROR, "max_tx_buf_size = %d\n", info->max_tx_buf_size);
6200 PRINTM(MERROR, "tx_buf_size = %d\n", info->tx_buf_size);
6201 PRINTM(MERROR, "curr_tx_buf_size = %d\n", info->curr_tx_buf_size);
6202 PRINTM(MERROR, "bypass_pkt_count=%d\n", info->bypass_pkt_count);
6203
6204 PRINTM(MERROR, "data_sent=%d cmd_sent=%d\n", info->data_sent,
6205 info->cmd_sent);
6206 PRINTM(MERROR, "data_sent_cnt=%u\n", info->data_sent_cnt);
6207
6208 PRINTM(MERROR, "ps_mode=%d ps_state=%d\n", info->ps_mode,
6209 info->ps_state);
6210 PRINTM(MERROR, "wakeup_dev_req=%d wakeup_tries=%d wakeup_timeout=%d\n",
6211 info->pm_wakeup_card_req, info->pm_wakeup_fw_try,
6212 info->pm_wakeup_timeout);
6213 PRINTM(MERROR, "hs_configured=%d hs_activated=%d\n",
6214 info->is_hs_configured, info->hs_activated);
6215 PRINTM(MERROR, "pps_uapsd_mode=%d sleep_pd=%d\n", info->pps_uapsd_mode,
6216 info->sleep_pd);
6217 PRINTM(MERROR, "tx_lock_flag = %d\n", info->tx_lock_flag);
6218 PRINTM(MERROR, "port_open = %d\n", info->port_open);
6219 PRINTM(MERROR, "scan_processing = %d\n", info->scan_processing);
6220 PRINTM(MERROR, "scan_state = 0x%x\n", info->scan_state);
6221 for (i = 0; i < (int)info->ralist_num; i++) {
6222 PRINTM(MERROR,
6223 "ralist ra: %02x:%02x:%02x:%02x:%02x:%02x tid=%d pkts=%d pause=%d\n",
6224 info->ralist[i].ra[0], info->ralist[i].ra[1],
6225 info->ralist[i].ra[2], info->ralist[i].ra[3],
6226 info->ralist[i].ra[4], info->ralist[i].ra[5],
6227 info->ralist[i].tid, info->ralist[i].total_pkts,
6228 info->ralist[i].tx_pause);
6229 }
6230
6231 #ifdef PCIE
6232 if (IS_PCIE(priv->phandle->card_type)) {
6233 PRINTM(MERROR, "txbd: rdptr=0x%x wrptr=0x%x\n",
6234 info->txbd_rdptr, info->txbd_wrptr);
6235 PRINTM(MERROR, "rxbd: rdptr=0x%x wrptr=0x%x\n",
6236 info->rxbd_rdptr, info->rxbd_wrptr);
6237 PRINTM(MERROR, "eventbd: rdptr=0x%x wrptr=0x%x\n",
6238 info->eventbd_rdptr, info->eventbd_wrptr);
6239 }
6240 #endif
6241 PRINTM(MERROR, "------------mlan_debug_info End-------------\n");
6242 LEAVE();
6243 }
6244
6245 /**
6246 * @brief This function handle the shutdown timeout issue
6247 *
6248 * @param handle Pointer to structure moal_handle
6249 *
6250 * @return N/A
6251 */
6252 static void woal_ioctl_timeout(moal_handle *handle)
6253 {
6254 moal_private *priv = NULL;
6255
6256 ENTER();
6257
6258 PRINTM(MMSG, "woal_ioctl_timout.\n");
6259 priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
6260 if (priv) {
6261 woal_mlan_debug_info(priv);
6262 woal_moal_debug_info(priv, NULL, MFALSE);
6263 }
6264 LEAVE();
6265 return;
6266 }
6267
6268 /**
6269 * @brief This function handles the timeout of packet
6270 * transmission
6271 *
6272 * @param dev A pointer to net_device structure
6273 *
6274 * @return N/A
6275 */
6276 void woal_tx_timeout(struct net_device *dev
6277 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
6278 ,
6279 unsigned int txqueue
6280 #endif
6281 )
6282 {
6283 moal_private *priv = (moal_private *)netdev_priv(dev);
6284 t_u8 auto_fw_dump = MFALSE;
6285 ENTER();
6286
6287 priv->num_tx_timeout++;
6288 PRINTM(MERROR, "%lu : %s (bss=%d): Tx timeout (%d)\n", jiffies,
6289 dev->name, priv->bss_index, priv->num_tx_timeout);
6290 woal_set_trans_start(dev);
6291
6292 if (priv->num_tx_timeout == NUM_TX_TIMEOUT_THRESHOLD &&
6293 priv->txwatchdog_disable == MFALSE) {
6294 #ifdef DEBUG_LEVEL1
6295 if (drvdbg & MFW_D)
6296 auto_fw_dump = MTRUE;
6297 #endif
6298 woal_mlan_debug_info(priv);
6299 woal_moal_debug_info(priv, NULL, MFALSE);
6300 priv->phandle->driver_status = MTRUE;
6301 if (!auto_fw_dump && !priv->phandle->fw_dump)
6302 woal_process_hang(priv->phandle);
6303
6304 wifi_status = WIFI_STATUS_TX_TIMEOUT;
6305 }
6306
6307 LEAVE();
6308 }
6309
6310 /**
6311 * @brief This function returns the network statistics
6312 *
6313 * @param dev A pointer to net_device structure
6314 *
6315 * @return A pointer to net_device_stats structure
6316 */
6317 struct net_device_stats *woal_get_stats(struct net_device *dev)
6318 {
6319 moal_private *priv = (moal_private *)netdev_priv(dev);
6320 return &priv->stats;
6321 }
6322
6323 #if !defined(STA_CFG80211) && !defined(UAP_CFG80211)
6324 /**
6325 * @brief This function determine the 802.1p/1d tag to use
6326 *
6327 * @param skb
6328 *
6329 * @return tid
6330 */
6331 unsigned int woal_classify8021d(struct sk_buff *skb)
6332 {
6333 unsigned int dscp;
6334 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
6335 unsigned char vlan_priority;
6336 #endif
6337 unsigned int tid;
6338
6339 /* skb->priority values from 256->263 are magic values to
6340 * directly indicate a specific 802.1d priority. This is used
6341 * to allow 802.1d priority to be passed directly in from VLAN
6342 * tags, etc.
6343 */
6344 if (skb->priority >= 256 && skb->priority <= 263) {
6345 tid = skb->priority - 256;
6346 goto out;
6347 }
6348 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
6349 if (skb_vlan_tag_present(skb)) {
6350 vlan_priority = (skb_vlan_tag_get(skb) & VLAN_PRIO_MASK) >>
6351 VLAN_PRIO_SHIFT;
6352 if (vlan_priority > 0) {
6353 tid = vlan_priority;
6354 goto out;
6355 }
6356 }
6357 #endif
6358 switch (skb->protocol) {
6359 case htons(ETH_P_IP):
6360 dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc;
6361 break;
6362 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
6363 case htons(ETH_P_IPV6):
6364 dscp = ipv6_get_dsfield(ipv6_hdr(skb)) & 0xfc;
6365 break;
6366 #endif
6367 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
6368 case htons(ETH_P_MPLS_UC):
6369 case htons(ETH_P_MPLS_MC): {
6370 struct mpls_label mpls_tmp, *mpls;
6371
6372 mpls = skb_header_pointer(skb, sizeof(struct ethhdr),
6373 sizeof(*mpls), &mpls_tmp);
6374 if (!mpls)
6375 return 0;
6376
6377 tid = (ntohl(mpls->entry) & MPLS_LS_TC_MASK) >>
6378 MPLS_LS_TC_SHIFT;
6379 goto out;
6380 }
6381 case htons(ETH_P_80221):
6382 /* 802.21 is always network control traffic */
6383 return 7;
6384 #endif
6385 default:
6386 return 0;
6387 }
6388 tid = dscp >> 5;
6389 out:
6390 return tid;
6391 }
6392 #endif
6393
6394 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
6395 /**
6396 * @brief This function handles wmm queue select
6397 *
6398 * @param dev A pointer to net_device structure
6399 * @param skb A pointer to sk_buff structure
6400 *
6401 * @return tx_queue index (0-3)
6402 */
6403 u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb
6404 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
6405 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
6406 ,
6407 struct net_device *sb_dev
6408 #else
6409 ,
6410 void *accel_priv
6411 #endif
6412 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) && \
6413 LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)
6414 ,
6415 select_queue_fallback_t fallback
6416 #endif
6417 #endif
6418 )
6419 {
6420 moal_private *priv = (moal_private *)netdev_priv(dev);
6421 t_u8 tid = 0;
6422 t_u8 index = 0;
6423
6424 ENTER();
6425 if (priv->phandle->surprise_removed == MTRUE) {
6426 LEAVE();
6427 return index;
6428 }
6429 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
6430 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
6431 tid = skb->priority = cfg80211_classify8021d(skb, NULL);
6432 #else
6433 tid = skb->priority = cfg80211_classify8021d(skb);
6434 #endif
6435 #else
6436 tid = skb->priority = woal_classify8021d(skb);
6437 #endif
6438 #define NXP_ETH_P_EAPOL 0x888E
6439 #define NXP_ETH_P_WAPI 0x8884
6440 switch (skb->protocol) {
6441 case htons(ETH_P_ARP):
6442 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
6443 case htons(ETH_P_TDLS):
6444 #endif
6445 case htons(NXP_ETH_P_EAPOL):
6446 case htons(NXP_ETH_P_WAPI):
6447 tid = skb->priority = 7;
6448 break;
6449 }
6450 index = mlan_select_wmm_queue(priv->phandle->pmlan_adapter,
6451 priv->bss_index, tid);
6452 PRINTM(MDATA, "select queue: tid=%d, index=%d\n", tid, index);
6453 LEAVE();
6454 return index;
6455 }
6456 #endif
6457
6458 /**
6459 * @brief This function flush tx status queue
6460 *
6461 * @param priv A pointer to moal_private structure
6462 *
6463 * @return N/A
6464 */
6465 void woal_flush_tx_stat_queue(moal_private *priv)
6466 {
6467 struct tx_status_info *tx_info = NULL, *tmp_node;
6468 unsigned long flags;
6469 struct sk_buff *skb = NULL;
6470 spin_lock_irqsave(&priv->tx_stat_lock, flags);
6471 list_for_each_entry_safe (tx_info, tmp_node, &priv->tx_stat_queue,
6472 link) {
6473 list_del(&tx_info->link);
6474 spin_unlock_irqrestore(&priv->tx_stat_lock, flags);
6475 skb = (struct sk_buff *)tx_info->tx_skb;
6476 if (tx_info->tx_cookie) {
6477 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
6478 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
6479 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
6480 cfg80211_mgmt_tx_status(priv->netdev,
6481 tx_info->tx_cookie, skb->data,
6482 skb->len, true, GFP_ATOMIC);
6483 #else
6484 cfg80211_mgmt_tx_status(priv->wdev, tx_info->tx_cookie,
6485 skb->data, skb->len, true,
6486 GFP_ATOMIC);
6487 #endif
6488 #endif
6489 #endif
6490 }
6491 dev_kfree_skb_any(skb);
6492 kfree(tx_info);
6493 spin_lock_irqsave(&priv->tx_stat_lock, flags);
6494 }
6495 INIT_LIST_HEAD(&priv->tx_stat_queue);
6496 spin_unlock_irqrestore(&priv->tx_stat_lock, flags);
6497 spin_lock_bh(&(priv->tx_q.lock));
6498 __skb_queue_purge(&priv->tx_q);
6499 spin_unlock_bh(&(priv->tx_q.lock));
6500 }
6501
6502 /**
6503 * @brief This function gets tx info from tx_stat_queue
6504 *
6505 * @param priv A pointer to moal_private structure
6506 * @param tx_seq_num tx seq number
6507 *
6508 * @return A pointer to the tcp tx_status_info structure, if found.
6509 * Otherwise, null
6510 */
6511 struct tx_status_info *woal_get_tx_info(moal_private *priv, t_u8 tx_seq_num)
6512 {
6513 struct tx_status_info *tx_info = NULL;
6514 ENTER();
6515
6516 list_for_each_entry (tx_info, &priv->tx_stat_queue, link) {
6517 if (tx_info->tx_seq_num == tx_seq_num) {
6518 LEAVE();
6519 return tx_info;
6520 }
6521 }
6522 LEAVE();
6523 return NULL;
6524 }
6525
6526 /**
6527 * @brief This function remove tx info from queue
6528 *
6529 * @param priv A pointer to moal_private structure
6530 * @param tx_seq_num tx seq number
6531 *
6532 * @return N/A
6533 */
6534 void woal_remove_tx_info(moal_private *priv, t_u8 tx_seq_num)
6535 {
6536 struct tx_status_info *tx_info, *tmp = NULL;
6537 unsigned long flags;
6538 ENTER();
6539
6540 spin_lock_irqsave(&priv->tx_stat_lock, flags);
6541 list_for_each_entry_safe (tx_info, tmp, &priv->tx_stat_queue, link) {
6542 if (tx_info->tx_seq_num == tx_seq_num) {
6543 list_del(&tx_info->link);
6544 dev_kfree_skb_any((struct sk_buff *)tx_info->tx_skb);
6545 kfree(tx_info);
6546 break;
6547 }
6548 }
6549 spin_unlock_irqrestore(&priv->tx_stat_lock, flags);
6550
6551 LEAVE();
6552 }
6553
6554 /**
6555 * @brief This function flush mcast list
6556 *
6557 * @param priv A pointer to moal_private structure
6558 *
6559 * @return N/A
6560 */
6561 void woal_flush_mcast_list(moal_private *priv)
6562 {
6563 struct mcast_node *node = NULL, *tmp_node;
6564 unsigned long flags;
6565 spin_lock_irqsave(&priv->mcast_lock, flags);
6566 list_for_each_entry_safe (node, tmp_node, &priv->mcast_list, link) {
6567 list_del(&node->link);
6568 kfree(node);
6569 }
6570 INIT_LIST_HEAD(&priv->mcast_list);
6571 priv->num_mcast_addr = 0;
6572 spin_unlock_irqrestore(&priv->mcast_lock, flags);
6573 }
6574
6575 /**
6576 * @brief find mcast node from tx packet
6577 *
6578 * @param priv A pointer to moal_private structure
6579 * @param skb A pointer to skb buffer.
6580 *
6581 * @return N/A
6582 */
6583 t_u8 woal_find_mcast_node_tx(moal_private *priv, struct sk_buff *skb)
6584 {
6585 struct mcast_node *node = NULL;
6586 unsigned long flags;
6587 t_u8 ret = MFALSE;
6588 t_u8 ra[MLAN_MAC_ADDR_LENGTH];
6589 ENTER();
6590 moal_memcpy_ext(priv->phandle, ra, skb->data, MLAN_MAC_ADDR_LENGTH,
6591 sizeof(ra));
6592 if (ra[0] & 0x01) {
6593 spin_lock_irqsave(&priv->mcast_lock, flags);
6594 list_for_each_entry (node, &priv->mcast_list, link) {
6595 if (!memcmp(node->mcast_addr, ra, ETH_ALEN)) {
6596 ret = MTRUE;
6597 break;
6598 }
6599 }
6600 spin_unlock_irqrestore(&priv->mcast_lock, flags);
6601 }
6602 LEAVE();
6603 return ret;
6604 }
6605
6606 /**
6607 * @brief add mcast node
6608 *
6609 * @param priv A pointer to moal_private structure
6610 * @param peer A point to peer address
6611 *
6612 * @return N/A
6613 */
6614 t_void woal_add_mcast_node(moal_private *priv, t_u8 *mcast_addr)
6615 {
6616 struct mcast_node *node = NULL;
6617 unsigned long flags;
6618 t_u8 find_node = MFALSE;
6619 if (priv) {
6620 spin_lock_irqsave(&priv->mcast_lock, flags);
6621 list_for_each_entry (node, &priv->mcast_list, link) {
6622 if (!memcmp(node->mcast_addr, mcast_addr, ETH_ALEN)) {
6623 find_node = MTRUE;
6624 break;
6625 }
6626 }
6627 if (!find_node) {
6628 /* create new mcast node */
6629 node = kzalloc(sizeof(struct mcast_node), GFP_ATOMIC);
6630 if (node) {
6631 moal_memcpy_ext(priv->phandle, node->mcast_addr,
6632 mcast_addr, ETH_ALEN, ETH_ALEN);
6633 INIT_LIST_HEAD(&node->link);
6634 list_add_tail(&node->link, &priv->mcast_list);
6635 PRINTM(MCMND,
6636 "Add to mcast list: node=" MACSTR "\n",
6637 MAC2STR(mcast_addr));
6638 }
6639 }
6640 spin_unlock_irqrestore(&priv->mcast_lock, flags);
6641 }
6642 }
6643
6644 /**
6645 * @brief This function remove mcast node
6646 *
6647 * @param priv A pointer to moal_private structure
6648 * @param mcast_addr mcast address
6649 *
6650 * @return N/A
6651 */
6652 void woal_remove_mcast_node(moal_private *priv, t_u8 *mcast_addr)
6653 {
6654 struct mcast_node *node, *tmp = NULL;
6655 unsigned long flags;
6656 ENTER();
6657
6658 spin_lock_irqsave(&priv->mcast_lock, flags);
6659 list_for_each_entry_safe (node, tmp, &priv->mcast_list, link) {
6660 if (!memcmp(node->mcast_addr, mcast_addr, ETH_ALEN)) {
6661 list_del(&node->link);
6662 kfree(node);
6663 break;
6664 }
6665 }
6666 spin_unlock_irqrestore(&priv->mcast_lock, flags);
6667
6668 LEAVE();
6669 }
6670
6671 #ifdef STA_CFG80211
6672 /**
6673 * @brief This function flush tcp session queue
6674 *
6675 * @param priv A pointer to moal_private structure
6676 *
6677 * @return N/A
6678 */
6679 void woal_flush_tdls_list(moal_private *priv)
6680 {
6681 struct tdls_peer *peer = NULL, *tmp_node;
6682 unsigned long flags;
6683 spin_lock_irqsave(&priv->tdls_lock, flags);
6684 list_for_each_entry_safe (peer, tmp_node, &priv->tdls_list, link) {
6685 list_del(&peer->link);
6686 kfree(peer);
6687 }
6688 INIT_LIST_HEAD(&priv->tdls_list);
6689 spin_unlock_irqrestore(&priv->tdls_lock, flags);
6690 priv->tdls_check_tx = MFALSE;
6691 }
6692
6693 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
6694 /**
6695 * @brief check the tx packet for tdls auto set up
6696 *
6697 * @param priv A pointer to moal_private structure
6698 * @param skb A pointer to skb buffer.
6699 *
6700 * @return N/A
6701 */
6702 static void woal_tdls_check_tx(moal_private *priv, struct sk_buff *skb)
6703 {
6704 struct tdls_peer *peer = NULL;
6705 unsigned long flags;
6706 t_u8 ra[MLAN_MAC_ADDR_LENGTH];
6707 ENTER();
6708 moal_memcpy_ext(priv->phandle, ra, skb->data, MLAN_MAC_ADDR_LENGTH,
6709 sizeof(ra));
6710 spin_lock_irqsave(&priv->tdls_lock, flags);
6711 list_for_each_entry (peer, &priv->tdls_list, link) {
6712 if (!memcmp(peer->peer_addr, ra, ETH_ALEN)) {
6713 if (peer->rssi &&
6714 (peer->rssi <= TDLS_RSSI_HIGH_THRESHOLD)) {
6715 if ((peer->link_status == TDLS_NOT_SETUP) &&
6716 (peer->num_failure <
6717 TDLS_MAX_FAILURE_COUNT)) {
6718 peer->link_status =
6719 TDLS_SETUP_INPROGRESS;
6720 PRINTM(MMSG,
6721 "Wlan: Set up TDLS link,peer=" MACSTR
6722 " rssi=%d\n",
6723 MAC2STR(peer->peer_addr),
6724 -peer->rssi);
6725 cfg80211_tdls_oper_request(
6726 priv->netdev, peer->peer_addr,
6727 NL80211_TDLS_SETUP, 0,
6728 GFP_ATOMIC);
6729 priv->tdls_check_tx = MFALSE;
6730 }
6731 }
6732 break;
6733 }
6734 }
6735 spin_unlock_irqrestore(&priv->tdls_lock, flags);
6736 LEAVE();
6737 }
6738 #endif
6739 #endif
6740
6741 /**
6742 * @brief This function flush tcp session queue
6743 *
6744 * @param priv A pointer to moal_private structure
6745 *
6746 * @return N/A
6747 */
6748 void woal_flush_tcp_sess_queue(moal_private *priv)
6749 {
6750 struct tcp_sess *tcp_sess = NULL, *tmp_node;
6751 unsigned long flags;
6752 struct sk_buff *skb;
6753 spin_lock_irqsave(&priv->tcp_sess_lock, flags);
6754 list_for_each_entry_safe (tcp_sess, tmp_node, &priv->tcp_sess_queue,
6755 link) {
6756 list_del(&tcp_sess->link);
6757 if (atomic_read(&tcp_sess->is_timer_set))
6758 woal_cancel_timer(&tcp_sess->ack_timer);
6759 skb = (struct sk_buff *)tcp_sess->ack_skb;
6760 if (skb)
6761 dev_kfree_skb_any(skb);
6762 kfree(tcp_sess);
6763 }
6764 INIT_LIST_HEAD(&priv->tcp_sess_queue);
6765 priv->tcp_ack_drop_cnt = 0;
6766 priv->tcp_ack_cnt = 0;
6767 spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
6768 }
6769
6770 /**
6771 * @brief This function gets tcp session from the tcp session queue
6772 *
6773 * @param priv A pointer to moal_private structure
6774 * @param src_ip IP address of the device
6775 * @param src_port TCP port of the device
6776 * @param dst_ip IP address of the client
6777 * @param dst_port TCP port of the client
6778 *
6779 * @return A pointer to the tcp session data structure, if found.
6780 * Otherwise, null
6781 */
6782 static inline struct tcp_sess *woal_get_tcp_sess(moal_private *priv,
6783 t_u32 src_ip, t_u16 src_port,
6784 t_u32 dst_ip, t_u16 dst_port)
6785 {
6786 struct tcp_sess *tcp_sess = NULL;
6787 ENTER();
6788
6789 list_for_each_entry (tcp_sess, &priv->tcp_sess_queue, link) {
6790 if ((tcp_sess->src_ip_addr == src_ip) &&
6791 (tcp_sess->src_tcp_port == src_port) &&
6792 (tcp_sess->dst_ip_addr == dst_ip) &&
6793 (tcp_sess->dst_tcp_port == dst_port)) {
6794 LEAVE();
6795 return tcp_sess;
6796 }
6797 }
6798 LEAVE();
6799 return NULL;
6800 }
6801
6802 #define TCP_SESS_AGEOUT 300
6803 /**
6804 * @brief This function flush tcp session queue
6805 *
6806 * @param priv A pointer to moal_private structure
6807 *
6808 * @return N/A
6809 */
6810 static void woal_ageout_tcp_sess_queue(moal_private *priv)
6811 {
6812 struct tcp_sess *tcp_sess = NULL, *tmp_node;
6813 wifi_timeval t;
6814 struct sk_buff *skb;
6815 woal_get_monotonic_time(&t);
6816 list_for_each_entry_safe (tcp_sess, tmp_node, &priv->tcp_sess_queue,
6817 link) {
6818 if (t.time_sec >
6819 (tcp_sess->update_time.time_sec + TCP_SESS_AGEOUT)) {
6820 PRINTM(MDATA, "wlan: ageout TCP seesion %p\n",
6821 tcp_sess);
6822 list_del(&tcp_sess->link);
6823 if (atomic_read(&tcp_sess->is_timer_set))
6824 woal_cancel_timer(&tcp_sess->ack_timer);
6825 skb = (struct sk_buff *)tcp_sess->ack_skb;
6826 if (skb)
6827 dev_kfree_skb_any(skb);
6828 kfree(tcp_sess);
6829 }
6830 }
6831 }
6832
6833 /**
6834 * @brief This function send the holding tcp ack packet
6835 * re-assoc thread.
6836 *
6837 * @param context A pointer to context
6838 * @return N/A
6839 */
6840 static void woal_tcp_ack_timer_func(void *context)
6841 {
6842 struct tcp_sess *tcp_session = (struct tcp_sess *)context;
6843 moal_private *priv = (moal_private *)tcp_session->priv;
6844 unsigned long flags;
6845 mlan_buffer *pmbuf;
6846 struct sk_buff *skb;
6847 mlan_status status;
6848 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
6849 t_u32 index = 0;
6850 #endif
6851 ENTER();
6852 spin_lock_irqsave(&priv->tcp_sess_lock, flags);
6853 atomic_set(&tcp_session->is_timer_set, MFALSE);
6854 skb = (struct sk_buff *)tcp_session->ack_skb;
6855 pmbuf = (mlan_buffer *)tcp_session->pmbuf;
6856 tcp_session->ack_skb = NULL;
6857 tcp_session->pmbuf = NULL;
6858 spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
6859 if (skb && pmbuf) {
6860 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
6861 index = skb_get_queue_mapping(skb);
6862 #endif
6863 status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
6864 switch (status) {
6865 case MLAN_STATUS_PENDING:
6866 atomic_inc(&priv->phandle->tx_pending);
6867 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
6868 atomic_inc(&priv->wmm_tx_pending[index]);
6869 if (atomic_read(&priv->wmm_tx_pending[index]) >=
6870 MAX_TX_PENDING) {
6871 struct netdev_queue *txq = netdev_get_tx_queue(
6872 priv->netdev, index);
6873 netif_tx_stop_queue(txq);
6874 moal_tp_accounting_rx_param(
6875 (t_void *)priv->phandle, 8, 0);
6876 PRINTM(MINFO, "Stop Kernel Queue : %d\n",
6877 index);
6878 }
6879 #else
6880 if (atomic_read(&priv->phandle->tx_pending) >=
6881 MAX_TX_PENDING)
6882 woal_stop_queue(priv->netdev);
6883 #endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)*/
6884 queue_work(priv->phandle->workqueue,
6885 &priv->phandle->main_work);
6886 break;
6887 case MLAN_STATUS_SUCCESS:
6888 priv->stats.tx_packets++;
6889 priv->stats.tx_bytes += skb->len;
6890 dev_kfree_skb_any(skb);
6891 break;
6892 case MLAN_STATUS_FAILURE:
6893 default:
6894 priv->stats.tx_dropped++;
6895 dev_kfree_skb_any(skb);
6896 break;
6897 }
6898 }
6899 LEAVE();
6900 return;
6901 }
6902
6903 /**
6904 * @brief This function send the tcp ack
6905 *
6906 *
6907 * @param priv A pointer to moal_private structure
6908 * @param tcp_session A pointer to tcp_session
6909 * @return N/A
6910 */
6911 static void woal_send_tcp_ack(moal_private *priv, struct tcp_sess *tcp_session)
6912 {
6913 mlan_status status;
6914 struct sk_buff *skb = (struct sk_buff *)tcp_session->ack_skb;
6915 mlan_buffer *pmbuf = (mlan_buffer *)tcp_session->pmbuf;
6916 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
6917 t_u32 index = 0;
6918 #endif
6919 ENTER();
6920 if (atomic_cmpxchg(&tcp_session->is_timer_set, MTRUE, MFALSE)) {
6921 woal_cancel_timer(&tcp_session->ack_timer);
6922 }
6923 tcp_session->ack_skb = NULL;
6924 tcp_session->pmbuf = NULL;
6925 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
6926 index = skb_get_queue_mapping(skb);
6927 #endif
6928 status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
6929 switch (status) {
6930 case MLAN_STATUS_PENDING:
6931 atomic_inc(&priv->phandle->tx_pending);
6932 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
6933 atomic_inc(&priv->wmm_tx_pending[index]);
6934 if (atomic_read(&priv->wmm_tx_pending[index]) >=
6935 MAX_TX_PENDING) {
6936 struct netdev_queue *txq =
6937 netdev_get_tx_queue(priv->netdev, index);
6938 netif_tx_stop_queue(txq);
6939 moal_tp_accounting_rx_param((t_void *)priv->phandle, 8,
6940 0);
6941 PRINTM(MINFO, "Stop Kernel Queue : %d\n", index);
6942 }
6943 #else
6944 if (atomic_read(&priv->phandle->tx_pending) >= MAX_TX_PENDING)
6945 woal_stop_queue(priv->netdev);
6946 #endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)*/
6947 queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
6948 break;
6949 case MLAN_STATUS_SUCCESS:
6950 priv->stats.tx_packets++;
6951 priv->stats.tx_bytes += skb->len;
6952 dev_kfree_skb_any(skb);
6953 break;
6954 case MLAN_STATUS_FAILURE:
6955 default:
6956 priv->stats.tx_dropped++;
6957 dev_kfree_skb_any(skb);
6958 break;
6959 }
6960 LEAVE();
6961 }
6962
6963 /**
6964 * @brief This function get the tcp ack session node
6965 *
6966 * @param priv A pointer to moal_private structure
6967 * @param pmbuf A pointer to mlan_buffer associated with a skb
6968 *
6969 * @return 1, if it's dropped; 2, if it's hold 0, if not dropped and
6970 * not hold
6971 *
6972 */
6973 static int woal_process_tcp_ack(moal_private *priv, mlan_buffer *pmbuf)
6974 {
6975 int ret = 0;
6976 unsigned long flags;
6977 struct tcp_sess *tcp_session;
6978 struct ethhdr *ethh = NULL;
6979 struct iphdr *iph = NULL;
6980 struct tcphdr *tcph = NULL;
6981 t_u32 ack_seq;
6982 struct sk_buff *skb;
6983
6984 ENTER();
6985
6986 /** check the tcp packet */
6987 ethh = (struct ethhdr *)(pmbuf->pbuf + pmbuf->data_offset);
6988 if (ntohs(ethh->h_proto) != ETH_P_IP) {
6989 LEAVE();
6990 return 0;
6991 }
6992 iph = (struct iphdr *)((t_u8 *)ethh + sizeof(struct ethhdr));
6993 if (iph->protocol != IPPROTO_TCP) {
6994 LEAVE();
6995 return 0;
6996 }
6997 tcph = (struct tcphdr *)((t_u8 *)iph + iph->ihl * 4);
6998
6999 if (*((t_u8 *)tcph + 13) == 0x10) {
7000 /* Only replace ACK */
7001 if (ntohs(iph->tot_len) > (iph->ihl + tcph->doff) * 4) {
7002 priv->tcp_ack_payload++;
7003 /* Don't drop ACK with payload */
7004 /* TODO: should we delete previous TCP session */
7005 LEAVE();
7006 return ret;
7007 }
7008 priv->tcp_ack_cnt++;
7009 spin_lock_irqsave(&priv->tcp_sess_lock, flags);
7010 tcp_session = woal_get_tcp_sess(priv, (__force t_u32)iph->saddr,
7011 (__force t_u16)tcph->source,
7012 (__force t_u32)iph->daddr,
7013 (__force t_u16)tcph->dest);
7014 if (!tcp_session) {
7015 /* check any aging out sessions can be removed */
7016 woal_ageout_tcp_sess_queue(priv);
7017
7018 tcp_session =
7019 kmalloc(sizeof(struct tcp_sess), GFP_ATOMIC);
7020 if (!tcp_session) {
7021 PRINTM(MERROR, "Fail to allocate tcp_sess.\n");
7022 spin_unlock_irqrestore(&priv->tcp_sess_lock,
7023 flags);
7024 goto done;
7025 }
7026 woal_get_monotonic_time(&tcp_session->update_time);
7027 PRINTM(MDATA, "wlan: create TCP seesion %p\n",
7028 tcp_session);
7029
7030 tcp_session->ack_skb = pmbuf->pdesc;
7031 tcp_session->pmbuf = pmbuf;
7032 pmbuf->flags |= MLAN_BUF_FLAG_TCP_ACK;
7033 tcp_session->src_ip_addr = (__force t_u32)iph->saddr;
7034 tcp_session->dst_ip_addr = (__force t_u32)iph->daddr;
7035 tcp_session->src_tcp_port = (__force t_u32)tcph->source;
7036 tcp_session->dst_tcp_port = (__force t_u32)tcph->dest;
7037 tcp_session->ack_seq = ntohl(tcph->ack_seq);
7038 tcp_session->priv = (void *)priv;
7039 skb = (struct sk_buff *)pmbuf->pdesc;
7040 skb->cb[0] = 0;
7041 /* Initialize the timer for tcp ack */
7042 woal_initialize_timer(&tcp_session->ack_timer,
7043 woal_tcp_ack_timer_func,
7044 tcp_session);
7045 atomic_set(&tcp_session->is_timer_set, MTRUE);
7046 woal_mod_timer(&tcp_session->ack_timer, MOAL_TIMER_1MS);
7047 list_add_tail(&tcp_session->link,
7048 &priv->tcp_sess_queue);
7049 spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
7050 ret = HOLD_TCP_ACK;
7051 LEAVE();
7052 return ret;
7053 } else if (!tcp_session->ack_skb) {
7054 woal_get_monotonic_time(&tcp_session->update_time);
7055 tcp_session->ack_skb = pmbuf->pdesc;
7056 tcp_session->pmbuf = pmbuf;
7057 pmbuf->flags |= MLAN_BUF_FLAG_TCP_ACK;
7058 tcp_session->ack_seq = ntohl(tcph->ack_seq);
7059 tcp_session->priv = (void *)priv;
7060 skb = (struct sk_buff *)pmbuf->pdesc;
7061 skb->cb[0] = 0;
7062 atomic_set(&tcp_session->is_timer_set, MTRUE);
7063 woal_mod_timer(&tcp_session->ack_timer, MOAL_TIMER_1MS);
7064 spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
7065 ret = HOLD_TCP_ACK;
7066 LEAVE();
7067 return ret;
7068 }
7069 woal_get_monotonic_time(&tcp_session->update_time);
7070 ack_seq = ntohl(tcph->ack_seq);
7071 skb = (struct sk_buff *)tcp_session->ack_skb;
7072 if (likely(ack_seq > tcp_session->ack_seq) &&
7073 (skb->len == pmbuf->data_len)) {
7074 moal_memcpy_ext(priv->phandle, skb->data,
7075 pmbuf->pbuf + pmbuf->data_offset,
7076 pmbuf->data_len, skb->len);
7077 tcp_session->ack_seq = ack_seq;
7078 ret = DROP_TCP_ACK;
7079 skb->cb[0]++;
7080 if (skb->cb[0] >= priv->tcp_ack_max_hold)
7081 woal_send_tcp_ack(priv, tcp_session);
7082 spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
7083 skb = (struct sk_buff *)pmbuf->pdesc;
7084 dev_kfree_skb_any(skb);
7085 priv->tcp_ack_drop_cnt++;
7086 } else {
7087 pmbuf->flags |= MLAN_BUF_FLAG_TCP_ACK;
7088 spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
7089 LEAVE();
7090 return ret;
7091 }
7092 }
7093 #if 0
7094 /* Might have race conditions with woal_tcp_ack_timer_func
7095 * Causing kernel panic, ageout handler will free tcp_sess
7096 * for now.
7097 */
7098 else if((*((t_u8 *)tcph + 13) & 0x11) == 0x11){
7099 /* TCP ACK + Fin */
7100 spin_lock_irqsave(&priv->tcp_sess_lock, flags);
7101 tcp_session = woal_get_tcp_sess(priv, (__force t_u32)iph->saddr, (__force t_u16)tcph->source,
7102 (__force t_u32)iph->daddr, (__force t_u16)tcph->dest);
7103 if (tcp_session) {
7104 PRINTM(MDATA,"wlan: delete TCP seesion %p\n",tcp_session);
7105 list_del(&tcp_session->link);
7106 if (atomic_read(&tcp_session->is_timer_set))
7107 woal_cancel_timer(&tcp_session->ack_timer);
7108 skb = (struct sk_buff *)tcp_session->ack_skb;
7109 if (skb)
7110 dev_kfree_skb_any(skb);
7111 kfree(tcp_session);
7112 }
7113 spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
7114 }
7115 #endif
7116
7117 done:
7118 LEAVE();
7119 return ret;
7120 }
7121
7122 /**
7123 * @brief This function handles packet transmission
7124 *
7125 * @param skb A pointer to sk_buff structure
7126 * @param dev A pointer to net_device structure
7127 *
7128 * @return N/A
7129 */
7130 static void woal_start_xmit(moal_private *priv, struct sk_buff *skb)
7131 {
7132 mlan_buffer *pmbuf = NULL;
7133 mlan_status status;
7134 struct sk_buff *new_skb = NULL;
7135 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
7136 t_u32 index = 0;
7137 #endif
7138 int ret = 0;
7139
7140 ENTER();
7141
7142 priv->num_tx_timeout = 0;
7143 if (!skb->len ||
7144 (skb->len > (priv->netdev->mtu + sizeof(struct ethhdr)))) {
7145 PRINTM(MERROR, "Tx Error: Bad skb length %d : %d\n", skb->len,
7146 priv->netdev->mtu);
7147 dev_kfree_skb_any(skb);
7148 priv->stats.tx_dropped++;
7149 goto done;
7150 }
7151 // kernel crash with cloned skb without copy
7152 // 2 AGO case
7153 // uap0 <-->muap0 bridge
7154 if (moal_extflg_isset(priv->phandle, EXT_TX_SKB_CLONE) || skb->cloned ||
7155 (skb_headroom(skb) <
7156 (MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
7157 priv->extra_tx_head_len))) {
7158 PRINTM(MINFO,
7159 "Tx: skb cloned %d skb headroom %d tx_skb_clone=%d \n",
7160 skb->cloned, skb_headroom(skb),
7161 moal_extflg_isset(priv->phandle, EXT_TX_SKB_CLONE));
7162 /* Insufficient skb headroom - allocate a new skb */
7163 new_skb = skb_realloc_headroom(
7164 skb, MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
7165 priv->extra_tx_head_len);
7166 moal_tp_accounting_rx_param((t_void *)priv->phandle, 7, 0);
7167 if (unlikely(!new_skb)) {
7168 PRINTM(MERROR, "Tx: Cannot allocate skb\n");
7169 dev_kfree_skb_any(skb);
7170 priv->stats.tx_dropped++;
7171 goto done;
7172 }
7173 if (new_skb != skb)
7174 dev_kfree_skb_any(skb);
7175 skb = new_skb;
7176
7177 PRINTM(MINFO, "new skb headroom %d\n", skb_headroom(skb));
7178 }
7179 pmbuf = (mlan_buffer *)skb->head;
7180 memset((t_u8 *)pmbuf, 0, sizeof(mlan_buffer));
7181 pmbuf->bss_index = priv->bss_index;
7182 woal_fill_mlan_buffer(priv, pmbuf, skb);
7183
7184 if (priv->enable_tcp_ack_enh == MTRUE) {
7185 ret = woal_process_tcp_ack(priv, pmbuf);
7186 if (ret)
7187 goto done;
7188 }
7189 #ifdef STA_CFG80211
7190 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
7191 if (priv->enable_auto_tdls && priv->tdls_check_tx)
7192 woal_tdls_check_tx(priv, skb);
7193 #endif
7194 #endif
7195 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
7196 index = skb_get_queue_mapping(skb);
7197 #endif
7198
7199 if (is_zero_timeval(priv->phandle->tx_time_start)) {
7200 priv->phandle->tx_time_start.time_sec = pmbuf->in_ts_sec;
7201 priv->phandle->tx_time_start.time_usec = pmbuf->in_ts_usec;
7202 PRINTM(MINFO, "%s : start_timeval=%d:%d \n", __func__,
7203 priv->phandle->tx_time_start.time_sec,
7204 priv->phandle->tx_time_start.time_usec);
7205 }
7206 status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
7207 switch (status) {
7208 case MLAN_STATUS_PENDING:
7209 atomic_inc(&priv->phandle->tx_pending);
7210
7211 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
7212 atomic_inc(&priv->wmm_tx_pending[index]);
7213 if (atomic_read(&priv->wmm_tx_pending[index]) >=
7214 MAX_TX_PENDING) {
7215 struct netdev_queue *txq =
7216 netdev_get_tx_queue(priv->netdev, index);
7217 netif_tx_stop_queue(txq);
7218 moal_tp_accounting_rx_param((t_void *)priv->phandle, 8,
7219 0);
7220 PRINTM(MINFO, "Stop Kernel Queue : %d\n", index);
7221 }
7222 #else
7223 if (atomic_read(&priv->phandle->tx_pending) >= MAX_TX_PENDING)
7224 woal_stop_queue(priv->netdev);
7225 #endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)*/
7226
7227 if (!mlan_is_main_process_running(priv->phandle->pmlan_adapter))
7228 queue_work(priv->phandle->workqueue,
7229 &priv->phandle->main_work);
7230 break;
7231 case MLAN_STATUS_SUCCESS:
7232 priv->stats.tx_packets++;
7233 priv->stats.tx_bytes += skb->len;
7234 dev_kfree_skb_any(skb);
7235 break;
7236 case MLAN_STATUS_FAILURE:
7237 default:
7238 priv->stats.tx_dropped++;
7239 dev_kfree_skb_any(skb);
7240 break;
7241 }
7242 done:
7243 LEAVE();
7244 return;
7245 }
7246
7247 /**
7248 * @brief This function handles packet transmission
7249 *
7250 * @param skb A pointer to sk_buff structure
7251 * @param dev A pointer to net_device structure
7252 *
7253 * @return 0 --success
7254 */
7255 netdev_tx_t woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
7256 {
7257 moal_private *priv = (moal_private *)netdev_priv(dev);
7258 ENTER();
7259 PRINTM(MDATA, "%lu : %s (bss=%d): Data <= kernel\n", jiffies, dev->name,
7260 priv->bss_index);
7261
7262 /* Collect TP statistics */
7263 if (priv->phandle->tp_acnt.on)
7264 moal_tp_accounting(priv->phandle, skb, 1);
7265 /* Drop Tx packets at drop point 1 */
7266 if (priv->phandle->tp_acnt.drop_point == 1) {
7267 dev_kfree_skb_any(skb);
7268 LEAVE();
7269 return 0;
7270 }
7271 if (priv->phandle->surprise_removed == MTRUE) {
7272 dev_kfree_skb_any(skb);
7273 priv->stats.tx_dropped++;
7274 goto done;
7275 }
7276 if (moal_extflg_isset(priv->phandle, EXT_TX_WORK)) {
7277 spin_lock_bh(&(priv->tx_q.lock));
7278 __skb_queue_tail(&(priv->tx_q), skb);
7279 spin_unlock_bh(&(priv->tx_q.lock));
7280
7281 queue_work(priv->phandle->tx_workqueue,
7282 &priv->phandle->tx_work);
7283 goto done;
7284 }
7285 woal_start_xmit(priv, skb);
7286 done:
7287 LEAVE();
7288 return 0;
7289 }
7290
7291 /**
7292 * @brief Convert ascii string to Hex integer
7293 *
7294 * @param d A pointer to integer buf
7295 * @param s A pointer to ascii string
7296 * @param dlen The byte number of ascii string in hex
7297 *
7298 * @return Number of integer
7299 */
7300 int woal_ascii2hex(t_u8 *d, char *s, t_u32 dlen)
7301 {
7302 unsigned int i;
7303 t_u8 n;
7304
7305 ENTER();
7306
7307 memset(d, 0x00, dlen);
7308
7309 for (i = 0; i < dlen * 2; i++) {
7310 if ((s[i] >= 48) && (s[i] <= 57))
7311 n = s[i] - 48;
7312 else if ((s[i] >= 65) && (s[i] <= 70))
7313 n = s[i] - 55;
7314 else if ((s[i] >= 97) && (s[i] <= 102))
7315 n = s[i] - 87;
7316 else
7317 break;
7318 if (!(i % 2))
7319 n = n * 16;
7320 d[i / 2] += n;
7321 }
7322
7323 LEAVE();
7324 return i;
7325 }
7326
7327 /**
7328 * @brief Return integer value of a given ascii string
7329 *
7330 * @param data Converted data to be returned
7331 * @param a String to be converted
7332 *
7333 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
7334 */
7335 mlan_status woal_atoi(int *data, char *a)
7336 {
7337 int i, val = 0, len;
7338 int mul = 1;
7339
7340 ENTER();
7341
7342 len = strlen(a);
7343 if (len > 2) {
7344 if (!strncmp(a, "0x", 2)) {
7345 a = a + 2;
7346 len -= 2;
7347 *data = woal_atox(a);
7348 LEAVE();
7349 return MLAN_STATUS_SUCCESS;
7350 }
7351 }
7352 for (i = 0; i < len; i++) {
7353 if (isdigit(a[i])) {
7354 val = val * 10 + (a[i] - '0');
7355 } else {
7356 if ((i == 0) && (a[i] == '-')) {
7357 mul = -1;
7358 } else if (a[i] == 0xa) {
7359 // line feed
7360 break;
7361 } else {
7362 PRINTM(MERROR, "Invalid char %c in string %s\n",
7363 a[i], a);
7364 LEAVE();
7365 return MLAN_STATUS_FAILURE;
7366 }
7367 }
7368 }
7369 *data = (mul * val);
7370
7371 LEAVE();
7372 return MLAN_STATUS_SUCCESS;
7373 }
7374
7375 /**
7376 * @brief Return hex value of a given ascii string
7377 *
7378 * @param a String to be converted to ascii
7379 *
7380 * @return The converted character if a is a valid hex, else 0
7381 */
7382 int woal_atox(char *a)
7383 {
7384 int i = 0;
7385
7386 ENTER();
7387
7388 while (isxdigit(*a))
7389 i = i * 16 + woal_hexval(*a++);
7390
7391 LEAVE();
7392 return i;
7393 }
7394
7395 /**
7396 * @brief Extension of strsep lib command. This function will also take care
7397 * escape character
7398 *
7399 * @param s A pointer to array of chars to process
7400 * @param delim The delimiter character to end the string
7401 * @param esc The escape character to ignore for delimiter
7402 *
7403 * @return Pointer to the separated string if delim found, else NULL
7404 */
7405 char *woal_strsep(char **s, char delim, char esc)
7406 {
7407 char *se = *s, *sb;
7408
7409 ENTER();
7410
7411 if (!(*s) || (*se == '\0')) {
7412 LEAVE();
7413 return NULL;
7414 }
7415
7416 for (sb = *s; *sb != '\0'; ++sb) {
7417 if (*sb == esc && *(sb + 1) == esc) {
7418 /*
7419 * We get a esc + esc seq then keep the one esc
7420 * and chop off the other esc character
7421 */
7422 memmove(sb, sb + 1, strlen(sb));
7423 continue;
7424 }
7425 if (*sb == esc && *(sb + 1) == delim) {
7426 /*
7427 * We get a delim + esc seq then keep the delim
7428 * and chop off the esc character
7429 */
7430 memmove(sb, sb + 1, strlen(sb));
7431 continue;
7432 }
7433 if (*sb == delim)
7434 break;
7435 }
7436
7437 if (*sb == '\0')
7438 sb = NULL;
7439 else
7440 *sb++ = '\0';
7441
7442 *s = sb;
7443
7444 LEAVE();
7445 return se;
7446 }
7447
7448 /**
7449 * @brief Convert mac address from string to t_u8 buffer.
7450 *
7451 * @param mac_addr The buffer to store the mac address in.
7452 * @param buf The source of mac address which is a string.
7453 *
7454 * @return N/A
7455 */
7456 void woal_mac2u8(t_u8 *mac_addr, char *buf)
7457 {
7458 char *begin, *end, *mac_buff;
7459 int i;
7460
7461 ENTER();
7462
7463 if (!buf) {
7464 LEAVE();
7465 return;
7466 }
7467
7468 mac_buff = kzalloc(strlen(buf) + 1, GFP_KERNEL);
7469 if (!mac_buff) {
7470 LEAVE();
7471 return;
7472 }
7473 moal_memcpy_ext(NULL, mac_buff, buf, strlen(buf), strlen(buf) + 1);
7474
7475 begin = mac_buff;
7476 for (i = 0; i < ETH_ALEN; ++i) {
7477 end = woal_strsep(&begin, ':', '/');
7478 if (end)
7479 mac_addr[i] = woal_atox(end);
7480 }
7481
7482 kfree(mac_buff);
7483 LEAVE();
7484 }
7485
7486 #ifdef STA_SUPPORT
7487 /**
7488 * @brief This function sets multicast addresses to firmware
7489 *
7490 * @param dev A pointer to net_device structure
7491 *
7492 * @return N/A
7493 */
7494 void woal_set_multicast_list(struct net_device *dev)
7495 {
7496 moal_private *priv = (moal_private *)netdev_priv(dev);
7497 ENTER();
7498 queue_work(priv->mclist_workqueue, &priv->mclist_work);
7499 LEAVE();
7500 }
7501 #endif
7502
7503 /**
7504 * @brief This function initializes the private structure
7505 * and set default value to the member of moal_private.
7506 *
7507 * @param priv A pointer to moal_private structure
7508 * @param wait_option Wait option
7509 *
7510 * @return N/A
7511 */
7512 void woal_init_priv(moal_private *priv, t_u8 wait_option)
7513 {
7514 ENTER();
7515 #ifdef STA_SUPPORT
7516 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
7517 priv->current_key_index = 0;
7518 priv->rate_index = AUTO_RATE;
7519 priv->is_adhoc_link_sensed = MFALSE;
7520 priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
7521 priv->bg_scan_start = MFALSE;
7522 priv->bg_scan_reported = MFALSE;
7523 priv->sched_scanning = MFALSE;
7524 #ifdef STA_CFG80211
7525 priv->roaming_enabled = MFALSE;
7526 priv->roaming_required = MFALSE;
7527 #endif
7528
7529 memset(&priv->nick_name, 0, sizeof(priv->nick_name));
7530 priv->num_tx_timeout = 0;
7531 priv->rx_filter = 0;
7532
7533 #ifdef REASSOCIATION
7534 priv->reassoc_on = MFALSE;
7535 priv->set_asynced_essid_flag = MFALSE;
7536 #endif
7537 priv->auto_assoc_priv.auto_assoc_type_on = 2;
7538 priv->auto_assoc_priv.auto_assoc_trigger_flag =
7539 AUTO_ASSOC_TYPE_DRV_RECONN;
7540 memset(&priv->auto_assoc_priv.drv_assoc, 0,
7541 sizeof(drv_auto_assoc));
7542 memset(&priv->auto_assoc_priv.drv_reconnect, 0,
7543 sizeof(drv_auto_assoc));
7544 priv->auto_assoc_priv.drv_reconnect.retry_count = 0xff;
7545 #ifdef STA_CFG80211
7546 memset(&priv->sme_current, 0,
7547 sizeof(struct cfg80211_connect_params));
7548 #endif
7549 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
7550 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
7551 woal_init_wifi_hal(priv);
7552 #endif
7553 #endif
7554 }
7555 #endif /* STA_SUPPORT */
7556 #ifdef UAP_SUPPORT
7557 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
7558 priv->bss_started = MFALSE;
7559 priv->uap_host_based = MFALSE;
7560 priv->skip_cac = MFALSE;
7561
7562 #ifdef UAP_CFG80211
7563 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
7564 memset(&priv->chan, 0, sizeof(struct cfg80211_chan_def));
7565 memset(&priv->csa_chan, 0, sizeof(struct cfg80211_chan_def));
7566 priv->uap_tx_blocked = MFALSE;
7567 memset(&priv->beacon_after, 0,
7568 sizeof(struct cfg80211_beacon_data));
7569 #endif
7570 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
7571 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
7572 woal_init_wifi_hal(priv);
7573 #endif
7574 #endif
7575 #endif
7576 }
7577 #endif
7578
7579 skb_queue_head_init(&priv->tx_q);
7580 memset(&priv->tx_protocols, 0, sizeof(dot11_protocol));
7581 memset(&priv->rx_protocols, 0, sizeof(dot11_protocol));
7582 priv->media_connected = MFALSE;
7583
7584 memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map));
7585
7586 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
7587 priv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
7588 priv->beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
7589 priv->proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
7590 priv->assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
7591 priv->beacon_wps_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
7592 priv->proberesp_p2p_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
7593 priv->assocresp_qos_map_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
7594 priv->beacon_vendor_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
7595 priv->mgmt_subtype_mask = 0;
7596 priv->cfg_disconnect = MFALSE;
7597 priv->cfg_connect = MFALSE;
7598 #endif
7599 #ifdef STA_SUPPORT
7600 #ifdef STA_CFG80211
7601 priv->pmk_saved = MFALSE;
7602 memset(&priv->pmk, 0, sizeof(mlan_pmk_t));
7603 #endif
7604 #endif
7605
7606 priv->enable_tcp_ack_enh = MTRUE;
7607 priv->tcp_ack_drop_cnt = 0;
7608 priv->tcp_ack_cnt = 0;
7609 priv->tcp_ack_payload = 0;
7610 priv->tcp_ack_max_hold = TCP_ACK_MAX_HOLD;
7611
7612 priv->enable_auto_tdls = MFALSE;
7613 priv->tdls_check_tx = MFALSE;
7614
7615 priv->gtk_data_ready = MFALSE;
7616 memset(&priv->gtk_rekey_data, 0, sizeof(mlan_ds_misc_gtk_rekey_data));
7617
7618 if (MLAN_STATUS_SUCCESS !=
7619 woal_request_get_fw_info(priv, wait_option, NULL)) {
7620 PRINTM(MERROR, "%s: get_fw_info failed \n", __func__);
7621 return;
7622 }
7623 /* Set MAC address from the insmod command line */
7624 if (priv->phandle->set_mac_addr &&
7625 priv->bss_type != MLAN_BSS_TYPE_DFS) {
7626 memset(priv->current_addr, 0, ETH_ALEN);
7627 moal_memcpy_ext(priv->phandle, priv->current_addr,
7628 priv->phandle->mac_addr, ETH_ALEN, ETH_ALEN);
7629 }
7630
7631 #ifdef WIFI_DIRECT_SUPPORT
7632 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
7633 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
7634 #ifdef MFG_CMD_SUPPORT
7635 if (priv->phandle->params.mfg_mode != MLAN_INIT_PARA_ENABLED)
7636 #endif
7637 if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
7638 if (priv->bss_virtual) {
7639 if (priv->pa_netdev) {
7640 moal_memcpy_ext(
7641 priv->phandle,
7642 priv->current_addr,
7643 priv->pa_netdev->dev_addr,
7644 ETH_ALEN, ETH_ALEN);
7645 priv->current_addr[4] ^= 0x80;
7646 if (priv->phandle->second_mac)
7647 priv->current_addr[5] ^= 0x80;
7648 PRINTM(MCMND,
7649 "Set WFD interface addr: " MACSTR
7650 "\n",
7651 MAC2STR(priv->current_addr));
7652 }
7653 } else {
7654 priv->current_addr[0] |= 0x02;
7655 PRINTM(MCMND,
7656 "Set WFD device addr: " MACSTR "\n",
7657 MAC2STR(priv->current_addr));
7658 }
7659 }
7660 #endif
7661 #endif
7662 #endif
7663
7664 /* Set MAC address for UAPx/MLANx/WFDx/OCBx and let them
7665 * different with each other */
7666 #ifdef WIFI_DIRECT_SUPPORT
7667 if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT)
7668 #endif
7669 {
7670 if (priv->bss_index) {
7671 priv->current_addr[0] |= 0x02;
7672 priv->current_addr[4] += priv->bss_index;
7673 }
7674 PRINTM(MCMND, "Set %s interface addr: " MACSTR "\n",
7675 priv->netdev->name, MAC2STR(priv->current_addr));
7676 }
7677
7678 /* ZeroDFS interface doesn't need to set mac address to fw */
7679 if (priv->bss_type != MLAN_BSS_TYPE_DFS) {
7680 if (MLAN_STATUS_SUCCESS !=
7681 woal_request_set_mac_address(priv, MOAL_IOCTL_WAIT))
7682 PRINTM(MERROR, "%s: set mac address failed \n",
7683 __func__);
7684 }
7685 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)
7686 eth_hw_addr_set(priv->netdev, priv->current_addr);
7687 #else
7688 moal_memcpy_ext(priv->phandle, priv->netdev->dev_addr,
7689 priv->current_addr, ETH_ALEN, ETH_ALEN);
7690 #endif
7691 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
7692 priv->host_mlme = 0;
7693 priv->auth_flag = 0;
7694 priv->auth_alg = 0xFFFF;
7695 #endif
7696
7697 #ifdef UAP_SUPPORT
7698 priv->target_chan = 0;
7699 priv->backup_chan = 0;
7700 priv->user_cac_period_msec = 0;
7701 priv->chan_under_nop = MFALSE;
7702 #endif
7703 LEAVE();
7704 }
7705
7706 /**
7707 * @brief Reset all interfaces if all_intf flag is TRUE,
7708 * otherwise specified interface only
7709 *
7710 * @param priv A pointer to moal_private structure
7711 * @param wait_option Wait option
7712 * @param all_intf TRUE : all interfaces
7713 * FALSE : current interface only
7714 *
7715 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
7716 */
7717 mlan_status woal_reset_intf(moal_private *priv, t_u8 wait_option, int all_intf)
7718 {
7719 int ret = MLAN_STATUS_SUCCESS;
7720 int intf_num;
7721 moal_handle *handle = NULL;
7722 mlan_bss_info bss_info;
7723
7724 ENTER();
7725
7726 if (!priv) {
7727 LEAVE();
7728 return MLAN_STATUS_FAILURE;
7729 }
7730 handle = priv->phandle;
7731
7732 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
7733 /* Unregister and detach connected radiotap net device */
7734 if (handle->mon_if) {
7735 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
7736 if (MLAN_STATUS_SUCCESS !=
7737 woal_set_net_monitor(handle->mon_if->priv, wait_option,
7738 MFALSE, 0, NULL)) {
7739 PRINTM(MERROR, "%s: stop net monitor failed \n",
7740 __func__);
7741 ret = MLAN_STATUS_FAILURE;
7742 goto done;
7743 }
7744 #endif
7745 netif_device_detach(handle->mon_if->mon_ndev);
7746 if (handle->mon_if->mon_ndev->reg_state == NETREG_REGISTERED)
7747 unregister_netdev(handle->mon_if->mon_ndev);
7748 handle->mon_if = NULL;
7749 }
7750 #endif
7751 if (handle->rf_test_mode)
7752 woal_process_rf_test_mode(handle, MFG_CMD_UNSET_TEST_MODE);
7753 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
7754 #endif
7755 #ifdef STA_SUPPORT
7756 if (MLAN_STATUS_SUCCESS != woal_cancel_scan(priv, wait_option)) {
7757 PRINTM(MERROR, "%s: cancel scan failed \n", __func__);
7758 ret = MLAN_STATUS_FAILURE;
7759 goto done;
7760 }
7761 #endif
7762
7763 /* Stop queue and detach device */
7764 if (!all_intf) {
7765 woal_stop_queue(priv->netdev);
7766 netif_device_detach(priv->netdev);
7767 } else {
7768 for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
7769 woal_stop_queue(handle->priv[intf_num]->netdev);
7770 netif_device_detach(handle->priv[intf_num]->netdev);
7771 }
7772 }
7773
7774 /* Get BSS info */
7775 memset(&bss_info, 0, sizeof(bss_info));
7776 if (MLAN_STATUS_SUCCESS !=
7777 woal_get_bss_info(priv, wait_option, &bss_info)) {
7778 PRINTM(MERROR, "%s: get bss info failed \n", __func__);
7779 ret = MLAN_STATUS_FAILURE;
7780 goto done;
7781 }
7782
7783 /* Cancel host sleep */
7784 if (bss_info.is_hs_configured) {
7785 if (MLAN_STATUS_SUCCESS != woal_cancel_hs(priv, wait_option)) {
7786 ret = -EFAULT;
7787 goto done;
7788 }
7789 }
7790
7791 /* Disconnect from network */
7792 if (!all_intf) {
7793 /* Disconnect specified interface only */
7794 if ((priv->media_connected == MTRUE)
7795 #ifdef UAP_SUPPORT
7796 || (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
7797 #endif
7798 ) {
7799 if (MLAN_STATUS_SUCCESS !=
7800 woal_disconnect(priv, wait_option, NULL,
7801 DEF_DEAUTH_REASON_CODE)) {
7802 PRINTM(MERROR, "%s: woal_disconnect failed \n",
7803 __func__);
7804 ret = MLAN_STATUS_FAILURE;
7805 goto done;
7806 }
7807 priv->media_connected = MFALSE;
7808 }
7809 } else {
7810 /* Disconnect all interfaces */
7811 for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
7812 if (handle->priv[intf_num]->media_connected == MTRUE
7813 #ifdef UAP_SUPPORT
7814 || (GET_BSS_ROLE(handle->priv[intf_num]) ==
7815 MLAN_BSS_ROLE_UAP)
7816 #endif
7817 ) {
7818 if (MLAN_STATUS_SUCCESS !=
7819 woal_disconnect(handle->priv[intf_num],
7820 wait_option, NULL,
7821 DEF_DEAUTH_REASON_CODE)) {
7822 PRINTM(MERROR,
7823 "%s: woal_disconnect failed \n",
7824 __func__);
7825 ret = MLAN_STATUS_FAILURE;
7826 goto done;
7827 }
7828 handle->priv[intf_num]->media_connected =
7829 MFALSE;
7830 }
7831 }
7832 }
7833
7834 #ifdef REASSOCIATION
7835 /* Reset the reassoc timer and status */
7836 if (!all_intf) {
7837 handle->reassoc_on &= ~MBIT(priv->bss_index);
7838 priv->reassoc_on = MFALSE;
7839 priv->auto_assoc_priv.drv_assoc.status = MFALSE;
7840 priv->auto_assoc_priv.drv_reconnect.status = MFALSE;
7841 priv->set_asynced_essid_flag = MFALSE;
7842 } else {
7843 handle->reassoc_on = 0;
7844 for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
7845 handle->priv[intf_num]->reassoc_on = MFALSE;
7846 handle->priv[intf_num]
7847 ->auto_assoc_priv.drv_assoc.status = MFALSE;
7848 handle->priv[intf_num]
7849 ->auto_assoc_priv.drv_reconnect.status = MFALSE;
7850 handle->priv[intf_num]->set_asynced_essid_flag = MFALSE;
7851 }
7852 }
7853 if (!handle->reassoc_on && handle->is_reassoc_timer_set) {
7854 woal_cancel_timer(&handle->reassoc_timer);
7855 handle->is_reassoc_timer_set = MFALSE;
7856 }
7857 #endif /* REASSOCIATION */
7858
7859 if (handle->is_fw_dump_timer_set) {
7860 woal_cancel_timer(&handle->fw_dump_timer);
7861 handle->is_fw_dump_timer_set = MFALSE;
7862 }
7863
7864 #ifdef WIFI_DIRECT_SUPPORT
7865 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
7866 if (handle->is_go_timer_set) {
7867 woal_cancel_timer(&handle->go_timer);
7868 handle->is_go_timer_set = MFALSE;
7869 }
7870 #endif
7871 #endif
7872
7873 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
7874 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
7875 if (handle->is_remain_timer_set) {
7876 woal_cancel_timer(&handle->remain_timer);
7877 woal_remain_timer_func(handle);
7878 }
7879 #endif
7880 #endif
7881
7882 done:
7883 LEAVE();
7884 return ret;
7885 }
7886
7887 /**
7888 * @brief This function return the point to structure moal_private
7889 *
7890 * @param handle Pointer to structure moal_handle
7891 * @param bss_index BSS index number
7892 *
7893 * @return moal_private pointer or NULL
7894 */
7895 moal_private *woal_bss_index_to_priv(moal_handle *handle, t_u8 bss_index)
7896 {
7897 int i;
7898
7899 ENTER();
7900 if (!handle || !handle->priv_num) {
7901 LEAVE();
7902 return NULL;
7903 }
7904 for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
7905 if (handle->priv[i] &&
7906 (handle->priv[i]->bss_index == bss_index)) {
7907 LEAVE();
7908 return handle->priv[i];
7909 }
7910 }
7911
7912 LEAVE();
7913 return NULL;
7914 }
7915
7916 /**
7917 * @brief This function alloc mlan_buffer.
7918 * @param handle A pointer to moal_handle structure
7919 * @param size buffer size to allocate
7920 *
7921 * @return mlan_buffer pointer or NULL
7922 */
7923 pmlan_buffer woal_alloc_mlan_buffer(moal_handle *handle, int size)
7924 {
7925 mlan_buffer *pmbuf = NULL;
7926 struct sk_buff *skb;
7927 gfp_t flag;
7928
7929 ENTER();
7930
7931 flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
7932 if (size <= 0) {
7933 PRINTM(MERROR, "Buffer size must be positive\n");
7934 LEAVE();
7935 return NULL;
7936 }
7937
7938 skb = __dev_alloc_skb(size + sizeof(mlan_buffer), flag);
7939 if (!skb) {
7940 PRINTM(MERROR, "%s: No free skb\n", __func__);
7941 LEAVE();
7942 return NULL;
7943 }
7944 skb_reserve(skb, sizeof(mlan_buffer));
7945 pmbuf = (mlan_buffer *)skb->head;
7946 memset((u8 *)pmbuf, 0, sizeof(mlan_buffer));
7947 pmbuf->pdesc = (t_void *)skb;
7948 pmbuf->pbuf = (t_u8 *)skb->data;
7949 atomic_inc(&handle->mbufalloc_count);
7950 LEAVE();
7951 return pmbuf;
7952 }
7953
7954 /**
7955 * @brief This function alloc mlan_ioctl_req.
7956 *
7957 * @param size buffer size to allocate
7958 *
7959 * @return mlan_ioctl_req pointer or NULL
7960 */
7961 pmlan_ioctl_req woal_alloc_mlan_ioctl_req(int size)
7962 {
7963 mlan_ioctl_req *req = NULL;
7964 gfp_t flag;
7965
7966 ENTER();
7967
7968 flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
7969 req = kzalloc((sizeof(mlan_ioctl_req) + size + sizeof(int) +
7970 sizeof(wait_queue)),
7971 flag);
7972 if (!req) {
7973 PRINTM(MERROR, "%s: Fail to alloc ioctl buffer\n", __func__);
7974 LEAVE();
7975 return NULL;
7976 }
7977 req->pbuf = (t_u8 *)req + sizeof(mlan_ioctl_req) + sizeof(wait_queue);
7978 req->buf_len = (t_u32)size;
7979 req->reserved_1 = (t_ptr)((t_u8 *)req + sizeof(mlan_ioctl_req));
7980
7981 LEAVE();
7982 return req;
7983 }
7984
7985 /**
7986 * @brief This function frees mlan_buffer.
7987 * @param handle A pointer to moal_handle structure
7988 * @param pmbuf Pointer to mlan_buffer
7989 *
7990 * @return N/A
7991 */
7992 void woal_free_mlan_buffer(moal_handle *handle, pmlan_buffer pmbuf)
7993 {
7994 ENTER();
7995 if (!pmbuf) {
7996 LEAVE();
7997 return;
7998 }
7999 if (pmbuf->pdesc)
8000 dev_kfree_skb_any((struct sk_buff *)pmbuf->pdesc);
8001 else
8002 PRINTM(MERROR, "free mlan buffer without pdesc\n");
8003 atomic_dec(&handle->mbufalloc_count);
8004 LEAVE();
8005 return;
8006 }
8007
8008 /**
8009 * @brief This function get card info from card type
8010 *
8011 * @param phandle A pointer to moal_handle
8012 *
8013 * @return 0-success , otherwise failure.
8014 */
8015 static int woal_get_card_info(moal_handle *phandle)
8016 {
8017 int ret = 0;
8018
8019 ENTER();
8020
8021 switch (phandle->card_type) {
8022 #ifdef SD8801
8023 case CARD_TYPE_SD8801:
8024 phandle->card_info = &card_info_SD8801;
8025 break;
8026 #endif
8027 #ifdef SD8887
8028 case CARD_TYPE_SD8887:
8029 phandle->card_info = &card_info_SD8887;
8030 break;
8031 #endif
8032 #if defined(SD8897)
8033 case CARD_TYPE_SD8897:
8034 phandle->card_info = &card_info_SD8897;
8035 break;
8036 #endif
8037 #if defined(PCIE8897)
8038 case CARD_TYPE_PCIE8897:
8039 phandle->card_info = &card_info_PCIE8897;
8040 break;
8041 #endif
8042 #if defined(USB8897)
8043 case CARD_TYPE_USB8897:
8044 phandle->card_info = &card_info_USB8897;
8045 break;
8046 #endif
8047 #ifdef SD8977
8048 case CARD_TYPE_SD8977:
8049 phandle->card_info = &card_info_SD8977;
8050 break;
8051 #endif
8052 #ifdef SD8978
8053 case CARD_TYPE_SD8978:
8054 phandle->card_info = &card_info_SD8978;
8055 break;
8056 #endif
8057 #ifdef SD8997
8058 case CARD_TYPE_SD8997:
8059 phandle->card_info = &card_info_SD8997;
8060 break;
8061 #endif
8062 #ifdef SD9098
8063 case CARD_TYPE_SD9098:
8064 phandle->card_info = &card_info_SD9098;
8065 break;
8066 #endif
8067 #ifdef SD9097
8068 case CARD_TYPE_SD9097:
8069 phandle->card_info = &card_info_SD9097;
8070 break;
8071 #endif
8072 #ifdef SDNW62X
8073 case CARD_TYPE_SDNW62X:
8074 phandle->card_info = &card_info_SDNW62X;
8075 break;
8076 #endif
8077 #ifdef SD9177
8078 case CARD_TYPE_SD9177:
8079 phandle->card_info = &card_info_SD9177;
8080 phandle->event_fw_dump = MFALSE;
8081 break;
8082 #endif
8083 #ifdef PCIE8997
8084 case CARD_TYPE_PCIE8997:
8085 phandle->card_info = &card_info_PCIE8997;
8086 break;
8087 #endif
8088 #ifdef PCIE9097
8089 case CARD_TYPE_PCIE9097:
8090 phandle->card_info = &card_info_PCIE9097;
8091 break;
8092 #endif
8093 #ifdef PCIENW62X
8094 case CARD_TYPE_PCIENW62X:
8095 phandle->card_info = &card_info_PCIENW62X;
8096 break;
8097 #endif
8098 #ifdef PCIE9098
8099 case CARD_TYPE_PCIE9098:
8100 phandle->card_info = &card_info_PCIE9098;
8101 phandle->event_fw_dump = MTRUE;
8102 break;
8103 #endif
8104 #ifdef USB8801
8105 case CARD_TYPE_USB8801:
8106 phandle->card_info = &card_info_USB8801;
8107 break;
8108 #endif
8109 #ifdef USB8997
8110 case CARD_TYPE_USB8997:
8111 phandle->card_info = &card_info_USB8997;
8112 break;
8113 #endif
8114 #ifdef USB8978
8115 case CARD_TYPE_USB8978:
8116 phandle->card_info = &card_info_USB8978;
8117 break;
8118 #endif
8119 #ifdef USB9098
8120 case CARD_TYPE_USB9098:
8121 phandle->card_info = &card_info_USB9098;
8122 break;
8123 #endif
8124 #ifdef USB9097
8125 case CARD_TYPE_USB9097:
8126 phandle->card_info = &card_info_USB9097;
8127 break;
8128 #endif
8129 #ifdef USBNW62X
8130 case CARD_TYPE_USBNW62X:
8131 phandle->card_info = &card_info_USBNW62X;
8132 break;
8133 #endif
8134 #ifdef SD8987
8135 case CARD_TYPE_SD8987:
8136 phandle->card_info = &card_info_SD8987;
8137 break;
8138 #endif
8139 default:
8140 PRINTM(MERROR,
8141 "woal_get_card_info can't get right card type \n");
8142 ret = -1;
8143 break;
8144 }
8145
8146 LEAVE();
8147 return ret;
8148 }
8149
8150 #ifdef STA_SUPPORT
8151 #endif /* STA_SUPPORT */
8152
8153 /**
8154 * @brief This function handles events generated by firmware
8155 *
8156 * @param priv A pointer to moal_private structure
8157 * @param payload A pointer to payload buffer
8158 * @param len Length of the payload
8159 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
8160 */
8161 mlan_status woal_broadcast_event(moal_private *priv, t_u8 *payload, t_u32 len)
8162 {
8163 mlan_status ret = MLAN_STATUS_SUCCESS;
8164 struct sk_buff *skb = NULL;
8165 struct nlmsghdr *nlh = NULL;
8166 moal_handle *handle = priv->phandle;
8167 struct net_device *netdev = priv->netdev;
8168 struct sock *sk = handle->nl_sk;
8169
8170 ENTER();
8171
8172 /* interface name to be prepended to event */
8173 /* NL_MAX_PAYLOAD = 3 * 1024 */
8174 if ((len + IFNAMSIZ) > NL_MAX_PAYLOAD) {
8175 PRINTM(MERROR, "event size is too big, len=%d\n", (int)len);
8176 ret = MLAN_STATUS_FAILURE;
8177 goto done;
8178 }
8179 if (sk) {
8180 /* Allocate skb */
8181 skb = alloc_skb(NLMSG_SPACE(NL_MAX_PAYLOAD), GFP_ATOMIC);
8182 if (!skb) {
8183 PRINTM(MERROR, "Could not allocate skb for netlink\n");
8184 ret = MLAN_STATUS_FAILURE;
8185 goto done;
8186 }
8187 memset(skb->data, 0, NLMSG_SPACE(NL_MAX_PAYLOAD));
8188
8189 nlh = (struct nlmsghdr *)skb->data;
8190 nlh->nlmsg_len = NLMSG_SPACE(len + IFNAMSIZ);
8191
8192 /* From kernel */
8193 nlh->nlmsg_pid = 0;
8194 nlh->nlmsg_flags = 0;
8195
8196 /* Data */
8197 skb_put(skb, nlh->nlmsg_len);
8198 moal_memcpy_ext(handle, NLMSG_DATA(nlh), netdev->name, IFNAMSIZ,
8199 nlh->nlmsg_len - NLMSG_LENGTH(0));
8200 moal_memcpy_ext(handle, ((t_u8 *)(NLMSG_DATA(nlh))) + IFNAMSIZ,
8201 payload, len,
8202 nlh->nlmsg_len - NLMSG_LENGTH(IFNAMSIZ));
8203
8204 /* From Kernel */
8205 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
8206 NETLINK_CB(skb).pid = 0;
8207 #else
8208 NETLINK_CB(skb).portid = 0;
8209 #endif
8210
8211 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
8212 /* Multicast message */
8213 NETLINK_CB(skb).dst_pid = 0;
8214 #endif
8215
8216 /* Multicast group number */
8217 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
8218 NETLINK_CB(skb).dst_groups = NL_MULTICAST_GROUP;
8219 #else
8220 NETLINK_CB(skb).dst_group = NL_MULTICAST_GROUP;
8221 #endif
8222
8223 /* Send message */
8224 ret = netlink_broadcast(sk, skb, 0, NL_MULTICAST_GROUP,
8225 GFP_ATOMIC);
8226 if (ret) {
8227 PRINTM(MWARN, "netlink_broadcast failed: ret=%d\n",
8228 ret);
8229 goto done;
8230 }
8231
8232 ret = MLAN_STATUS_SUCCESS;
8233 } else {
8234 PRINTM(MERROR,
8235 "Could not send event through NETLINK. Link down.\n");
8236 ret = MLAN_STATUS_FAILURE;
8237 }
8238 done:
8239 LEAVE();
8240 return ret;
8241 }
8242
8243 #ifdef REASSOCIATION
8244 /**
8245 * @brief This function handles re-association. it is triggered
8246 * by re-assoc timer.
8247 *
8248 * @param data A pointer to wlan_thread structure
8249 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
8250 */
8251 int woal_reassociation_thread(void *data)
8252 {
8253 moal_thread *pmoal_thread = data;
8254 moal_private *priv = NULL;
8255 moal_handle *handle = (moal_handle *)pmoal_thread->handle;
8256 #if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 13, 0)
8257 wait_queue_t wait;
8258 #else
8259 wait_queue_entry_t wait;
8260 #endif
8261 int i;
8262 BOOLEAN reassoc_timer_req;
8263 mlan_802_11_ssid req_ssid;
8264 mlan_ssid_bssid *ssid_bssid = NULL;
8265 mlan_status status;
8266 mlan_bss_info bss_info;
8267 t_u32 timer_val = MOAL_TIMER_10S;
8268 t_u32 retry_count = 0;
8269 t_u32 retry_interval = 0;
8270 t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
8271 ENTER();
8272 ssid_bssid = kmalloc(sizeof(mlan_ssid_bssid), GFP_KERNEL);
8273 if (!ssid_bssid) {
8274 LEAVE();
8275 return 0;
8276 }
8277
8278 woal_activate_thread(pmoal_thread);
8279 init_waitqueue_entry(&wait, current);
8280
8281 current->flags |= PF_NOFREEZE;
8282
8283 for (;;) {
8284 add_wait_queue(&pmoal_thread->wait_q, &wait);
8285 set_current_state(TASK_INTERRUPTIBLE);
8286
8287 schedule();
8288
8289 set_current_state(TASK_RUNNING);
8290 remove_wait_queue(&pmoal_thread->wait_q, &wait);
8291 #if defined(USB)
8292 if (IS_USB(handle->card_type)) {
8293 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
8294 try_to_freeze(0); /* Argument is not used by the kernel
8295 */
8296 #else
8297 try_to_freeze();
8298 #endif
8299 }
8300 #endif
8301
8302 /* Cancel re-association timer */
8303 if (handle->is_reassoc_timer_set == MTRUE) {
8304 woal_cancel_timer(&handle->reassoc_timer);
8305 handle->is_reassoc_timer_set = MFALSE;
8306 }
8307
8308 if (handle->surprise_removed)
8309 break;
8310 if (kthread_should_stop())
8311 break;
8312
8313 if (handle->hardware_status != HardwareStatusReady) {
8314 PRINTM(MINFO,
8315 "Reassoc: Hardware status is not correct\n");
8316 continue;
8317 }
8318
8319 PRINTM(MEVENT, "Reassoc: Thread waking up...\n");
8320 reassoc_timer_req = MFALSE;
8321 #ifdef STA_CFG80211
8322 for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM) &&
8323 (priv = handle->priv[i]);
8324 i++) {
8325 if (priv->roaming_required) {
8326 priv->roaming_required = MFALSE;
8327 PRINTM(MEVENT, "Try to roaming......\n");
8328 woal_start_roaming(priv);
8329 break;
8330 }
8331 }
8332 #endif
8333
8334 for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM) &&
8335 (priv = handle->priv[i]);
8336 i++) {
8337 if (priv->reassoc_required == MFALSE) {
8338 priv->auto_assoc_priv.drv_assoc.status = MFALSE;
8339 priv->auto_assoc_priv.drv_reconnect.status =
8340 MFALSE;
8341 continue;
8342 }
8343
8344 if (priv->auto_assoc_priv.auto_assoc_trigger_flag ==
8345 AUTO_ASSOC_TYPE_DRV_RECONN ||
8346 priv->auto_assoc_priv.auto_assoc_trigger_flag ==
8347 AUTO_ASSOC_TYPE_DRV_ASSOC) {
8348 if (priv->auto_assoc_priv
8349 .auto_assoc_trigger_flag ==
8350 AUTO_ASSOC_TYPE_DRV_RECONN) {
8351 retry_count = priv->auto_assoc_priv
8352 .drv_reconnect
8353 .retry_count;
8354 retry_interval =
8355 priv->auto_assoc_priv
8356 .drv_reconnect
8357 .retry_interval *
8358 1000;
8359 if (retry_count == 0xff)
8360 retry_count =
8361 AUTO_ASSOC_RETRY_FOREVER;
8362 priv->auto_assoc_priv.drv_reconnect
8363 .status = MTRUE;
8364 PRINTM(MINFO,
8365 "Auto assoc: driver auto re-connect triggered\n");
8366 }
8367 if (priv->auto_assoc_priv
8368 .auto_assoc_trigger_flag ==
8369 AUTO_ASSOC_TYPE_DRV_ASSOC) {
8370 /* disconnect before driver
8371 * assoc */
8372 woal_disconnect(priv, MOAL_IOCTL_WAIT,
8373 NULL,
8374 DEF_DEAUTH_REASON_CODE);
8375 if (priv->auto_assoc_priv
8376 .auto_assoc_type_on &
8377 (0x1 << (AUTO_ASSOC_TYPE_DRV_ASSOC -
8378 1))) {
8379 retry_count =
8380 priv->auto_assoc_priv
8381 .drv_assoc
8382 .retry_count;
8383 retry_interval =
8384 priv->auto_assoc_priv
8385 .drv_assoc
8386 .retry_interval *
8387 1000;
8388 if (retry_count == 0xff)
8389 retry_count =
8390 AUTO_ASSOC_RETRY_FOREVER;
8391 else
8392 retry_count =
8393 retry_count + 1;
8394 PRINTM(MINFO,
8395 "Auto assoc: driver auto assoc triggered\n");
8396 } else {
8397 retry_count = 1;
8398 retry_interval = 0;
8399 PRINTM(MINFO,
8400 "Auto assoc: set asynced essid with drv auto assoc disable\n");
8401 }
8402 priv->reassoc_required = MTRUE;
8403 priv->auto_assoc_priv.drv_assoc.status =
8404 MTRUE;
8405 }
8406 priv->auto_assoc_priv.auto_assoc_trigger_flag =
8407 AUTO_ASSOC_TYPE_NONE;
8408 }
8409
8410 if (retry_count == 0 &&
8411 (priv->auto_assoc_priv.drv_assoc.status == MTRUE ||
8412 priv->auto_assoc_priv.drv_reconnect.status ==
8413 MTRUE)) {
8414 PRINTM(MINFO,
8415 "Auto assoc: stop driver auto assoc: the retry count is 0\n");
8416 priv->auto_assoc_priv.drv_assoc.status = MFALSE;
8417 priv->auto_assoc_priv.drv_reconnect.status =
8418 MFALSE;
8419 continue;
8420 }
8421
8422 memset(&bss_info, 0x00, sizeof(bss_info));
8423
8424 if (MLAN_STATUS_SUCCESS !=
8425 woal_get_bss_info(priv, MOAL_IOCTL_WAIT,
8426 &bss_info)) {
8427 PRINTM(MINFO, "Ressoc: Fail to get bss info\n");
8428 priv->reassoc_required = MFALSE;
8429 priv->auto_assoc_priv.drv_assoc.status = MFALSE;
8430 priv->auto_assoc_priv.drv_reconnect.status =
8431 MFALSE;
8432 continue;
8433 }
8434
8435 if (bss_info.bss_mode != MLAN_BSS_MODE_INFRA ||
8436 priv->media_connected != MFALSE) {
8437 PRINTM(MINFO,
8438 "Reassoc: ad-hoc mode or media connected\n");
8439 priv->reassoc_required = MFALSE;
8440 priv->auto_assoc_priv.drv_assoc.status = MFALSE;
8441 priv->auto_assoc_priv.drv_reconnect.status =
8442 MFALSE;
8443 continue;
8444 }
8445 /** avoid on going scan from other thread */
8446 if (handle->scan_pending_on_block) {
8447 reassoc_timer_req = MTRUE;
8448 break;
8449 }
8450
8451 /* The semaphore is used to avoid reassociation
8452 thread and wlan_set_scan/wlan_set_essid
8453 interrupting each other. Reassociation should
8454 be disabled completely by application if
8455 wlan_set_user_scan_ioctl/wlan_set_wap is
8456 used.
8457 */
8458 if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
8459 PRINTM(MERROR,
8460 "Acquire semaphore error, reassociation thread\n");
8461 reassoc_timer_req = MTRUE;
8462 break;
8463 }
8464
8465 PRINTM(MINFO, "Reassoc: Required ESSID: %s\n",
8466 priv->prev_ssid_bssid.ssid.ssid);
8467 PRINTM(MINFO, "Reassoc: Performing Active Scan\n");
8468
8469 memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid));
8470 moal_memcpy_ext(priv->phandle, &req_ssid,
8471 &priv->prev_ssid_bssid.ssid,
8472 sizeof(mlan_802_11_ssid),
8473 sizeof(mlan_802_11_ssid));
8474
8475 /* Do specific SSID scanning */
8476 if (MLAN_STATUS_SUCCESS !=
8477 woal_request_scan(priv, MOAL_IOCTL_WAIT,
8478 &req_ssid)) {
8479 PRINTM(MERROR,
8480 "Reassoc: Fail to do specific scan\n");
8481 reassoc_timer_req = MTRUE;
8482 MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
8483 break;
8484 }
8485
8486 if (handle->surprise_removed) {
8487 MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
8488 break;
8489 }
8490
8491 memset(ssid_bssid, 0, sizeof(mlan_ssid_bssid));
8492
8493 if (priv->auto_assoc_priv.drv_assoc.status == MTRUE) {
8494 if (priv->assoc_with_mac &&
8495 memcmp(priv->prev_ssid_bssid.bssid,
8496 zero_mac, MLAN_MAC_ADDR_LENGTH)) {
8497 /* Search AP by BSSID & SSID */
8498 PRINTM(MINFO,
8499 "Reassoc: Search AP by BSSID & SSID\n");
8500 moal_memcpy_ext(
8501 priv->phandle,
8502 &ssid_bssid->bssid,
8503 &priv->prev_ssid_bssid.bssid,
8504 MLAN_MAC_ADDR_LENGTH,
8505 sizeof(mlan_802_11_mac_addr));
8506 } else {
8507 /* Search AP by ESSID for driver
8508 * auto reassoc */
8509 PRINTM(MINFO,
8510 "Reassoc: Search AP by ESSID\n");
8511 }
8512
8513 moal_memcpy_ext(priv->phandle,
8514 &ssid_bssid->ssid,
8515 &priv->prev_ssid_bssid.ssid,
8516 sizeof(mlan_802_11_ssid),
8517 sizeof(mlan_802_11_ssid));
8518
8519 } else {
8520 /* Search AP by BSSID first */
8521 PRINTM(MINFO,
8522 "Reassoc: Search AP by BSSID first\n");
8523 moal_memcpy_ext(priv->phandle,
8524 &ssid_bssid->bssid,
8525 &priv->prev_ssid_bssid.bssid,
8526 MLAN_MAC_ADDR_LENGTH,
8527 sizeof(mlan_802_11_mac_addr));
8528 }
8529
8530 status = woal_find_best_network(priv, MOAL_IOCTL_WAIT,
8531 ssid_bssid);
8532 #ifdef STA_WEXT
8533 if (status == MLAN_STATUS_SUCCESS) {
8534 if (MLAN_STATUS_SUCCESS !=
8535 woal_11d_check_ap_channel(priv,
8536 MOAL_IOCTL_WAIT,
8537 ssid_bssid)) {
8538 PRINTM(MERROR,
8539 "Reassoc: The AP's channel is invalid for current region\n");
8540 status = MLAN_STATUS_FAILURE;
8541 }
8542 }
8543 #endif
8544 /** The find AP without ssid, we need re-search
8545 */
8546 if (status == MLAN_STATUS_SUCCESS &&
8547 !ssid_bssid->ssid.ssid_len) {
8548 PRINTM(MINFO,
8549 "Reassoc: Skip AP without ssid\n");
8550 status = MLAN_STATUS_FAILURE;
8551 }
8552
8553 if (priv->auto_assoc_priv.drv_assoc.status != MTRUE &&
8554 MLAN_STATUS_SUCCESS != status) {
8555 PRINTM(MINFO,
8556 "Reassoc: AP not found in scan list\n");
8557 PRINTM(MINFO, "Reassoc: Search AP by SSID\n");
8558 /* Search AP by SSID */
8559 memset(ssid_bssid, 0, sizeof(mlan_ssid_bssid));
8560 moal_memcpy_ext(priv->phandle,
8561 &ssid_bssid->ssid,
8562 &priv->prev_ssid_bssid.ssid,
8563 sizeof(mlan_802_11_ssid),
8564 sizeof(mlan_802_11_ssid));
8565 status = woal_find_best_network(
8566 priv, MOAL_IOCTL_WAIT, ssid_bssid);
8567 #ifdef STA_WEXT
8568 if (status == MLAN_STATUS_SUCCESS) {
8569 if (MLAN_STATUS_SUCCESS !=
8570 woal_11d_check_ap_channel(
8571 priv, MOAL_IOCTL_WAIT,
8572 ssid_bssid)) {
8573 PRINTM(MERROR,
8574 "Reassoc: The AP's channel is invalid for current region\n");
8575 status = MLAN_STATUS_FAILURE;
8576 }
8577 }
8578 #endif
8579 }
8580
8581 if (status == MLAN_STATUS_SUCCESS) {
8582 /* set the wep key */
8583 if (bss_info.wep_status) {
8584 if (MLAN_STATUS_SUCCESS !=
8585 woal_enable_wep_key(
8586 priv, MOAL_IOCTL_WAIT)) {
8587 PRINTM(MERROR,
8588 "Reassoc: woal_enable_wep_key failed\n");
8589 status = MLAN_STATUS_FAILURE;
8590 }
8591 }
8592 /* Zero SSID implies use BSSID to
8593 * connect */
8594 memset(&ssid_bssid->ssid, 0,
8595 sizeof(mlan_802_11_ssid));
8596 status = woal_bss_start(priv, MOAL_IOCTL_WAIT,
8597 ssid_bssid);
8598 if (status != MLAN_STATUS_SUCCESS)
8599 PRINTM(MERROR,
8600 "Reassoc: woal_bss_start failed\n");
8601 }
8602
8603 if (priv->media_connected == MFALSE)
8604 reassoc_timer_req = MTRUE;
8605 else {
8606 mlan_ds_rate *rate = NULL;
8607 mlan_ioctl_req *req = NULL;
8608
8609 reassoc_timer_req = MFALSE;
8610 if (priv->auto_assoc_priv.drv_assoc.status ==
8611 MTRUE) {
8612 memset(&bss_info, 0, sizeof(bss_info));
8613 if (MLAN_STATUS_SUCCESS !=
8614 woal_get_bss_info(priv,
8615 MOAL_IOCTL_WAIT,
8616 &bss_info)) {
8617 PRINTM(MINFO,
8618 "Ressoc: Fail to get bss info after driver auto reassoc\n");
8619 } else {
8620 moal_memcpy_ext(
8621 priv->phandle,
8622 &priv->prev_ssid_bssid
8623 .ssid,
8624 &bss_info.ssid,
8625 sizeof(mlan_802_11_ssid),
8626 sizeof(mlan_802_11_ssid));
8627 moal_memcpy_ext(
8628 priv->phandle,
8629 &priv->prev_ssid_bssid
8630 .bssid,
8631 &bss_info.bssid,
8632 MLAN_MAC_ADDR_LENGTH,
8633 sizeof(priv->prev_ssid_bssid
8634 .bssid));
8635 }
8636 priv->auto_assoc_priv.drv_assoc.status =
8637 MFALSE;
8638 }
8639 priv->auto_assoc_priv.drv_reconnect.status =
8640 MFALSE;
8641 if (priv->rate_index != AUTO_RATE) {
8642 req = woal_alloc_mlan_ioctl_req(
8643 sizeof(mlan_ds_rate));
8644
8645 if (req == NULL) {
8646 LEAVE();
8647 return MLAN_STATUS_FAILURE;
8648 }
8649
8650 rate = (mlan_ds_rate *)req->pbuf;
8651 rate->param.rate_cfg.rate_type =
8652 MLAN_RATE_INDEX;
8653 rate->sub_command = MLAN_OID_RATE_CFG;
8654 req->req_id = MLAN_IOCTL_RATE;
8655
8656 req->action = MLAN_ACT_SET;
8657
8658 rate->param.rate_cfg.rate =
8659 priv->rate_index;
8660
8661 status = woal_request_ioctl(
8662 priv, req, MOAL_IOCTL_WAIT);
8663 if (status != MLAN_STATUS_SUCCESS) {
8664 if (status !=
8665 MLAN_STATUS_PENDING)
8666 kfree(req);
8667 LEAVE();
8668 return MLAN_STATUS_FAILURE;
8669 }
8670 kfree(req);
8671 }
8672 }
8673
8674 MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
8675 }
8676
8677 if (handle->surprise_removed)
8678 break;
8679
8680 if (reassoc_timer_req == MTRUE) {
8681 handle->is_reassoc_timer_set = MTRUE;
8682 if (priv &&
8683 (priv->auto_assoc_priv.drv_assoc.status == MTRUE ||
8684 priv->auto_assoc_priv.drv_reconnect.status ==
8685 MTRUE)) {
8686 PRINTM(MEVENT,
8687 "Auto assoc: No AP found or assoc failed. "
8688 "Restarting re-assoc Timer: %d\n",
8689 (int)retry_interval);
8690 if (retry_count != AUTO_ASSOC_RETRY_FOREVER)
8691 retry_count--;
8692 woal_mod_timer(&handle->reassoc_timer,
8693 retry_interval);
8694 } else {
8695 PRINTM(MEVENT,
8696 "Reassoc: No AP found or assoc failed. "
8697 "Restarting re-assoc Timer: %d\n",
8698 (int)timer_val);
8699 woal_mod_timer(&handle->reassoc_timer,
8700 timer_val);
8701 }
8702 } else {
8703 if (priv) {
8704 priv->auto_assoc_priv.drv_assoc.status = MFALSE;
8705 priv->auto_assoc_priv.drv_reconnect.status =
8706 MFALSE;
8707 priv->set_asynced_essid_flag = MFALSE;
8708 }
8709 }
8710 }
8711 woal_deactivate_thread(pmoal_thread);
8712 kfree(ssid_bssid);
8713 LEAVE();
8714 return MLAN_STATUS_SUCCESS;
8715 }
8716
8717 /**
8718 * @brief This function triggers re-association by waking up
8719 * re-assoc thread.
8720 *
8721 * @param context A pointer to context
8722 * @return N/A
8723 */
8724 void woal_reassoc_timer_func(void *context)
8725 {
8726 moal_handle *handle = (moal_handle *)context;
8727
8728 ENTER();
8729
8730 PRINTM(MINFO, "reassoc_timer fired.\n");
8731 handle->is_reassoc_timer_set = MFALSE;
8732
8733 PRINTM(MINFO, "Waking Up the Reassoc Thread\n");
8734 wake_up_interruptible(&handle->reassoc_thread.wait_q);
8735
8736 LEAVE();
8737 return;
8738 }
8739 #endif /* REASSOCIATION */
8740
8741 /**
8742 * @brief This function triggers process hang
8743 * re-assoc thread.
8744 *
8745 * @param context A pointer to context
8746 * @return N/A
8747 */
8748 void woal_fw_dump_timer_func(void *context)
8749 {
8750 moal_handle *handle = (moal_handle *)context;
8751
8752 ENTER();
8753
8754 PRINTM(MMSG, "fw_dump_timer fired.\n");
8755 handle->is_fw_dump_timer_set = MFALSE;
8756 if (handle->priv_num)
8757 woal_process_hang(handle);
8758 LEAVE();
8759 return;
8760 }
8761
8762 #ifdef STA_SUPPORT
8763 /**
8764 * @brief update dscp mapping from assoc_resp/reassoc_resp
8765 *
8766 * @param priv Pointer to the moal_private driver data struct
8767 *
8768 * @return N/A
8769 */
8770 void woal_update_dscp_mapping(moal_private *priv)
8771 {
8772 mlan_ds_misc_assoc_rsp *assoc_rsp = NULL;
8773 IEEEtypes_AssocRsp_t *passoc_rsp = NULL;
8774 IEEEtypes_Header_t *qos_mapping_ie = NULL;
8775 DSCP_Range_t *pdscp_range = NULL;
8776 t_u8 dscp_except_num = 0;
8777 DSCP_Exception_t dscp_except[MAX_DSCP_EXCEPTION_NUM];
8778 int i, j;
8779 ENTER();
8780 assoc_rsp = kmalloc(sizeof(mlan_ds_misc_assoc_rsp), GFP_KERNEL);
8781 if (!assoc_rsp) {
8782 LEAVE();
8783 return;
8784 }
8785 memset(assoc_rsp, 0, sizeof(mlan_ds_misc_assoc_rsp));
8786 if (MLAN_STATUS_FAILURE ==
8787 woal_get_assoc_rsp(priv, assoc_rsp, MOAL_NO_WAIT)) {
8788 PRINTM(MERROR, "woal_get_assoc_rsp failed\n");
8789 kfree(assoc_rsp);
8790 LEAVE();
8791 return;
8792 }
8793
8794 passoc_rsp = (IEEEtypes_AssocRsp_t *)assoc_rsp->assoc_resp_buf;
8795 memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map));
8796 qos_mapping_ie = (IEEEtypes_Header_t *)woal_parse_ie_tlv(
8797 passoc_rsp->ie_buffer,
8798 assoc_rsp->assoc_resp_len - ASSOC_RESP_FIXED_SIZE, QOS_MAPPING);
8799 if (qos_mapping_ie &&
8800 (qos_mapping_ie->len >= (sizeof(DSCP_Range_t) * MAX_NUM_TID))) {
8801 dscp_except_num = (qos_mapping_ie->len -
8802 sizeof(DSCP_Range_t) * MAX_NUM_TID) /
8803 sizeof(DSCP_Exception_t);
8804 if (dscp_except_num > MAX_DSCP_EXCEPTION_NUM) {
8805 PRINTM(MERROR, "dscp_except_num exceeds MAX limit\n");
8806 kfree(assoc_rsp);
8807 LEAVE();
8808 return;
8809 }
8810 moal_memcpy_ext(priv->phandle, dscp_except,
8811 (t_u8 *)qos_mapping_ie +
8812 sizeof(IEEEtypes_Header_t),
8813 dscp_except_num * sizeof(DSCP_Exception_t),
8814 sizeof(dscp_except));
8815 pdscp_range =
8816 (DSCP_Range_t *)((t_u8 *)qos_mapping_ie +
8817 sizeof(IEEEtypes_Header_t) +
8818 dscp_except_num *
8819 sizeof(DSCP_Exception_t));
8820 for (i = 0; i < MAX_NUM_TID; i++) {
8821 PRINTM(MEVENT, "TID %d: dscp_low=%d, dscp_high=%d\n", i,
8822 pdscp_range->dscp_low_value,
8823 pdscp_range->dscp_high_value);
8824 if (pdscp_range->dscp_low_value != 0xff &&
8825 pdscp_range->dscp_high_value != 0xff &&
8826 pdscp_range->dscp_high_value <= 63) {
8827 for (j = pdscp_range->dscp_low_value;
8828 j <= pdscp_range->dscp_high_value; j++)
8829 priv->dscp_map[j] = i;
8830 }
8831 pdscp_range++;
8832 }
8833 for (i = 0; i < dscp_except_num; i++) {
8834 if ((dscp_except[i].dscp_value <= 63) &&
8835 (dscp_except[i].user_priority <= 7)) {
8836 PRINTM(MEVENT,
8837 "dscp excpt: value=%d priority=%d\n",
8838 dscp_except[i].dscp_value,
8839 dscp_except[i].user_priority);
8840 priv->dscp_map[dscp_except[i].dscp_value] =
8841 dscp_except[i].user_priority;
8842 }
8843 }
8844 }
8845 kfree(assoc_rsp);
8846 LEAVE();
8847 }
8848
8849 /**
8850 * @brief Sends disconnect event
8851 *
8852 * @param priv A pointer to moal_private struct
8853 * @param disconnect_reason disconnect reason code
8854 * @return N/A
8855 */
8856 t_void woal_send_disconnect_to_system(moal_private *priv,
8857 t_u16 disconnect_reason)
8858 {
8859 int custom_len = 0;
8860 t_u8 event_buf[32];
8861 #ifdef STA_WEXT
8862 union iwreq_data wrqu;
8863 #endif
8864 #ifdef STA_CFG80211
8865 unsigned long flags;
8866 #endif
8867 int cfg80211_wext = priv->phandle->params.cfg80211_wext;
8868 #ifdef STA_CFG80211
8869 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
8870 mlan_ds_misc_gtk_rekey_data zero_gtk;
8871 #endif
8872 #endif
8873 #ifdef STA_CFG80211
8874 t_u16 reason_code = 0;
8875 #endif
8876 ENTER();
8877 priv->media_connected = MFALSE;
8878 #ifdef STA_CFG80211
8879 if (!disconnect_reason)
8880 reason_code = MLAN_REASON_DEAUTH_LEAVING;
8881 else
8882 reason_code = disconnect_reason;
8883 #endif
8884 woal_stop_queue(priv->netdev);
8885 if (netif_carrier_ok(priv->netdev))
8886 netif_carrier_off(priv->netdev);
8887 woal_flush_tcp_sess_queue(priv);
8888
8889 #ifdef STA_CFG80211
8890 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
8891 priv->gtk_data_ready = MFALSE;
8892 memset(&zero_gtk, 0x00, sizeof(zero_gtk));
8893 if (priv->phandle->params.gtk_rekey_offload ==
8894 GTK_REKEY_OFFLOAD_ENABLE &&
8895 memcmp(&priv->gtk_rekey_data, &zero_gtk,
8896 sizeof(priv->gtk_rekey_data)) != 0) {
8897 PRINTM(MCMND, "clear GTK in woal_send_disconnect_to_system\n");
8898 if (MLAN_STATUS_FAILURE == woal_set_rekey_data(priv, NULL,
8899 MLAN_ACT_CLEAR,
8900 MOAL_NO_WAIT))
8901 PRINTM(MERROR, "%s: clear GTK failed!\n", __func__);
8902 }
8903 memset(&priv->gtk_rekey_data, 0, sizeof(mlan_ds_misc_gtk_rekey_data));
8904 #endif
8905 #endif
8906
8907 #ifdef STA_CFG80211
8908 if (priv->bss_type == MLAN_BSS_TYPE_STA)
8909 woal_flush_tdls_list(priv);
8910 #endif
8911 woal_flush_mcast_list(priv);
8912 #ifdef STA_CFG80211
8913 if (priv->bss_type == MLAN_BSS_TYPE_STA &&
8914 IS_STA_CFG80211(cfg80211_wext)) {
8915 if (woal_flush_pmksa_list(priv))
8916 PRINTM(MERROR, "%s: woal_flush_pmksa_list failed!\n",
8917 __func__);
8918 if (priv->okc_roaming_ie) {
8919 kfree(priv->okc_roaming_ie);
8920 priv->okc_roaming_ie = NULL;
8921 priv->okc_ie_len = 0;
8922 }
8923 }
8924 #endif
8925 if (priv->bss_type == MLAN_BSS_TYPE_STA)
8926 woal_hist_data_reset(priv);
8927
8928 #ifdef STA_WEXT
8929 if (IS_STA_WEXT(cfg80211_wext)) {
8930 memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
8931 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
8932 wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
8933 }
8934 #endif
8935 #ifdef STA_CFG80211
8936 if (IS_STA_CFG80211(cfg80211_wext)) {
8937 spin_lock_irqsave(&priv->connect_lock, flags);
8938 if (!priv->cfg_disconnect && !priv->cfg_connect && priv->wdev &&
8939 #if ((CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) || IMX_ANDROID_13)
8940 priv->wdev->connected) {
8941 #else
8942 priv->wdev->current_bss) {
8943 #endif
8944 PRINTM(MMSG,
8945 "wlan: Disconnected from " MACSTR
8946 ": Reason code %d\n",
8947 MAC2STR(priv->cfg_bssid), reason_code);
8948 spin_unlock_irqrestore(&priv->connect_lock, flags);
8949 priv->cfg_disconnect = MTRUE;
8950 /* This function must be called only when
8951 disconnect issued by the FW, i.e.
8952 disconnected by AP. For IBSS mode this call
8953 is not valid */
8954 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
8955 if (priv->host_mlme)
8956 woal_host_mlme_disconnect(priv, reason_code,
8957 NULL);
8958 else
8959 #endif
8960 cfg80211_disconnected(priv->netdev, reason_code,
8961 NULL, 0,
8962 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
8963 false,
8964 #endif
8965 GFP_KERNEL);
8966 } else {
8967 spin_unlock_irqrestore(&priv->connect_lock, flags);
8968 }
8969 if (!woal_is_any_interface_active(priv->phandle)) {
8970 if (MLAN_STATUS_SUCCESS !=
8971 woal_set_scan_time(priv, ACTIVE_SCAN_CHAN_TIME,
8972 PASSIVE_SCAN_CHAN_TIME,
8973 SPECIFIC_SCAN_CHAN_TIME))
8974 PRINTM(MERROR, "%s: set scan time failed \n",
8975 __func__);
8976 }
8977 priv->ft_ie_len = 0;
8978 priv->ft_pre_connect = MFALSE;
8979 priv->ft_md = 0;
8980 priv->ft_cap = 0;
8981 memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map));
8982 }
8983 #endif /* STA_CFG80211 */
8984
8985 memset(event_buf, 0, sizeof(event_buf));
8986 custom_len = strlen(CUS_EVT_AP_CONNECTED);
8987 memcpy(event_buf, CUS_EVT_AP_CONNECTED,
8988 MIN((int)(sizeof(event_buf) - 1), custom_len));
8989 if (MLAN_STATUS_SUCCESS !=
8990 woal_broadcast_event(priv, event_buf, custom_len + ETH_ALEN))
8991 PRINTM(MINFO, "%s: woal_broadcast_event failed!\n", __func__);
8992 LEAVE();
8993 }
8994 #endif /* STA_SUPPORT */
8995
8996 #define OFFSET_SEQNUM 4
8997 #define OFFSET_TYPE 8
8998 #define DUMP_TYPE_ENDE 2
8999 /**
9000 * @brief This function stores the FW dumps received from events
9001 *
9002 * @param phandle A pointer to moal_handle
9003 * @param pmevent A pointer to mlan_event structure
9004 *
9005 * @return N/A
9006 */
9007 t_void woal_store_firmware_dump(moal_handle *phandle, mlan_event *pmevent)
9008 {
9009 int ret = 0;
9010 t_u16 seqnum;
9011 t_u16 type = 0;
9012 t_u8 *pos;
9013
9014 ENTER();
9015
9016 if (!phandle || !pmevent) {
9017 PRINTM(MERROR, "Could not dump firmware info\n");
9018 LEAVE();
9019 return;
9020 }
9021 seqnum = woal_le16_to_cpu(
9022 *(t_u16 *)(pmevent->event_buf + OFFSET_SEQNUM));
9023 type = woal_le16_to_cpu(*(t_u16 *)(pmevent->event_buf + OFFSET_TYPE));
9024
9025 if (seqnum == 1) {
9026 #ifdef DEBUG_LEVEL1
9027 if (drvdbg & MFW_D)
9028 phandle->fw_dump_status = MTRUE;
9029 #endif
9030 if (phandle->fw_dump == MFALSE) {
9031 PRINTM(MMSG, "=====FW trigger dump====\n");
9032 phandle->fw_dump = MTRUE;
9033 phandle->is_fw_dump_timer_set = MTRUE;
9034 woal_mod_timer(&phandle->fw_dump_timer, MOAL_TIMER_5S);
9035 }
9036
9037 if (!phandle->fw_dump_buf) {
9038 ret = moal_vmalloc(phandle, FW_DUMP_INFO_LEN,
9039 &phandle->fw_dump_buf);
9040 if (ret != MLAN_STATUS_SUCCESS ||
9041 !phandle->fw_dump_buf) {
9042 PRINTM(MERROR,
9043 "Failed to vmalloc fw dump buffer\n");
9044 LEAVE();
9045 return;
9046 }
9047 } else {
9048 memset(phandle->fw_dump_buf, 0x00, FW_DUMP_INFO_LEN);
9049 }
9050 phandle->fw_dump_len = 0;
9051 PRINTM(MMSG, "==== Start Receive FW dump event ====\n");
9052 } else {
9053 if (!phandle->fw_dump_buf || !phandle->fw_dump_len) {
9054 PRINTM(MERROR,
9055 "Error! Fw dump buffer is null or dump len is zero\n");
9056 LEAVE();
9057 return;
9058 }
9059 }
9060 pos = phandle->fw_dump_buf + phandle->fw_dump_len;
9061 moal_memcpy_ext(phandle, pos, pmevent->event_buf + OFFSET_SEQNUM,
9062 pmevent->event_len - OFFSET_SEQNUM,
9063 FW_DUMP_INFO_LEN - phandle->fw_dump_len);
9064 phandle->fw_dump_len += pmevent->event_len - OFFSET_SEQNUM;
9065
9066 PRINTM(MINFO, "fw dump event: evt_len=%d toal_len=%ld\n",
9067 pmevent->event_len, (long int)phandle->fw_dump_len);
9068 if (type == DUMP_TYPE_ENDE) {
9069 PRINTM(MMSG, "==== FW DUMP END: %ld bytes ====\n",
9070 (long int)phandle->fw_dump_len);
9071 woal_append_end_block(phandle);
9072 phandle->fw_dump = MFALSE;
9073 if (phandle->is_fw_dump_timer_set) {
9074 woal_cancel_timer(&phandle->fw_dump_timer);
9075 phandle->is_fw_dump_timer_set = MFALSE;
9076 }
9077 if (phandle->priv_num) {
9078 woal_send_fw_dump_complete_event(
9079 woal_get_priv(phandle, MLAN_BSS_ROLE_ANY));
9080 mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE);
9081 woal_process_hang(phandle);
9082 }
9083 }
9084
9085 LEAVE();
9086 return;
9087 }
9088
9089 #define DRV_INFO_SIZE 0x60000
9090 #define DRV_INFO_PER_INTF 0x11000
9091 #define ROW_SIZE_16 16
9092 #define ROW_SIZE_32 32
9093
9094 /**
9095 * @brief This function dump hex to file
9096 *
9097 * @param phandle A pointer to moal_handle
9098 * @param buf A pointer to buffer to dump
9099 * @param len lengh of buf
9100 * @param ascii Whether add ascii at the end
9101 * @param save_buf Buffer which is saved to
9102 *
9103 * @return The length of this log
9104 */
9105 static int woal_save_hex_dump(int rowsize, const void *buf, size_t len,
9106 bool ascii, t_u8 *save_buf)
9107 {
9108 const u8 *ptr = buf;
9109 int i, linelen, remaining = len;
9110 unsigned char linebuf[ROW_SIZE_32 * 3 + 2 + ROW_SIZE_32 + 1];
9111 char *pos = (char *)save_buf;
9112
9113 if (rowsize != ROW_SIZE_16 && rowsize != ROW_SIZE_32)
9114 rowsize = ROW_SIZE_16;
9115
9116 for (i = 0; i < (int)len; i += rowsize) {
9117 linelen = min(remaining, rowsize);
9118 remaining -= rowsize;
9119
9120 hex_dump_to_buffer(ptr + i, linelen, rowsize, 1, linebuf,
9121 sizeof(linebuf), false);
9122
9123 pos += sprintf(pos, "%s\n", linebuf);
9124 }
9125
9126 return pos - (char *)save_buf;
9127 }
9128
9129 /**
9130 * @brief This function save moal_priv's debug log
9131 *
9132 * @param phandle A pointer to moal_handle
9133 * @param buf A pointer buffer saving log
9134 *
9135 * @return The length of this log
9136 */
9137 static int woal_dump_priv_drv_info(moal_handle *handle, t_u8 *buf)
9138 {
9139 char *ptr = (char *)buf;
9140 int index;
9141 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
9142 int i = 0;
9143 #endif
9144 moal_private *priv;
9145
9146 ENTER();
9147 if (!handle || !buf) {
9148 PRINTM(MMSG, "%s: can't retreive info\n", __func__);
9149 LEAVE();
9150 return 0;
9151 }
9152 for (index = 0; index < MIN(handle->priv_num, MLAN_MAX_BSS_NUM);
9153 index++) {
9154 priv = handle->priv[index];
9155 if (priv) {
9156 ptr += sprintf(ptr, "[Interface : %s]\n",
9157 priv->proc_entry_name);
9158 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
9159 ptr += sprintf(ptr, "wmm_tx_pending[0] = %d\n",
9160 atomic_read(&priv->wmm_tx_pending[0]));
9161 ptr += sprintf(ptr, "wmm_tx_pending[1] = %d\n",
9162 atomic_read(&priv->wmm_tx_pending[1]));
9163 ptr += sprintf(ptr, "wmm_tx_pending[2] = %d\n",
9164 atomic_read(&priv->wmm_tx_pending[2]));
9165 ptr += sprintf(ptr, "wmm_tx_pending[3] = %d\n",
9166 atomic_read(&priv->wmm_tx_pending[3]));
9167 #endif
9168 ptr += sprintf(ptr, "Media state = \"%s\"\n",
9169 ((priv->media_connected == MFALSE) ?
9170 "Disconnected" :
9171 "Connected"));
9172 ptr += sprintf(ptr, "carrier %s\n",
9173 ((netif_carrier_ok(priv->netdev)) ?
9174 "on" :
9175 "off"));
9176 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
9177 for (i = 0; i < (int)(priv->netdev->num_tx_queues);
9178 i++) {
9179 ptr += sprintf(
9180 ptr, "tx queue %d: %s\n", i,
9181 ((netif_tx_queue_stopped(
9182 netdev_get_tx_queue(
9183 priv->netdev, i))) ?
9184 "stopped" :
9185 "started"));
9186 }
9187 #else
9188 ptr += sprintf(ptr, "tx queue %s\n",
9189 ((netif_queue_stopped(priv->netdev)) ?
9190 "stopped" :
9191 "started"));
9192 #endif
9193 ptr += sprintf(ptr, "%s: num_tx_timeout = %d\n",
9194 priv->netdev->name,
9195 priv->num_tx_timeout);
9196 }
9197 }
9198
9199 LEAVE();
9200 return ptr - (char *)buf;
9201 }
9202
9203 /**
9204 * @brief This function save moal_handle's info
9205 *
9206 * @param phandle A pointer to moal_handle
9207 * @param buf A pointer buffer saving log
9208 *
9209 * @return The length of this log
9210 */
9211 static int woal_dump_moal_drv_info(moal_handle *phandle, t_u8 *buf)
9212 {
9213 char *ptr;
9214 #ifdef USB
9215 struct usb_card_rec *cardp = NULL;
9216 #endif
9217 char str_buf[MLAN_MAX_VER_STR_LEN];
9218
9219 ENTER();
9220 if (!phandle || !buf) {
9221 PRINTM(MMSG, "%s: can't retreive info\n", __func__);
9222 LEAVE();
9223 return 0;
9224 }
9225 #ifdef USB
9226 if (IS_USB(phandle->card_type))
9227 cardp = (struct usb_card_rec *)phandle->card;
9228 #endif
9229 ptr = (char *)buf;
9230 ptr += sprintf(ptr, "------------moal_debug_info-------------\n");
9231 woal_get_version(phandle, str_buf, sizeof(str_buf) - 1);
9232 ptr += sprintf(ptr, "Driver version = %s\n", str_buf);
9233 ptr += sprintf(ptr, "main_state = %d\n", phandle->main_state);
9234 #ifdef USB
9235 if (IS_USB(phandle->card_type)) {
9236 ptr += sprintf(ptr, "tx_cmd_urb_pending = %d\n",
9237 atomic_read(&cardp->tx_cmd_urb_pending));
9238 ptr += sprintf(ptr, "tx_data_urb_pending = %d\n",
9239 atomic_read(&cardp->tx_data_urb_pending));
9240 #ifdef USB_CMD_DATA_EP
9241 ptr += sprintf(ptr, "rx_cmd_urb_pending = %d\n",
9242 atomic_read(&cardp->rx_cmd_urb_pending));
9243 #endif
9244 ptr += sprintf(ptr, "rx_data_urb_pending = %d\n",
9245 atomic_read(&cardp->rx_data_urb_pending));
9246 }
9247 #endif
9248 ptr += sprintf(ptr, "ioctl_pending = %d\n",
9249 atomic_read(&phandle->ioctl_pending));
9250 ptr += sprintf(ptr, "tx_pending = %d\n",
9251 atomic_read(&phandle->tx_pending));
9252 ptr += sprintf(ptr, "rx_pending = %d\n",
9253 atomic_read(&phandle->rx_pending));
9254 ptr += sprintf(ptr, "lock_count = %d\n",
9255 atomic_read(&phandle->lock_count));
9256 ptr += sprintf(ptr, "malloc_count = %d\n",
9257 atomic_read(&phandle->malloc_count));
9258 ptr += sprintf(ptr, "mbufalloc_count = %d\n",
9259 atomic_read(&phandle->mbufalloc_count));
9260 #ifdef PCIE
9261 if (IS_PCIE(phandle->card_type)) {
9262 ptr += sprintf(ptr, "malloc_cons_count = %d\n",
9263 atomic_read(&phandle->malloc_cons_count));
9264 }
9265 #endif
9266 ptr += sprintf(ptr, "hs_skip_count = %u\n", phandle->hs_skip_count);
9267 ptr += sprintf(ptr, "hs_force_count = %u\n", phandle->hs_force_count);
9268
9269 ptr += woal_dump_priv_drv_info(phandle, ptr);
9270 ptr += sprintf(ptr, "------------moal_debug_info End-------------\n");
9271
9272 if (phandle->ops.dump_reg_info)
9273 ptr += phandle->ops.dump_reg_info(phandle, ptr);
9274
9275 LEAVE();
9276 return ptr - (char *)buf;
9277 }
9278
9279 /**
9280 * @brief This function save mlan's info
9281 *
9282 * @param phandle A pointer to moal_handle
9283 * @param buf A pointer buffer saving log
9284 *
9285 * @return The length of this log
9286 */
9287 static int woal_dump_mlan_drv_info(moal_private *priv, t_u8 *buf)
9288 {
9289 char *ptr = (char *)buf;
9290 int i;
9291 #ifdef SDIO
9292 int j;
9293 t_u8 mp_aggr_pkt_limit = 0;
9294 #endif
9295 char str[11 * DBG_CMD_NUM + 1] = {0};
9296 char *s;
9297 mlan_debug_info *info = NULL;
9298
9299 ENTER();
9300 if (!priv || !priv->phandle) {
9301 PRINTM(MERROR, "priv or priv->phandle is null\n");
9302 LEAVE();
9303 return 0;
9304 }
9305 info = &(priv->phandle->debug_info);
9306 if (woal_get_debug_info(priv, MOAL_IOCTL_WAIT, info)) {
9307 PRINTM(MERROR,
9308 "Could not retrieve debug information from MLAN\n");
9309 LEAVE();
9310 return 0;
9311 }
9312 ptr += sprintf(ptr, "------------mlan_debug_info-------------\n");
9313 ptr += sprintf(ptr, "mlan_processing =%d\n", info->mlan_processing);
9314 ptr += sprintf(ptr, "main_lock_flag =%d\n", info->main_lock_flag);
9315 ptr += sprintf(ptr, "main_process_cnt =%d\n", info->main_process_cnt);
9316 ptr += sprintf(ptr, "delay_task_flag =%d\n", info->delay_task_flag);
9317 ptr += sprintf(ptr, "mlan_rx_processing =%d\n",
9318 info->mlan_rx_processing);
9319 ptr += sprintf(ptr, "rx_pkts_queued =%d\n", info->rx_pkts_queued);
9320 ptr += sprintf(ptr, "tx_pkts_queued =%d\n", info->tx_pkts_queued);
9321 ptr += sprintf(ptr, "fw_hang_report = %d\n", info->fw_hang_report);
9322 ptr += sprintf(ptr, "num_cmd_timeout = %d\n", info->num_cmd_timeout);
9323 ptr += sprintf(ptr, "Timeout cmd id = 0x%x, act = 0x%x\n",
9324 info->timeout_cmd_id, info->timeout_cmd_act);
9325 ptr += sprintf(ptr, "last_cmd_index = %d\n", info->last_cmd_index);
9326 for (s = str, i = 0; i < DBG_CMD_NUM; i++)
9327 s += sprintf(s, "0x%x ", info->last_cmd_id[i]);
9328 ptr += sprintf(ptr, "last_cmd_id = %s\n", str);
9329
9330 for (s = str, i = 0; i < DBG_CMD_NUM; i++)
9331 s += sprintf(s, "0x%x ", info->last_cmd_act[i]);
9332
9333 ptr += sprintf(ptr, "last_cmd_act = %s\n", str);
9334 ptr += sprintf(ptr, "last_cmd_resp_index = %d\n",
9335 info->last_cmd_resp_index);
9336 for (s = str, i = 0; i < DBG_CMD_NUM; i++)
9337 s += sprintf(s, "0x%x ", info->last_cmd_resp_id[i]);
9338
9339 ptr += sprintf(ptr, "last_cmd_resp_id = %s\n", str);
9340 ptr += sprintf(ptr, "last_event_index = %d\n", info->last_event_index);
9341 for (s = str, i = 0; i < DBG_CMD_NUM; i++)
9342 s += sprintf(s, "0x%x ", info->last_event[i]);
9343
9344 ptr += sprintf(ptr, "last_event = %s\n", str);
9345 ptr += sprintf(ptr, "num_data_h2c_failure = %d\n",
9346 info->num_tx_host_to_card_failure);
9347 ptr += sprintf(ptr, "num_cmd_h2c_failure = %d\n",
9348 info->num_cmd_host_to_card_failure);
9349 ptr += sprintf(ptr, "num_alloc_buffer_failure = %d\n",
9350 info->num_alloc_buffer_failure);
9351 ptr += sprintf(ptr, "num_pkt_dropped = %d\n", info->num_pkt_dropped);
9352 #ifdef SDIO
9353 if (IS_SD(priv->phandle->card_type)) {
9354 ptr += sprintf(ptr, "num_data_c2h_failure = %d\n",
9355 info->num_rx_card_to_host_failure);
9356 ptr += sprintf(ptr, "num_cmdevt_c2h_failure = %d\n",
9357 info->num_cmdevt_card_to_host_failure);
9358 ptr += sprintf(ptr, "num_int_read_failure = %d\n",
9359 info->num_int_read_failure);
9360 ptr += sprintf(ptr, "last_int_status = %d\n",
9361 info->last_int_status);
9362 ptr += sprintf(ptr, "mp_rd_bitmap=0x%x curr_rd_port=0x%x\n",
9363 (unsigned int)info->mp_rd_bitmap,
9364 info->curr_rd_port);
9365 ptr += sprintf(ptr, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n",
9366 (unsigned int)info->mp_wr_bitmap,
9367 info->curr_wr_port);
9368 ptr += sprintf(ptr, "mp_data_port_mask=0x%x\n",
9369 info->mp_data_port_mask);
9370 ptr += sprintf(
9371 ptr, "last_recv_rd_bitmap=0x%x mp_invalid_update=%d\n",
9372 info->last_recv_rd_bitmap, info->mp_invalid_update);
9373 mp_aggr_pkt_limit = info->mp_aggr_pkt_limit;
9374 ptr += sprintf(ptr,
9375 "last_recv_wr_bitmap=0x%x last_mp_index = %d\n",
9376 info->last_recv_wr_bitmap, info->last_mp_index);
9377 for (i = 0; i < SDIO_MP_DBG_NUM; i++) {
9378 for (s = str, j = 0; j < mp_aggr_pkt_limit; j++)
9379 s += sprintf(
9380 s, "0x%02x ",
9381 info->last_mp_wr_info
9382 [i * mp_aggr_pkt_limit + j]);
9383
9384 ptr += sprintf(
9385 ptr,
9386 "mp_wr_bitmap: 0x%x mp_wr_ports=0x%x len=%d curr_wr_port=0x%x\n%s\n",
9387 info->last_mp_wr_bitmap[i],
9388 info->last_mp_wr_ports[i],
9389 info->last_mp_wr_len[i],
9390 info->last_curr_wr_port[i], str);
9391 }
9392 }
9393 #endif
9394 #ifdef PCIE
9395 if (IS_PCIE(priv->phandle->card_type)) {
9396 ptr += sprintf(ptr, "txbd_rdptr=0x%x txbd_wrptr=0x%x\n",
9397 info->txbd_rdptr, info->txbd_wrptr);
9398 ptr += sprintf(ptr, "rxbd_rdptr=0x%x rxbd_wrptr=0x%x\n",
9399 info->rxbd_rdptr, info->rxbd_wrptr);
9400 ptr += sprintf(ptr, "eventbd_rdptr=0x%x event_wrptr=0x%x\n",
9401 info->eventbd_rdptr, info->eventbd_wrptr);
9402 ptr += sprintf(ptr, "last_wr_index:%d\n",
9403 info->txbd_wrptr & (info->txrx_bd_size - 1));
9404 ptr += sprintf(ptr, "TxRx BD size:%d\n", info->txrx_bd_size);
9405 }
9406 #endif
9407 ptr += sprintf(ptr, "num_event_deauth = %d\n", info->num_event_deauth);
9408 ptr += sprintf(ptr, "num_event_disassoc = %d\n",
9409 info->num_event_disassoc);
9410 ptr += sprintf(ptr, "num_event_link_lost = %d\n",
9411 info->num_event_link_lost);
9412 ptr += sprintf(ptr, "num_cmd_deauth = %d\n", info->num_cmd_deauth);
9413 ptr += sprintf(ptr, "num_cmd_assoc_success = %d\n",
9414 info->num_cmd_assoc_success);
9415 ptr += sprintf(ptr, "num_cmd_assoc_failure = %d\n",
9416 info->num_cmd_assoc_failure);
9417 ptr += sprintf(ptr, "num_cons_assoc_failure = %d\n",
9418 info->num_cons_assoc_failure);
9419 ptr += sprintf(ptr, "cmd_resp_received = %d\n",
9420 info->cmd_resp_received);
9421 ptr += sprintf(ptr, "event_received = %d\n", info->event_received);
9422 ptr += sprintf(ptr, "max_tx_buf_size = %d\n", info->max_tx_buf_size);
9423 ptr += sprintf(ptr, "tx_buf_size = %d\n", info->tx_buf_size);
9424 ptr += sprintf(ptr, "curr_tx_buf_size = %d\n", info->curr_tx_buf_size);
9425 ptr += sprintf(ptr, "bypass_pkt_count=%d\n", info->bypass_pkt_count);
9426
9427 ptr += sprintf(ptr, "data_sent=%d cmd_sent=%d\n", info->data_sent,
9428 info->cmd_sent);
9429 ptr += sprintf(ptr, "data_sent_cnt=%u\n", info->data_sent_cnt);
9430 ptr += sprintf(ptr, "ps_mode=%d ps_state=%d\n", info->ps_mode,
9431 info->ps_state);
9432 ptr += sprintf(
9433 ptr, "wakeup_dev_req=%d wakeup_tries=%d pm_wakeup_timeout=%d\n",
9434 info->pm_wakeup_card_req, info->pm_wakeup_fw_try,
9435 info->pm_wakeup_timeout);
9436 ptr += sprintf(ptr, "hs_configured=%d hs_activated=%d\n",
9437 info->is_hs_configured, info->hs_activated);
9438 ptr += sprintf(ptr, "pps_uapsd_mode=%d sleep_pd=%d\n",
9439 info->pps_uapsd_mode, info->sleep_pd);
9440 ptr += sprintf(ptr, "tx_lock_flag = %d\n", info->tx_lock_flag);
9441 ptr += sprintf(ptr, "port_open = %d\n", info->port_open);
9442 ptr += sprintf(ptr, "scan_processing = %d\n", info->scan_processing);
9443 ptr += sprintf(ptr, "scan_state = %d\n", info->scan_state);
9444
9445 #ifdef PCIE
9446 if (IS_PCIE(priv->phandle->card_type)) {
9447 ptr += sprintf(ptr, "txbd: rdptr=0x%x wrptr=0x%x\n",
9448 info->txbd_rdptr, info->txbd_wrptr);
9449 ptr += sprintf(ptr, "rxbd: rdptr=0x%x wrptr=0x%x\n",
9450 info->rxbd_rdptr, info->rxbd_wrptr);
9451 ptr += sprintf(ptr, "eventbd: rdptr=0x%x wrptr=0x%x\n",
9452 info->eventbd_rdptr, info->eventbd_wrptr);
9453 ptr += sprintf(ptr, "TXBD Ring:\n");
9454 ptr += woal_save_hex_dump(ROW_SIZE_16, info->txbd_ring_vbase,
9455 info->txbd_ring_size, MTRUE, ptr);
9456 ptr += sprintf(ptr, "RXBD Ring:\n");
9457 ptr += woal_save_hex_dump(ROW_SIZE_16, info->rxbd_ring_vbase,
9458 info->rxbd_ring_size, MTRUE, ptr);
9459 ptr += sprintf(ptr, "EVTBD Ring:\n");
9460 ptr += woal_save_hex_dump(ROW_SIZE_16, info->evtbd_ring_vbase,
9461 info->evtbd_ring_size, MTRUE, ptr);
9462 }
9463 #endif
9464 ptr += sprintf(ptr, "------------mlan_debug_info End-------------\n");
9465
9466 LEAVE();
9467 return ptr - (char *)buf;
9468 }
9469
9470 /**
9471 * @brief This function dump moal hex to file
9472 *
9473 * @param phandle A pointer to moal_handle
9474 * @param buf A pointer to buffer
9475 *
9476 * @return The length of this log
9477 */
9478 static int woal_dump_moal_hex(moal_handle *phandle, t_u8 *buf)
9479 {
9480 char *ptr = (char *)buf;
9481 int i;
9482 ENTER();
9483
9484 if (!phandle || !buf) {
9485 PRINTM(MMSG, "%s: can't retreive info\n", __func__);
9486 LEAVE();
9487 return 0;
9488 }
9489
9490 ptr += sprintf(ptr, "<--moal_handle-->\n");
9491 ptr += sprintf(ptr, "moal_handle=%p, size=%ld(0x%lx)\n", phandle,
9492 (long int)sizeof(*phandle),
9493 (long unsigned int)sizeof(*phandle));
9494 ptr += woal_save_hex_dump(ROW_SIZE_16, phandle, sizeof(*phandle), MTRUE,
9495 ptr);
9496 ptr += sprintf(ptr, "<--moal_handle End-->\n");
9497
9498 for (i = 0; i < phandle->priv_num; i++) {
9499 if (!phandle->priv[i])
9500 continue;
9501 ptr += sprintf(ptr, "<--moal_private(%d) %s-->\n", i,
9502 phandle->priv[i]->netdev->name);
9503 ptr += sprintf(ptr, "moal_private=%p, size=%ld(0x%lx)\n",
9504 phandle->priv[i],
9505 (long int)sizeof(*(phandle->priv[i])),
9506 (long unsigned int)sizeof(*(phandle->priv[i])));
9507 ptr += woal_save_hex_dump(ROW_SIZE_16, phandle->priv[i],
9508 sizeof(*(phandle->priv[i])), MTRUE,
9509 ptr);
9510 ptr += sprintf(ptr, "<--moal_private(%d) End-->\n", i);
9511 }
9512 LEAVE();
9513 return ptr - (char *)buf;
9514 }
9515
9516 /**
9517 * @brief This function dump mlan hex to file
9518 *
9519 * @param priv A pointer to moal_private structure
9520 * @param buf A pointer to buffer
9521 *
9522 * @return The length of this log
9523 */
9524 static int woal_dump_mlan_hex(moal_private *priv, t_u8 *buf)
9525 {
9526 char *ptr = (char *)buf;
9527 int i;
9528 mlan_debug_info *info = NULL;
9529
9530 ENTER();
9531
9532 if (!buf || !priv || !priv->phandle) {
9533 PRINTM(MERROR, "buf priv or priv->phandle is null\n");
9534 LEAVE();
9535 return 0;
9536 }
9537 info = &(priv->phandle->debug_info);
9538 if (woal_get_debug_info(priv, MOAL_IOCTL_WAIT, info)) {
9539 PRINTM(MMSG, "%s: can't retreive info\n", __func__);
9540 LEAVE();
9541 return 0;
9542 }
9543
9544 ptr += sprintf(ptr, "<--mlan_adapter-->\n");
9545 ptr += sprintf(ptr, "mlan_adapter=%p, size=%d(0x%x)\n",
9546 info->mlan_adapter, info->mlan_adapter_size,
9547 info->mlan_adapter_size);
9548 ptr += woal_save_hex_dump(ROW_SIZE_16, info->mlan_adapter,
9549 info->mlan_adapter_size, MTRUE, ptr);
9550 ptr += sprintf(ptr, "<--mlan_adapter End-->\n");
9551 #ifdef SDIO
9552 if (IS_SD(priv->phandle->card_type) && info->mpa_buf &&
9553 info->mpa_buf_size) {
9554 ptr += sprintf(ptr, "<--mlan_mpa_buf-->\n");
9555 ptr += sprintf(ptr, "mlan_mpa_buf=%p, size=%d(0x%x)\n",
9556 info->mpa_buf, info->mpa_buf_size,
9557 info->mpa_buf_size);
9558 ptr += woal_save_hex_dump(ROW_SIZE_16, info->mpa_buf,
9559 info->mpa_buf_size, MTRUE, ptr);
9560 ptr += sprintf(ptr, "<--mlan_mpa_buf End-->\n");
9561 }
9562 #endif
9563 for (i = 0; i < info->mlan_priv_num; i++) {
9564 ptr += sprintf(ptr, "<--mlan_private(%d)-->\n", i);
9565 ptr += sprintf(ptr, "mlan_private=%p, size=%d(0x%x)\n",
9566 info->mlan_priv[i], info->mlan_priv_size[i],
9567 info->mlan_priv_size[i]);
9568 ptr += woal_save_hex_dump(ROW_SIZE_16, info->mlan_priv[i],
9569 info->mlan_priv_size[i], MTRUE, ptr);
9570 ptr += sprintf(ptr, "<--mlan_private(%d) End-->\n", i);
9571 }
9572
9573 LEAVE();
9574 return ptr - (char *)buf;
9575 }
9576
9577 /**
9578 * @brief This function dump drv info to file
9579 *
9580 * @param phandle A pointer to moal_handle
9581 * @param dump_len A point to hold the len of drv info memory
9582 *
9583 * @return A pointer to drv_info memory
9584 */
9585 t_u8 *woal_dump_drv_info(moal_handle *phandle, t_u32 *dump_len)
9586 {
9587 t_u8 *drv_buf = NULL;
9588 t_u32 len = 0;
9589 t_u32 total_len = 0;
9590 t_u32 drv_info_size = DRV_INFO_SIZE;
9591 int ret;
9592 if (!phandle->priv_num)
9593 return NULL;
9594 if (phandle->priv_num > 3)
9595 drv_info_size += (phandle->priv_num - 3) * DRV_INFO_PER_INTF;
9596 PRINTM(MERROR, "=== START DRIVER INFO DUMP===");
9597 ret = moal_vmalloc(phandle, drv_info_size, &drv_buf);
9598 if ((ret != MLAN_STATUS_SUCCESS) || !drv_buf) {
9599 PRINTM(MERROR, "Error: vmalloc drv buffer failed!\n");
9600 goto done;
9601 }
9602
9603 len = woal_dump_moal_drv_info(phandle, drv_buf);
9604 total_len += len;
9605 len = woal_dump_mlan_drv_info(woal_get_priv(phandle, MLAN_BSS_ROLE_ANY),
9606 drv_buf + total_len);
9607 total_len += len;
9608 len = woal_dump_moal_hex(phandle, drv_buf + total_len);
9609 total_len += len;
9610 len = woal_dump_mlan_hex(woal_get_priv(phandle, MLAN_BSS_ROLE_ANY),
9611 drv_buf + total_len);
9612 total_len += len;
9613
9614 PRINTM(MERROR, "Drv info total bytes = %ld (0x%lx)\n",
9615 (long int)total_len, (long unsigned int)total_len);
9616 PRINTM(MERROR, "=== DRIVER INFO DUMP END===");
9617 *dump_len = total_len;
9618 done:
9619 return drv_buf;
9620 }
9621
9622 /**
9623 * @brief This function adds header and copy the src data to buf
9624 *
9625 * @param phandle A pointer to moal_handle
9626 * @param src A ponter to source buffer
9627 * @param len Length of raw data
9628 * @param type Dump type
9629 *
9630 * return Total len of buf
9631 */
9632 int woal_save_dump_info_to_buf(moal_handle *phandle, t_u8 *src, t_u32 len,
9633 t_u32 type)
9634 {
9635 mem_dump_header header;
9636 t_u32 left_len = 0;
9637 t_u32 len_to_copy = 0;
9638 int total_len = 0;
9639 t_u8 *dest = NULL;
9640 int count = 0;
9641 int pad = 0;
9642 dest = phandle->fw_dump_buf + phandle->fw_dump_len;
9643
9644 left_len = len;
9645 while (left_len) {
9646 header.type = type;
9647 if (left_len < 1024)
9648 len_to_copy = left_len;
9649 else
9650 len_to_copy = 1024;
9651 header.len = (t_u16)(len_to_copy + sizeof(t_u32));
9652 header.start_addr = count * 1024;
9653 moal_memcpy_ext(phandle, dest, &header, sizeof(mem_dump_header),
9654 FW_DUMP_INFO_LEN - phandle->fw_dump_len);
9655 dest += sizeof(mem_dump_header);
9656 moal_memcpy_ext(phandle, dest, src, len_to_copy,
9657 FW_DUMP_INFO_LEN - phandle->fw_dump_len -
9658 sizeof(mem_dump_header));
9659 dest += len_to_copy;
9660 src += len_to_copy;
9661 left_len -= len_to_copy;
9662 // 8 bytes align
9663 pad = (header.len & 7) ? (8 - (header.len & 7)) : 0;
9664 dest += pad;
9665 total_len += pad + len_to_copy + sizeof(mem_dump_header);
9666 count++;
9667 }
9668 phandle->fw_dump_len += total_len;
9669 PRINTM(MMSG, "type=%d, len=%d block=%d total=%d\n", type, len, count,
9670 total_len);
9671 return total_len;
9672 }
9673
9674 /**
9675 * @brief This function append end block to dump file
9676 *
9677 * @param phandle A pointer to moal_handle
9678 *
9679 * return N/A
9680 */
9681 void woal_append_end_block(moal_handle *phandle)
9682 {
9683 mem_dump_header header;
9684 t_u8 *pos = phandle->fw_dump_buf + phandle->fw_dump_len;
9685 ENTER();
9686 memset(&header, 0, sizeof(header));
9687 header.type = FW_DUMP_TYPE_ENDED;
9688 header.len = 0;
9689 moal_memcpy_ext(phandle, pos, &header, sizeof(mem_dump_header),
9690 FW_DUMP_INFO_LEN - phandle->fw_dump_len);
9691 phandle->fw_dump_len += sizeof(mem_dump_header);
9692 PRINTM(MMSG, "fw dump total length is %ld\n",
9693 (long int)phandle->fw_dump_len);
9694 LEAVE();
9695 return;
9696 }
9697
9698 /**
9699 * @brief This function displays extra MOAL debug information
9700 *
9701 * @param priv A pointer to moal_private
9702 * @param handle A pointer to moal_handle
9703 * @param flag Indicates whether register read can be done directly
9704 *
9705 * @return N/A
9706 */
9707 void woal_moal_debug_info(moal_private *priv, moal_handle *handle, u8 flag)
9708 {
9709 moal_handle *phandle = NULL;
9710 #ifdef USB
9711 struct usb_card_rec *cardp = NULL;
9712 #endif
9713 char buf[MLAN_MAX_VER_STR_LEN];
9714 int i = 0;
9715
9716 ENTER();
9717
9718 if (!priv) {
9719 if (handle) {
9720 phandle = handle;
9721 } else {
9722 PRINTM(MERROR,
9723 "Could not retrieve debug information from MOAL\n");
9724 LEAVE();
9725 return;
9726 }
9727 } else {
9728 phandle = priv->phandle;
9729 }
9730 #ifdef USB
9731 if (IS_USB(phandle->card_type)) {
9732 cardp = (struct usb_card_rec *)phandle->card;
9733 PRINTM(MERROR, "tx_cmd_urb_pending = %d\n",
9734 atomic_read(&cardp->tx_cmd_urb_pending));
9735 PRINTM(MERROR, "tx_data_urb_pending = %d\n",
9736 atomic_read(&cardp->tx_data_urb_pending));
9737 #ifdef USB_CMD_DATA_EP
9738 PRINTM(MERROR, "rx_cmd_urb_pending = %d\n",
9739 atomic_read(&cardp->rx_cmd_urb_pending));
9740 #endif
9741 PRINTM(MERROR, "rx_data_urb_pending = %d\n",
9742 atomic_read(&cardp->rx_data_urb_pending));
9743 }
9744 #endif
9745
9746 woal_get_version(phandle, buf, sizeof(buf) - 1);
9747 PRINTM(MERROR, "Driver version = %s\n", buf);
9748 PRINTM(MERROR, "main_state = %d\n", phandle->main_state);
9749 PRINTM(MERROR, "ioctl_pending = %d\n",
9750 atomic_read(&phandle->ioctl_pending));
9751 PRINTM(MERROR, "tx_pending = %d\n", atomic_read(&phandle->tx_pending));
9752 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
9753 if (priv) {
9754 PRINTM(MERROR, "wmm_tx_pending[0] = %d\n",
9755 atomic_read(&priv->wmm_tx_pending[0]));
9756 PRINTM(MERROR, "wmm_tx_pending[1] = %d\n",
9757 atomic_read(&priv->wmm_tx_pending[1]));
9758 PRINTM(MERROR, "wmm_tx_pending[2] = %d\n",
9759 atomic_read(&priv->wmm_tx_pending[2]));
9760 PRINTM(MERROR, "wmm_tx_pending[3] = %d\n",
9761 atomic_read(&priv->wmm_tx_pending[3]));
9762 }
9763 #endif
9764 PRINTM(MERROR, "rx_pending = %d\n", atomic_read(&phandle->rx_pending));
9765 PRINTM(MERROR, "lock_count = %d\n", atomic_read(&phandle->lock_count));
9766 PRINTM(MERROR, "malloc_count = %d\n",
9767 atomic_read(&phandle->malloc_count));
9768 PRINTM(MERROR, "mbufalloc_count = %d\n",
9769 atomic_read(&phandle->mbufalloc_count));
9770 #ifdef PCIE
9771 if (IS_PCIE(phandle->card_type)) {
9772 PRINTM(MERROR, "malloc_cons_count = %d\n",
9773 atomic_read(&phandle->malloc_cons_count));
9774 }
9775 #endif
9776 PRINTM(MERROR, "hs_skip_count = %u\n", phandle->hs_skip_count);
9777 PRINTM(MERROR, "hs_force_count = %u\n", phandle->hs_force_count);
9778
9779 if (priv && priv->netdev) {
9780 PRINTM(MERROR, "Media state = \"%s\"\n",
9781 ((priv->media_connected == MFALSE) ? "Disconnected" :
9782 "Connected"));
9783 PRINTM(MERROR, "carrier %s\n",
9784 ((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
9785 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
9786 for (i = 0; i < (int)(priv->netdev->num_tx_queues); i++) {
9787 PRINTM(MERROR, "tx queue %d: %s\n", i,
9788 ((netif_tx_queue_stopped(
9789 netdev_get_tx_queue(priv->netdev, i))) ?
9790 "stopped" :
9791 "started"));
9792 }
9793 #else
9794 PRINTM(MERROR, "tx queue %s\n",
9795 ((netif_queue_stopped(priv->netdev)) ? "stopped" :
9796 "started"));
9797 #endif
9798 }
9799
9800 for (i = 0; i < phandle->priv_num; i++) {
9801 priv = phandle->priv[i];
9802 if (priv && priv->netdev)
9803 PRINTM(MERROR, "%s: num_tx_timeout = %d\n",
9804 priv->netdev->name, priv->num_tx_timeout);
9805 }
9806
9807 if (phandle->is_suspended == MTRUE) {
9808 LEAVE();
9809 return;
9810 }
9811
9812 #ifdef PCIE
9813 if (IS_PCIE(phandle->card_type)) {
9814 #ifdef DEBUG_LEVEL1
9815 if (phandle->ops.reg_dbg && (drvdbg & (MREG_D | MFW_D))) {
9816 if (!phandle->event_fw_dump)
9817 phandle->ops.reg_dbg(phandle);
9818 }
9819 #endif
9820 }
9821 #endif
9822 #ifdef SDIO
9823 if (IS_SD(phandle->card_type)) {
9824 if (flag && ((phandle->main_state == MOAL_END_MAIN_PROCESS) ||
9825 (phandle->main_state == MOAL_STATE_IDLE))) {
9826 #ifdef DEBUG_LEVEL1
9827 if (phandle->ops.reg_dbg &&
9828 (drvdbg & (MREG_D | MFW_D))) {
9829 if (!phandle->event_fw_dump)
9830 phandle->ops.reg_dbg(phandle);
9831 }
9832 #endif
9833 } else {
9834 #ifdef DEBUG_LEVEL1
9835 if (drvdbg & (MREG_D | MFW_D)) {
9836 if (!phandle->event_fw_dump) {
9837 phandle->reg_dbg = MTRUE;
9838 queue_work(phandle->workqueue,
9839 &phandle->main_work);
9840 }
9841 }
9842 #endif
9843 }
9844 }
9845 #endif
9846 #ifdef DEBUG_LEVEL1
9847 if ((drvdbg & MFW_D) && !phandle->fw_dump_status) {
9848 phandle->fw_dump_status = MTRUE;
9849 phandle->fw_dbg = MTRUE;
9850 queue_work(phandle->workqueue, &phandle->main_work);
9851 }
9852 #endif
9853 LEAVE();
9854 return;
9855 }
9856
9857 /**
9858 * @brief Download power table to firmware for a specific country
9859 *
9860 * @param priv A pointer to moal_private
9861 * @param country ISO 3166-1 alpha-2 country code
9862 *
9863 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
9864 */
9865 mlan_status woal_request_country_power_table(moal_private *priv, char *country)
9866 {
9867 mlan_status ret = MLAN_STATUS_SUCCESS;
9868 moal_handle *handle = NULL;
9869 char country_name[128];
9870 char file_path[256];
9871 char *last_slash = NULL;
9872 char *fw_name = NULL;
9873
9874 ENTER();
9875
9876 if (!priv || !priv->phandle) {
9877 PRINTM(MERROR, "Priv or handle is null\n");
9878 LEAVE();
9879 return MLAN_STATUS_FAILURE;
9880 }
9881
9882 if (!country) {
9883 PRINTM(MERROR, "Country is null\n");
9884 LEAVE();
9885 return MLAN_STATUS_FAILURE;
9886 }
9887 handle = priv->phandle;
9888 memset(country_name, 0, sizeof(country_name));
9889 if (handle->params.hw_name)
9890 sprintf(country_name, "%s_txpower_XX.bin",
9891 handle->params.hw_name);
9892 else
9893 memcpy(country_name, "txpower_XX.bin",
9894 strlen("txpower_XX.bin"));
9895 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
9896 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
9897 if (handle->params.cntry_txpwr == CNTRY_RGPOWER_MODE) {
9898 memset(country_name, 0, sizeof(country_name));
9899 if (handle->params.hw_name)
9900 sprintf(country_name, "%s_rgpower_XX.bin",
9901 handle->params.hw_name);
9902 else
9903 memcpy(country_name, "rgpower_XX.bin",
9904 strlen("rgpower_XX.bin"));
9905 }
9906 #endif
9907 #endif
9908
9909 /* Replace XX with ISO 3166-1 alpha-2 country code */
9910 memcpy(strstr(country_name, "XX"), country, strlen(country));
9911 fw_name = handle->params.fw_name;
9912 memset(file_path, 0, sizeof(file_path));
9913 /* file_path should be Null terminated */
9914 if (fw_name) {
9915 moal_memcpy(handle, file_path, fw_name, sizeof(file_path) - 1);
9916 last_slash = strrchr(file_path, '/');
9917 if (last_slash)
9918 memset(last_slash + 1, 0,
9919 sizeof(file_path) - 1 -
9920 (last_slash - file_path));
9921 else
9922 memset(file_path, 0, sizeof(file_path));
9923 } else {
9924 memcpy(file_path, "nxp/",
9925 MIN((sizeof(file_path) - 1), strlen("nxp/")));
9926 }
9927
9928 if ((strlen(file_path) + strlen(country_name)) <
9929 (sizeof(file_path) - 1))
9930 strncpy(file_path + strlen(file_path), country_name,
9931 sizeof(file_path) - strlen(file_path) - 1);
9932 else {
9933 PRINTM(MERROR,
9934 "file path buffer too small, fail to dnld power table\n");
9935 LEAVE();
9936 return MLAN_STATUS_FAILURE;
9937 }
9938
9939 PRINTM(MMSG, "Trying download country_power_tble: %s\n", file_path);
9940 ret = woal_set_user_init_data(handle, COUNTRY_POWER_TABLE,
9941 MOAL_IOCTL_WAIT, file_path);
9942 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
9943 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
9944 /* Try download WW rgpowertable */
9945 if ((handle->params.cntry_txpwr == CNTRY_RGPOWER_MODE) &&
9946 (ret == MLAN_STATUS_FILE_ERR)) {
9947 memset(country_name, 0, sizeof(country_name));
9948 if (handle->params.hw_name)
9949 sprintf(country_name, "%s_rgpower_WW.bin",
9950 handle->params.hw_name);
9951 else
9952 memcpy(country_name, "rgpower_WW.bin",
9953 strlen("rgpower_WW.bin"));
9954 last_slash = strrchr(file_path, '/');
9955 if (last_slash)
9956 memset(last_slash + 1, 0,
9957 sizeof(file_path) - 1 -
9958 (last_slash - file_path));
9959 else
9960 memset(file_path, 0, sizeof(file_path));
9961 if ((strlen(file_path) + strlen(country_name)) <
9962 (sizeof(file_path) - 1))
9963 strncpy(file_path + strlen(file_path), country_name,
9964 sizeof(file_path) - strlen(file_path) - 1);
9965 else {
9966 PRINTM(MERROR,
9967 "file path buffer too small, fail to dnld power table\n");
9968 LEAVE();
9969 return MLAN_STATUS_FAILURE;
9970 }
9971 PRINTM(MMSG, "Trying again download country_power_tble: %s\n",
9972 file_path);
9973 ret = woal_set_user_init_data(handle, COUNTRY_POWER_TABLE,
9974 MOAL_IOCTL_WAIT, file_path);
9975 if (!ret) {
9976 handle->country_code[0] = '0';
9977 handle->country_code[1] = '0';
9978 }
9979 }
9980 #endif
9981 #endif
9982 LEAVE();
9983 return ret;
9984 }
9985
9986 /**
9987 * @brief napi polling call back function.
9988 *
9989 * @param napi A pointer to napi_struct
9990 * @param budget the limit of packets driver should poll
9991 *
9992 * @return packets received
9993 */
9994 static int woal_netdev_poll_rx(struct napi_struct *napi, int budget)
9995 {
9996 moal_handle *handle = container_of(napi, moal_handle, napi_rx);
9997 t_u8 recv = budget;
9998
9999 ENTER();
10000 if (handle->surprise_removed == MTRUE) {
10001 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
10002 if (false == napi_complete(napi))
10003 PRINTM(MINFO, "%s: napi_complete with false \n",
10004 __func__);
10005 #else
10006 napi_complete(napi);
10007 #endif
10008 LEAVE();
10009 return 0;
10010 }
10011 if (MLAN_STATUS_SUCCESS !=
10012 mlan_rx_process(handle->pmlan_adapter, &recv))
10013 PRINTM(MERROR, "%s: mlan_rx_process failed \n", __func__);
10014 if (recv < budget) {
10015 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
10016 if (false == napi_complete(napi))
10017 PRINTM(MINFO, "%s: napi_complete with false \n",
10018 __func__);
10019 #else
10020 napi_complete(napi);
10021 #endif
10022 }
10023 LEAVE();
10024 return recv;
10025 }
10026
10027 /**
10028 * @brief This workqueue function handles set multicast_list
10029 *
10030 * @param work A pointer to work_struct
10031 *
10032 * @return N/A
10033 */
10034 t_void woal_mclist_work_queue(struct work_struct *work)
10035 {
10036 moal_private *priv = container_of(work, moal_private, mclist_work);
10037 woal_request_set_multicast_list(priv, priv->netdev);
10038 }
10039
10040 #ifdef STA_CFG80211
10041 /**
10042 * @brief This workqueue function handles woal scan timeout work
10043 *
10044 * @param work A pointer to work_struct
10045 *
10046 * @return N/A
10047 */
10048 t_void woal_scan_timeout_handler(struct work_struct *work)
10049 {
10050 struct delayed_work *delayed_work = to_delayed_work(work);
10051 moal_handle *handle =
10052 container_of(delayed_work, moal_handle, scan_timeout_work);
10053 unsigned long flags;
10054 moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_STA);
10055 t_u8 auto_fw_dump = MFALSE;
10056
10057 ENTER();
10058
10059 if (IS_STA_CFG80211(handle->params.cfg80211_wext)) {
10060 if (handle->scan_request && handle->fake_scan_complete) {
10061 PRINTM(MMSG, "wlan: Send fake scan result\n");
10062 if (priv)
10063 woal_inform_bss_from_scan_result(priv, NULL,
10064 MOAL_NO_WAIT);
10065 spin_lock_irqsave(&handle->scan_req_lock, flags);
10066 woal_cfg80211_scan_done(handle->scan_request, MFALSE);
10067 handle->scan_request = NULL;
10068 spin_unlock_irqrestore(&handle->scan_req_lock, flags);
10069 } else if (handle->scan_request) {
10070 PRINTM(MMSG, "wlan: scan timeout!\n");
10071 #ifdef DEBUG_LEVEL1
10072 if (drvdbg & MFW_D)
10073 auto_fw_dump = MTRUE;
10074 #endif
10075 if (priv) {
10076 woal_mlan_debug_info(priv);
10077 woal_moal_debug_info(priv, NULL, MFALSE);
10078 }
10079 handle->driver_status = MTRUE;
10080 if (!auto_fw_dump && !handle->fw_dump && priv)
10081 woal_process_hang(priv->phandle);
10082 wifi_status = WIFI_STATUS_SCAN_TIMEOUT;
10083 }
10084 }
10085
10086 LEAVE();
10087 }
10088 #endif
10089
10090 /**
10091 * @brief This workqueue function handles woal event queue
10092 *
10093 * @param work A pointer to work_struct
10094 *
10095 * @return N/A
10096 */
10097 t_void woal_evt_work_queue(struct work_struct *work)
10098 {
10099 moal_handle *handle = container_of(work, moal_handle, evt_work);
10100 struct woal_event *evt;
10101 unsigned long flags;
10102 #if defined(UAP_CFG80211) || defined(STA_CFG80211)
10103 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
10104 moal_private *priv;
10105 #endif
10106 #endif
10107 ENTER();
10108 if (handle->surprise_removed == MTRUE) {
10109 LEAVE();
10110 return;
10111 }
10112 spin_lock_irqsave(&handle->evt_lock, flags);
10113 while (!list_empty(&handle->evt_queue)) {
10114 evt = list_first_entry(&handle->evt_queue, struct woal_event,
10115 link);
10116 list_del(&evt->link);
10117 spin_unlock_irqrestore(&handle->evt_lock, flags);
10118 switch (evt->type) {
10119 case WOAL_EVENT_CHAN_SWITCH:
10120 #if defined(UAP_SUPPORT) || defined(STA_SUPPORT)
10121 #if defined(UAP_CFG80211) || defined(STA_CFG80211)
10122 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
10123 woal_cfg80211_notify_channel((moal_private *)evt->priv,
10124 &evt->chan_info);
10125 #endif
10126 #endif
10127 #endif
10128 break;
10129 case WOAL_EVENT_RX_MGMT_PKT:
10130 #if defined(UAP_CFG80211) || defined(STA_CFG80211)
10131 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
10132 priv = evt->priv;
10133 mutex_lock(&priv->wdev->mtx);
10134 cfg80211_rx_mlme_mgmt(priv->netdev, evt->evt.event_buf,
10135 evt->evt.event_len);
10136 mutex_unlock(&priv->wdev->mtx);
10137 #endif
10138 #endif
10139 break;
10140 case WOAL_EVENT_BGSCAN_STOP:
10141 #ifdef STA_CFG80211
10142 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
10143 woal_cfg80211_notify_sched_scan_stop(
10144 (moal_private *)evt->priv);
10145 #endif
10146 #endif
10147 break;
10148 #if defined(UAP_CFG80211) || defined(STA_CFG80211)
10149 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
10150 case WOAL_EVENT_DEAUTH:
10151 priv = evt->priv;
10152 woal_host_mlme_disconnect(evt->priv, evt->reason_code,
10153 priv->cfg_bssid);
10154 break;
10155
10156 case WOAL_EVENT_ASSOC_RESP:
10157 woal_host_mlme_process_assoc_resp(
10158 (moal_private *)evt->priv, &evt->assoc_info);
10159 break;
10160 #endif
10161 #endif
10162 #ifdef UAP_SUPPORT
10163 case WOAL_EVENT_CHAN_RPT:
10164 woal_process_chan_event((moal_private *)evt->priv,
10165 WOAL_EVENT_CHAN_RPT,
10166 evt->radar_info.channel,
10167 evt->radar_info.radar);
10168 break;
10169 case WOAL_EVENT_RADAR:
10170 woal_process_chan_event((moal_private *)evt->priv,
10171 WOAL_EVENT_RADAR,
10172 evt->radar_info.channel,
10173 evt->radar_info.radar);
10174 break;
10175 #endif
10176 #ifdef UAP_CFG80211
10177 #if KERNEL_VERSION(3, 12, 0) <= CFG80211_VERSION_CODE
10178 case WOAL_EVENT_CANCEL_CHANRPT:
10179 woal_process_cancel_chanrpt_event(
10180 (moal_private *)evt->priv);
10181 break;
10182 #endif
10183 #endif
10184 default:
10185 break;
10186 }
10187 kfree(evt);
10188 spin_lock_irqsave(&handle->evt_lock, flags);
10189 }
10190 spin_unlock_irqrestore(&handle->evt_lock, flags);
10191 LEAVE();
10192 }
10193 /**
10194 * @brief This workqueue function handles rx_process
10195 *
10196 * @param work A pointer to work_struct
10197 *
10198 * @return N/A
10199 */
10200 t_void woal_rx_work_queue(struct work_struct *work)
10201 {
10202 moal_handle *handle = container_of(work, moal_handle, rx_work);
10203 wifi_timeval start_timeval;
10204 wifi_timeval end_timeval;
10205
10206 ENTER();
10207 if (handle->surprise_removed == MTRUE) {
10208 LEAVE();
10209 return;
10210 }
10211 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
10212 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
10213 if (handle->cfg80211_suspend == MTRUE) {
10214 LEAVE();
10215 return;
10216 }
10217 #endif
10218 #endif
10219 woal_get_monotonic_time(&start_timeval);
10220 if (MLAN_STATUS_SUCCESS != mlan_rx_process(handle->pmlan_adapter, NULL))
10221 PRINTM(MERROR, "%s: mlan_rx_process failed \n", __func__);
10222
10223 woal_get_monotonic_time(&end_timeval);
10224 handle->rx_time += (t_u64)(timeval_to_usec(end_timeval) -
10225 timeval_to_usec(start_timeval));
10226 PRINTM(MINFO,
10227 "%s : start_timeval=%d:%d end_timeval=%d:%d inter=%llu rx_time=%llu\n",
10228 __func__, start_timeval.time_sec, start_timeval.time_usec,
10229 end_timeval.time_sec, end_timeval.time_usec,
10230 (t_u64)(timeval_to_usec(end_timeval) -
10231 timeval_to_usec(start_timeval)),
10232 handle->rx_time);
10233 LEAVE();
10234 }
10235
10236 /**
10237 * @brief This function dequeue pkt from list
10238 *
10239 * @param list A pointer to struct sk_buff_head
10240 *
10241 * @return skb buffer
10242 */
10243
10244 struct sk_buff *woal_skb_dequeue_spinlock(struct sk_buff_head *list)
10245 {
10246 struct sk_buff *result;
10247
10248 spin_lock_bh(&list->lock);
10249 result = __skb_dequeue(list);
10250 spin_unlock_bh(&list->lock);
10251 return result;
10252 }
10253
10254 /**
10255 * @brief This workqueue function handles rx_work_process
10256 *
10257 * @param work A pointer to work_struct
10258 *
10259 * @return N/A
10260 */
10261 t_void woal_tx_work_handler(struct work_struct *work)
10262 {
10263 moal_handle *handle = container_of(work, moal_handle, tx_work);
10264 moal_private *priv = NULL;
10265 int i = 0;
10266 struct sk_buff *skb = NULL;
10267
10268 ENTER();
10269 if (handle->surprise_removed == MTRUE) {
10270 LEAVE();
10271 return;
10272 }
10273
10274 for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
10275 priv = handle->priv[i];
10276 while ((skb = woal_skb_dequeue_spinlock(&priv->tx_q)) != NULL) {
10277 woal_start_xmit(priv, skb);
10278 }
10279 }
10280
10281 LEAVE();
10282 }
10283
10284 /**
10285 * @brief This workqueue function handles main_process
10286 *
10287 * @param work A pointer to work_struct
10288 *
10289 * @return N/A
10290 */
10291 t_void woal_main_work_queue(struct work_struct *work)
10292 {
10293 moal_handle *handle = container_of(work, moal_handle, main_work);
10294 #ifdef USB
10295 struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
10296 #endif
10297 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
10298 struct sched_param sp = {.sched_priority = wq_sched_prio};
10299 #endif
10300
10301 ENTER();
10302
10303 if (handle->surprise_removed == MTRUE) {
10304 LEAVE();
10305 return;
10306 }
10307 if (handle->reg_dbg == MTRUE) {
10308 handle->reg_dbg = MFALSE;
10309 if (handle->ops.reg_dbg)
10310 handle->ops.reg_dbg(handle);
10311 }
10312 if (handle->fw_dbg == MTRUE) {
10313 handle->fw_dbg = MFALSE;
10314 if (handle->ops.dump_fw_info)
10315 handle->ops.dump_fw_info(handle);
10316 LEAVE();
10317 return;
10318 }
10319 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
10320 /* Change the priority and scheduling policy of main work queue
10321 */
10322 if ((handle->params.wq_sched_prio != current->rt_priority) ||
10323 (handle->params.wq_sched_policy != current->policy)) {
10324 PRINTM(MMSG,
10325 "Set work queue priority %d and scheduling policy %d\n",
10326 handle->params.wq_sched_prio,
10327 handle->params.wq_sched_policy);
10328 sched_setscheduler(current, handle->params.wq_sched_policy,
10329 &sp);
10330 }
10331 #endif
10332
10333 handle->main_state = MOAL_ENTER_WORK_QUEUE;
10334 #ifdef USB
10335 /* WAR for no free skb issue */
10336 if (IS_USB(handle->card_type) && !atomic_read(&handle->rx_pending) &&
10337 atomic_read(&cardp->rx_data_urb_pending) < MVUSB_RX_DATA_URB) {
10338 PRINTM(MWARN, "Try to resubmit Rx data URBs\n");
10339 woal_usb_submit_rx_data_urbs(handle);
10340 }
10341 #endif
10342 handle->main_state = MOAL_START_MAIN_PROCESS;
10343 /* Call MLAN main process */
10344 mlan_main_process(handle->pmlan_adapter);
10345 handle->main_state = MOAL_END_MAIN_PROCESS;
10346
10347 LEAVE();
10348 }
10349
10350 #ifdef IMX_SUPPORT
10351 /**
10352 * @brief This function allocates the interrupt line to wakeup
10353 * the host, and initializes the device for wakeup
10354 *
10355 * @param handle A pointer to moal_handle structure
10356 *
10357 * @return N/A
10358 */
10359 void woal_regist_oob_wakeup_irq(moal_handle *handle)
10360 {
10361 int ret;
10362 struct device *dev = handle->hotplug_device;
10363 struct device_node *node;
10364
10365 ENTER();
10366
10367 node = of_find_compatible_node(NULL, NULL, "nxp,wifi-wake-host");
10368 if (!node)
10369 goto err_exit;
10370
10371 handle->irq_oob_wakeup = irq_of_parse_and_map(node, 0);
10372 if (!handle->irq_oob_wakeup) {
10373 dev_dbg(dev, "fail to parse irq_oob_wakeup from device tree\n");
10374 goto err_exit;
10375 }
10376
10377 ret = devm_request_threaded_irq(dev, handle->irq_oob_wakeup, NULL,
10378 woal_oob_wakeup_irq_handler,
10379 IRQF_SHARED | IRQF_ONESHOT,
10380 "wifi_oob_wakeup", handle);
10381 if (ret) {
10382 dev_err(dev, "Failed to request irq_oob_wakeup %d (%d)\n",
10383 handle->irq_oob_wakeup, ret);
10384 goto err_exit;
10385 }
10386
10387 disable_irq(handle->irq_oob_wakeup);
10388
10389 LEAVE();
10390 return;
10391
10392 err_exit:
10393 handle->irq_oob_wakeup = -1;
10394 }
10395
10396 /**
10397 * @brief This function frees the wakeup interrupt line
10398 *
10399 * @param handle A pointer to moal_handle structure
10400 *
10401 * @return N/A
10402 */
10403 void woal_unregist_oob_wakeup_irq(moal_handle *handle)
10404 {
10405 struct device *dev = handle->hotplug_device;
10406
10407 ENTER();
10408 if (handle->irq_oob_wakeup >= 0) {
10409 devm_free_irq(dev, handle->irq_oob_wakeup, handle);
10410 }
10411 LEAVE();
10412 }
10413
10414 /**
10415 * @brief This function disables power management wakeup
10416 *
10417 * @param handle A pointer to moal_handle structure
10418 *
10419 * @return N/A
10420 */
10421 void woal_disable_oob_wakeup_irq(moal_handle *handle)
10422 {
10423 ENTER();
10424
10425 if (handle->irq_oob_wakeup >= 0) {
10426 if (handle->wake_by_wifi)
10427 disable_irq_wake(handle->irq_oob_wakeup);
10428 else {
10429 disable_irq_wake(handle->irq_oob_wakeup);
10430 disable_irq(handle->irq_oob_wakeup);
10431 }
10432 }
10433
10434 LEAVE();
10435 }
10436
10437 /**
10438 * @brief This function enables power management wakeup
10439 *
10440 * @param handle A pointer to moal_handle structure
10441 *
10442 * @return N/A
10443 */
10444 void woal_enable_oob_wakeup_irq(moal_handle *handle)
10445 {
10446 ENTER();
10447
10448 /* Enable platform specific wakeup interrupt */
10449 if (handle->irq_oob_wakeup >= 0) {
10450 handle->wake_by_wifi = false;
10451 enable_irq(handle->irq_oob_wakeup);
10452 enable_irq_wake(handle->irq_oob_wakeup);
10453 }
10454
10455 LEAVE();
10456 }
10457
10458 /**
10459 * @brief This function will be called when the wakeup IRQ occurs
10460 *
10461 * @param irq Wakeup interrupt line
10462 * @param priv A void pointer to store moal_handle structure pointer
10463 *
10464 * @return Returns status of interrupt handler.
10465 */
10466 irqreturn_t woal_oob_wakeup_irq_handler(int irq, void *priv)
10467 {
10468 moal_handle *handle = priv;
10469 struct device *dev = handle->hotplug_device;
10470
10471 ENTER();
10472
10473 dev_dbg(dev, "%s: OOB wakeup by wifi", __func__);
10474 handle->wake_by_wifi = true;
10475 disable_irq_nosync(irq);
10476
10477 /* Notify PM core we are wakeup source */
10478 pm_wakeup_event(dev, 0);
10479 pm_system_wakeup();
10480
10481 LEAVE();
10482 return IRQ_HANDLED;
10483 }
10484 #endif /* IMX_SUPPORT */
10485
10486 /**
10487 * @brief This function adds the card. it will probe the
10488 * card, allocate the mlan_private and initialize the device.
10489 *
10490 * @param card A pointer to card
10491 * @param dev A pointer to device structure
10492 * @param if_ops A pointer to interface ops
10493 * @param card_type card type id
10494 *
10495 * @return A pointer to moal_handle structure
10496 */
10497 moal_handle *woal_add_card(void *card, struct device *dev, moal_if_ops *if_ops,
10498 t_u16 card_type)
10499 {
10500 moal_handle *handle = NULL;
10501 mlan_status status = MLAN_STATUS_SUCCESS;
10502 int netlink_num = NETLINK_NXP;
10503 int index = 0;
10504 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
10505 struct netlink_kernel_cfg cfg = {
10506 .groups = NL_MULTICAST_GROUP,
10507 };
10508 #endif
10509
10510 ENTER();
10511
10512 if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
10513 goto exit_sem_err;
10514
10515 for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
10516 if (m_handle[index] == NULL)
10517 break;
10518 }
10519 if (index >= MAX_MLAN_ADAPTER)
10520 goto err_handle;
10521
10522 /* Allocate buffer for moal_handle */
10523 handle = kzalloc(sizeof(moal_handle), GFP_KERNEL);
10524 if (!handle) {
10525 PRINTM(MERROR, "Allocate buffer for moal_handle failed!\n");
10526 goto err_handle;
10527 }
10528
10529 /* Init moal_handle */
10530 handle->card = card;
10531
10532 /* Save the handle */
10533 m_handle[index] = handle;
10534 handle->handle_idx = index;
10535
10536 handle->hotplug_device = dev;
10537 handle->card_type = card_type;
10538 /* Attach moal handle ops */
10539 PRINTM(MMSG, "Attach moal handle ops, card interface type: 0x%x\n",
10540 handle->card_type);
10541 moal_memcpy_ext(handle, &handle->ops, if_ops, sizeof(*if_ops),
10542 sizeof(handle->ops));
10543 handle->second_mac = handle->ops.is_second_mac(handle);
10544 if (handle->second_mac) {
10545 if ((index >= 1) && m_handle[index - 1]) {
10546 handle->pref_mac = (void *)m_handle[index - 1];
10547 m_handle[index - 1]->pref_mac = (void *)handle;
10548 }
10549 }
10550
10551 /* Init module parameters */
10552 if (woal_init_module_param(handle)) {
10553 PRINTM(MERROR, "Fail to load module parameter file\n");
10554 goto err_kmalloc;
10555 }
10556 if (!handle->params.drv_mode) {
10557 PRINTM(MMSG, "wlan: stop init_adapter, drv_mode=%d\n",
10558 handle->params.drv_mode);
10559 goto err_kmalloc;
10560 }
10561 #ifdef IMX_SUPPORT
10562 #ifdef SDIO
10563 if (IS_SD(handle->card_type)) {
10564 moal_extflg_set(handle, EXT_TX_WORK);
10565 moal_extflg_set(handle, EXT_TX_SKB_CLONE);
10566 }
10567 #endif
10568 #endif
10569
10570 #ifdef DEBUG_LEVEL1
10571 drvdbg = handle->params.drvdbg;
10572 #endif
10573
10574 if (handle->params.mac_addr
10575 #ifdef MFG_CMD_SUPPORT
10576 && handle->params.mfg_mode != MLAN_INIT_PARA_ENABLED
10577 #endif
10578 ) {
10579 t_u8 temp[20];
10580 t_u8 len = strlen(handle->params.mac_addr) + 1;
10581 if (len < sizeof(temp)) {
10582 moal_memcpy_ext(handle, temp, handle->params.mac_addr,
10583 len, sizeof(temp));
10584 handle->set_mac_addr = 1;
10585 /* note: the following function overwrites the
10586 * temp buffer */
10587 woal_mac2u8(handle->mac_addr, temp);
10588 }
10589 }
10590
10591 /* Get card info */
10592 if (woal_get_card_info(handle)) {
10593 PRINTM(MERROR, "Fail to get card info\n");
10594 goto err_kmalloc;
10595 }
10596 /** Get card revision */
10597 handle->ops.get_fw_name(handle);
10598 #ifdef STA_SUPPORT
10599 handle->scan_pending_on_block = MFALSE;
10600 MOAL_INIT_SEMAPHORE(&handle->async_sem);
10601 #endif
10602
10603 #if defined(USB)
10604 if (IS_USB(handle->card_type))
10605 handle->boot_state = ((struct usb_card_rec *)card)->boot_state;
10606 #endif /* USB_NEW_FW_DNLD */
10607 /* Init SW */
10608 if (MLAN_STATUS_SUCCESS != woal_init_sw(handle)) {
10609 PRINTM(MFATAL, "Software Init Failed\n");
10610 goto err_kmalloc;
10611 }
10612
10613 do {
10614 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
10615 handle->nl_sk = netlink_kernel_create(netlink_num, NULL);
10616 #else
10617 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
10618 handle->nl_sk = netlink_kernel_create(
10619 netlink_num, NL_MULTICAST_GROUP, NULL, THIS_MODULE);
10620 #else
10621 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
10622 handle->nl_sk =
10623 netlink_kernel_create(netlink_num, NL_MULTICAST_GROUP,
10624 NULL, NULL, THIS_MODULE);
10625 #else
10626 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
10627 handle->nl_sk = netlink_kernel_create(&init_net, netlink_num,
10628 NL_MULTICAST_GROUP, NULL,
10629 NULL, THIS_MODULE);
10630 #else
10631 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
10632 handle->nl_sk = netlink_kernel_create(&init_net, netlink_num,
10633 THIS_MODULE, &cfg);
10634 #else
10635 handle->nl_sk =
10636 netlink_kernel_create(&init_net, netlink_num, &cfg);
10637 #endif
10638 #endif
10639 #endif
10640 #endif
10641 #endif
10642 if (handle->nl_sk) {
10643 PRINTM(MINFO, "Netlink number = %d\n", netlink_num);
10644 handle->netlink_num = netlink_num;
10645 break;
10646 }
10647 netlink_num--;
10648 } while (netlink_num > 0);
10649
10650 if (handle->nl_sk == NULL) {
10651 PRINTM(MERROR,
10652 "Could not initialize netlink event passing mechanism!\n");
10653 goto err_kmalloc;
10654 }
10655
10656 /* Create workqueue for main process */
10657 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
10658 /* For kernel less than 2.6.14 name can not be
10659 * greater than 10 characters */
10660 handle->workqueue = create_workqueue("MOAL_WORKQ");
10661 #else
10662 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
10663 handle->workqueue = alloc_workqueue(
10664 "MOAL_WORK_QUEUE", WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
10665 #else
10666 handle->workqueue = create_workqueue("MOAL_WORK_QUEUE");
10667 #endif
10668 #endif
10669 if (!handle->workqueue)
10670 goto err_kmalloc;
10671
10672 MLAN_INIT_WORK(&handle->main_work, woal_main_work_queue);
10673
10674 /* Create workqueue for event process */
10675 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
10676 /* For kernel less than 2.6.14 name can not be
10677 * greater than 10 characters */
10678 handle->evt_workqueue = create_workqueue("MOAL_EVT_WORKQ");
10679 #else
10680 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
10681 handle->evt_workqueue =
10682 alloc_workqueue("MOAL_EVT_WORK_QUEUE",
10683 WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
10684 #else
10685 handle->evt_workqueue = create_workqueue("MOAL_EVT_WORK_QUEUE");
10686 #endif
10687 #endif
10688 if (!handle->evt_workqueue) {
10689 woal_terminate_workqueue(handle);
10690 goto err_kmalloc;
10691 }
10692
10693 MLAN_INIT_WORK(&handle->evt_work, woal_evt_work_queue);
10694 INIT_LIST_HEAD(&handle->evt_queue);
10695 spin_lock_init(&handle->evt_lock);
10696
10697 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
10698 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
10699 MLAN_INIT_WORK(&handle->regulatory_work, woal_regulatory_work_queue);
10700 #endif
10701 #endif
10702
10703 #ifdef STA_CFG80211
10704 INIT_DELAYED_WORK(&handle->scan_timeout_work,
10705 woal_scan_timeout_handler);
10706 #endif
10707
10708 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
10709 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
10710 MLAN_INIT_WORK(&handle->host_mlme_work, woal_host_mlme_work_queue);
10711 #endif
10712 #endif
10713
10714 if (!moal_extflg_isset(handle, EXT_NAPI)) {
10715 /* Create workqueue for rx process */
10716 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
10717 /* For kernel less than 2.6.14 name can not be
10718 * greater than 10 characters */
10719 handle->rx_workqueue = create_workqueue("MOAL_RX_WORKQ");
10720 #else
10721 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
10722 handle->rx_workqueue = alloc_workqueue(
10723 "MOAL_RX_WORK_QUEUE",
10724 WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
10725 #else
10726 handle->rx_workqueue = create_workqueue("MOAL_RX_WORK_QUEUE");
10727 #endif
10728 #endif
10729 if (!handle->rx_workqueue) {
10730 woal_terminate_workqueue(handle);
10731 goto err_kmalloc;
10732 }
10733 MLAN_INIT_WORK(&handle->rx_work, woal_rx_work_queue);
10734 }
10735 #define NAPI_BUDGET 64
10736 if (moal_extflg_isset(handle, EXT_NAPI)) {
10737 init_dummy_netdev(&handle->napi_dev);
10738 netif_napi_add(&handle->napi_dev, &handle->napi_rx,
10739 #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
10740 woal_netdev_poll_rx);
10741 #else
10742 woal_netdev_poll_rx, NAPI_BUDGET);
10743 #endif
10744 napi_enable(&handle->napi_rx);
10745 }
10746
10747 if (moal_extflg_isset(handle, EXT_TX_WORK)) {
10748 /* Create workqueue for tx process */
10749 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
10750 handle->tx_workqueue = create_workqueue("MOAL_TX_WORKQ");
10751 #else
10752 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
10753 handle->tx_workqueue = alloc_workqueue(
10754 "MOAL_TX_WORK_QUEUE",
10755 WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
10756 #else
10757 handle->tx_workqueue = create_workqueue("MOAL_TX_WORK_QUEUE");
10758 #endif
10759 #endif
10760 if (!handle->tx_workqueue) {
10761 woal_terminate_workqueue(handle);
10762 goto err_kmalloc;
10763 }
10764 MLAN_INIT_WORK(&handle->tx_work, woal_tx_work_handler);
10765 }
10766
10767 #ifdef REASSOCIATION
10768 PRINTM(MINFO, "Starting re-association thread...\n");
10769 handle->reassoc_thread.handle = handle;
10770 woal_create_thread(woal_reassociation_thread, &handle->reassoc_thread,
10771 "woal_reassoc_service");
10772
10773 while (!handle->reassoc_thread.pid)
10774 woal_sched_timeout(2);
10775 #endif /* REASSOCIATION */
10776
10777 /* Register the device. Fill up the private data structure with
10778 * relevant information from the card and request for the
10779 * required IRQ.
10780 */
10781 if (handle->ops.register_dev(handle) != MLAN_STATUS_SUCCESS) {
10782 PRINTM(MFATAL, "Failed to register wlan device!\n");
10783 goto err_registerdev;
10784 }
10785 woal_update_firmware_name(handle);
10786 #ifdef ANDROID_KERNEL
10787 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
10788 wakeup_source_init(&handle->ws, "mwlan");
10789 #else
10790 wake_lock_init(&handle->wake_lock, WAKE_LOCK_SUSPEND, "mwlan");
10791 #endif
10792 #endif
10793
10794 /* Init FW and HW */
10795 if (MLAN_STATUS_SUCCESS != woal_init_fw(handle)) {
10796 PRINTM(MFATAL, "Firmware Init Failed\n");
10797 goto err_init_fw;
10798 }
10799 device_init_wakeup(dev, true);
10800 #ifdef SD8887
10801 if (IS_SD8887(handle->card_type)) {
10802 union {
10803 t_u32 l;
10804 t_u8 c[4];
10805 } ver;
10806 ver.l = handle->fw_release_number;
10807 if (ver.c[1] == 75) {
10808 handle->card_info->embedded_supp = 0;
10809 PRINTM(MMSG,
10810 "Disable EMBEDED Supplicant for SD8887-FP75\n");
10811 }
10812 }
10813 #endif
10814 LEAVE();
10815 return handle;
10816
10817 err_init_fw:
10818 if ((handle->hardware_status == HardwareStatusFwReady) ||
10819 (handle->hardware_status == HardwareStatusReady)) {
10820 PRINTM(MINFO, "shutdown mlan\n");
10821 handle->init_wait_q_woken = MFALSE;
10822 status = mlan_shutdown_fw(handle->pmlan_adapter);
10823 if (status == MLAN_STATUS_PENDING)
10824 wait_event_interruptible(handle->init_wait_q,
10825 handle->init_wait_q_woken);
10826 }
10827 #ifdef ANDROID_KERNEL
10828 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
10829 wakeup_source_trash(&handle->ws);
10830 #else
10831 wake_lock_destroy(&handle->wake_lock);
10832 #endif
10833 #endif
10834 /* Unregister device */
10835 PRINTM(MINFO, "unregister device\n");
10836 handle->ops.unregister_dev(handle);
10837 err_registerdev:
10838 handle->surprise_removed = MTRUE;
10839 #ifdef REASSOCIATION
10840 if (handle->reassoc_thread.pid)
10841 wake_up_interruptible(&handle->reassoc_thread.wait_q);
10842 /* waiting for main thread quit */
10843 while (handle->reassoc_thread.pid)
10844 woal_sched_timeout(2);
10845 #endif /* REASSOCIATION */
10846 if (moal_extflg_isset(handle, EXT_NAPI))
10847 netif_napi_del(&handle->napi_rx);
10848 woal_terminate_workqueue(handle);
10849 err_kmalloc:
10850 woal_free_moal_handle(handle);
10851 if (index < MAX_MLAN_ADAPTER)
10852 m_handle[index] = NULL;
10853 err_handle:
10854 MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
10855 exit_sem_err:
10856 LEAVE();
10857 return NULL;
10858 }
10859
10860 /**
10861 * @brief This function removes the card.
10862 *
10863 * @param card A pointer to card
10864 *
10865 * @return MLAN_STATUS_SUCCESS
10866 */
10867 mlan_status woal_remove_card(void *card)
10868 {
10869 moal_handle *handle = NULL;
10870 moal_private *priv = NULL;
10871 mlan_status status;
10872 int i;
10873 int index = 0;
10874
10875 ENTER();
10876
10877 if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
10878 goto exit_sem_err;
10879 /* Find the correct handle */
10880 for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
10881 if (m_handle[index] && (m_handle[index]->card == card)) {
10882 handle = m_handle[index];
10883 break;
10884 }
10885 }
10886 if (!handle)
10887 goto exit_remove;
10888 device_init_wakeup(handle->hotplug_device, false);
10889 #ifdef MFG_CMD_SUPPORT
10890 if (handle->params.mfg_mode == MLAN_INIT_PARA_ENABLED
10891 #if defined(USB)
10892 && handle->boot_state == USB_FW_READY
10893 #endif
10894 ) {
10895 if (handle->params.fw_name) {
10896 kfree(handle->params.fw_name);
10897 handle->params.fw_name = NULL;
10898 }
10899 }
10900 #endif
10901 if (handle->rf_test_mode)
10902 woal_process_rf_test_mode(handle, MFG_CMD_UNSET_TEST_MODE);
10903 handle->surprise_removed = MTRUE;
10904
10905 woal_flush_workqueue(handle);
10906
10907 if (moal_extflg_isset(handle, EXT_NAPI)) {
10908 napi_disable(&handle->napi_rx);
10909 netif_napi_del(&handle->napi_rx);
10910 }
10911
10912 /* Stop data */
10913 for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
10914 priv = handle->priv[i];
10915 if (priv) {
10916 if (priv->netdev) {
10917 woal_stop_queue(priv->netdev);
10918 if (netif_carrier_ok(priv->netdev))
10919 netif_carrier_off(priv->netdev);
10920 }
10921 }
10922 }
10923 if ((handle->hardware_status == HardwareStatusFwReady) ||
10924 (handle->hardware_status == HardwareStatusReady)) {
10925 /* Shutdown firmware */
10926 PRINTM(MIOCTL, "mlan_shutdown_fw.....\n");
10927 handle->init_wait_q_woken = MFALSE;
10928
10929 status = mlan_shutdown_fw(handle->pmlan_adapter);
10930 if (status == MLAN_STATUS_PENDING)
10931 wait_event_interruptible(handle->init_wait_q,
10932 handle->init_wait_q_woken);
10933 PRINTM(MIOCTL, "mlan_shutdown_fw done!\n");
10934 }
10935 /* Unregister mlan */
10936 if (handle->pmlan_adapter) {
10937 mlan_unregister(handle->pmlan_adapter);
10938 handle->pmlan_adapter = NULL;
10939 }
10940 if (atomic_read(&handle->rx_pending) ||
10941 atomic_read(&handle->tx_pending) ||
10942 atomic_read(&handle->ioctl_pending)) {
10943 PRINTM(MERROR,
10944 "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n",
10945 atomic_read(&handle->rx_pending),
10946 atomic_read(&handle->tx_pending),
10947 atomic_read(&handle->ioctl_pending));
10948 }
10949 unregister_inetaddr_notifier(&handle->woal_notifier);
10950 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
10951 #if IS_ENABLED(CONFIG_IPV6)
10952 unregister_inet6addr_notifier(&handle->woal_inet6_notifier);
10953 #endif
10954 #endif
10955
10956 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
10957 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
10958 if (handle->is_remain_timer_set) {
10959 woal_cancel_timer(&handle->remain_timer);
10960 woal_remain_timer_func(handle);
10961 }
10962 #endif
10963 #endif
10964
10965 #ifdef WIFI_DIRECT_SUPPORT
10966 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
10967 if (handle->is_go_timer_set) {
10968 woal_cancel_timer(&handle->go_timer);
10969 handle->is_go_timer_set = MFALSE;
10970 }
10971 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
10972 /* Remove virtual interface */
10973 woal_remove_virtual_interface(handle);
10974 #endif
10975 #endif
10976 #endif
10977 if (handle->tp_acnt.on) {
10978 handle->tp_acnt.on = 0;
10979 handle->tp_acnt.drop_point = 0;
10980 if (handle->is_tp_acnt_timer_set) {
10981 woal_cancel_timer(&handle->tp_acnt.timer);
10982 handle->is_tp_acnt_timer_set = MFALSE;
10983 }
10984 }
10985
10986 /* Remove interface */
10987 for (i = 0; i < MIN(MLAN_MAX_BSS_NUM, handle->priv_num); i++)
10988 woal_remove_interface(handle, i);
10989
10990 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
10991 /* Unregister and detach connected radiotap net device */
10992 if (handle->mon_if) {
10993 netif_device_detach(handle->mon_if->mon_ndev);
10994 if (handle->mon_if->mon_ndev->reg_state == NETREG_REGISTERED)
10995 unregister_netdev(handle->mon_if->mon_ndev);
10996 handle->mon_if = NULL;
10997 }
10998 #endif
10999
11000 woal_terminate_workqueue(handle);
11001
11002 #ifdef UAP_CFG80211
11003 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
11004 if (handle->is_cac_timer_set) {
11005 woal_cancel_timer(&handle->cac_timer);
11006 handle->is_cac_timer_set = MFALSE;
11007 }
11008 #endif
11009 #endif
11010 #ifdef REASSOCIATION
11011 PRINTM(MINFO, "Free reassoc_timer\n");
11012 if (handle->is_reassoc_timer_set) {
11013 woal_cancel_timer(&handle->reassoc_timer);
11014 handle->is_reassoc_timer_set = MFALSE;
11015 }
11016 if (handle->reassoc_thread.pid)
11017 wake_up_interruptible(&handle->reassoc_thread.wait_q);
11018
11019 /* waiting for main thread quit */
11020 while (handle->reassoc_thread.pid)
11021 woal_sched_timeout(2);
11022 #endif /* REASSOCIATION */
11023
11024 PRINTM(MINFO, "Free FW dump timer\n");
11025 if (handle->is_fw_dump_timer_set) {
11026 woal_cancel_timer(&handle->fw_dump_timer);
11027 handle->is_fw_dump_timer_set = MFALSE;
11028 }
11029
11030 #ifdef CONFIG_PROC_FS
11031 woal_proc_exit(handle);
11032 #endif
11033 /* Unregister device */
11034 PRINTM(MINFO, "unregister device\n");
11035 handle->ops.unregister_dev(handle);
11036 #ifdef ANDROID_KERNEL
11037 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
11038 wakeup_source_trash(&handle->ws);
11039 #else
11040 wake_lock_destroy(&handle->wake_lock);
11041 #endif
11042 #endif
11043 /* Free adapter structure */
11044 PRINTM(MINFO, "Free Adapter\n");
11045 woal_free_moal_handle(handle);
11046
11047 for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
11048 if (m_handle[index] == handle) {
11049 m_handle[index] = NULL;
11050 break;
11051 }
11052 }
11053 exit_remove:
11054 MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
11055 exit_sem_err:
11056 LEAVE();
11057 return MLAN_STATUS_SUCCESS;
11058 }
11059
11060 #ifdef CONFIG_PROC_FS
11061 /**
11062 * @brief This function switch the drv_mode
11063 *
11064 * @param handle A pointer to moal_handle structure
11065 * @param mode new drv_mode to switch.
11066 *
11067 * @return MLAN_STATUS_SUCCESS /MLAN_STATUS_FAILURE
11068 * /MLAN_STATUS_PENDING
11069 */
11070 mlan_status woal_switch_drv_mode(moal_handle *handle, t_u32 mode)
11071 {
11072 unsigned int i;
11073 mlan_status status = MLAN_STATUS_SUCCESS;
11074 moal_private *priv = NULL;
11075
11076 ENTER();
11077
11078 if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
11079 goto exit_sem_err;
11080
11081 if (woal_update_drv_tbl(handle, mode) != MLAN_STATUS_SUCCESS) {
11082 PRINTM(MERROR, "Could not update driver mode table!\n");
11083 status = MLAN_STATUS_FAILURE;
11084 goto exit;
11085 }
11086
11087 /* Reset all interfaces */
11088 priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
11089 if (MLAN_STATUS_SUCCESS !=
11090 woal_reset_intf(priv, MOAL_IOCTL_WAIT, MTRUE)) {
11091 PRINTM(MERROR, "woal_reset_inf failed!\n");
11092 goto exit;
11093 }
11094
11095 status = woal_shutdown_fw(priv, MOAL_IOCTL_WAIT);
11096 if (status != MLAN_STATUS_SUCCESS) {
11097 PRINTM(MERROR, "func shutdown failed!\n");
11098 goto exit;
11099 }
11100 #ifdef USB
11101 handle->skip_fw_dnld = MTRUE;
11102 #endif
11103
11104 /* Shutdown firmware */
11105 PRINTM(MIOCTL, "mlan_shutdown_fw.....\n");
11106 handle->init_wait_q_woken = MFALSE;
11107 status = mlan_shutdown_fw(handle->pmlan_adapter);
11108 if (status == MLAN_STATUS_PENDING)
11109 wait_event_interruptible(handle->init_wait_q,
11110 handle->init_wait_q_woken);
11111 PRINTM(MIOCTL, "mlan_shutdown_fw done!\n");
11112 /* Unregister mlan */
11113 if (handle->pmlan_adapter) {
11114 mlan_unregister(handle->pmlan_adapter);
11115 handle->pmlan_adapter = NULL;
11116 }
11117 if (atomic_read(&handle->rx_pending) ||
11118 atomic_read(&handle->tx_pending) ||
11119 atomic_read(&handle->ioctl_pending)) {
11120 PRINTM(MERROR,
11121 "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n",
11122 atomic_read(&handle->rx_pending),
11123 atomic_read(&handle->tx_pending),
11124 atomic_read(&handle->ioctl_pending));
11125 }
11126
11127 unregister_inetaddr_notifier(&handle->woal_notifier);
11128 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
11129 #if IS_ENABLED(CONFIG_IPV6)
11130 unregister_inet6addr_notifier(&handle->woal_inet6_notifier);
11131 #endif
11132 #endif
11133
11134 /* Remove interface */
11135 for (i = 0; i < MIN(MLAN_MAX_BSS_NUM, handle->priv_num); i++)
11136 woal_remove_interface(handle, i);
11137
11138 if (atomic_read(&handle->lock_count) ||
11139 atomic_read(&handle->malloc_count) ||
11140 atomic_read(&handle->mbufalloc_count)) {
11141 PRINTM(MERROR,
11142 "mlan has memory leak: lock_count=%d, malloc_count=%d, mbufalloc_count=%d\n",
11143 atomic_read(&handle->lock_count),
11144 atomic_read(&handle->malloc_count),
11145 atomic_read(&handle->mbufalloc_count));
11146 }
11147 #ifdef PCIE
11148 if (IS_PCIE(handle->card_type) &&
11149 atomic_read(&handle->malloc_cons_count)) {
11150 PRINTM(MERROR, "mlan has memory leak: malloc_cons_count=%d\n",
11151 atomic_read(&handle->malloc_cons_count));
11152 }
11153 #endif
11154
11155 handle->priv_num = 0;
11156 handle->params.drv_mode = mode;
11157 /* Init SW */
11158 if (woal_init_sw(handle)) {
11159 PRINTM(MFATAL, "Software Init Failed\n");
11160 goto exit;
11161 }
11162 /* Init FW and HW */
11163 if (woal_init_fw(handle)) {
11164 PRINTM(MFATAL, "Firmware Init Failed\n");
11165 goto exit;
11166 }
11167 LEAVE();
11168 return status;
11169 exit:
11170 MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
11171 exit_sem_err:
11172 LEAVE();
11173 return status;
11174 }
11175 #endif
11176
11177 #ifdef SDIO_MMC
11178 #define FW_POLL_TRIES 100
11179
11180 /**
11181 * @brief This function reload fw
11182 *
11183 * @param handle A pointer to moal_handle structure
11184 * @param mode FW_RELOAD_SDIO_INBAND_RESET or FW_RELOAD_SDIO_HW_RESET
11185 *
11186 * @return 0--success, otherwise failure
11187 */
11188 static int woal_reset_and_reload_fw(moal_handle *handle, t_u8 mode)
11189 {
11190 int ret = 0, tries = 0;
11191 t_u32 value = 1;
11192 t_u32 reset_reg = handle->card_info->fw_reset_reg;
11193 t_u8 reset_val = handle->card_info->fw_reset_val;
11194
11195 ENTER();
11196 if (mode == FW_RELOAD_SDIO_HW_RESET) {
11197 PRINTM(MCMND, "woal_sdio_reset_fw...\n");
11198 woal_sdio_reset_hw(handle);
11199 goto reload_fw;
11200 }
11201 mlan_pm_wakeup_card(handle->pmlan_adapter, MTRUE);
11202 /** wait SOC fully wake up */
11203 for (tries = 0; tries < FW_POLL_TRIES; ++tries) {
11204 ret = handle->ops.write_reg(handle, reset_reg, 0xba);
11205 if (ret == MLAN_STATUS_SUCCESS) {
11206 handle->ops.read_reg(handle, reset_reg, &value);
11207 if (value == 0xba) {
11208 PRINTM(MMSG, "FW wake up\n");
11209 break;
11210 }
11211 }
11212 udelay(1000);
11213 }
11214 /* Write register to notify FW */
11215 if (handle->ops.write_reg(handle, reset_reg, reset_val) !=
11216 MLAN_STATUS_SUCCESS) {
11217 PRINTM(MERROR, "Failed to write register.\n");
11218 ret = -EFAULT;
11219 goto done;
11220 }
11221 #if defined(SD9098) || defined(SD9097) || defined(SDNW62X) || defined(SD9177)
11222 if (IS_SD9098(handle->card_type) || IS_SD9097(handle->card_type) ||
11223 IS_SDNW62X(handle->card_type) || IS_SD9177(handle->card_type))
11224 handle->ops.write_reg(handle, 0x00, 0x10);
11225 #endif
11226 /* Poll register around 100 ms */
11227 for (tries = 0; tries < FW_POLL_TRIES; ++tries) {
11228 handle->ops.read_reg(handle, reset_reg, &value);
11229 if (value == 0)
11230 /* FW is ready */
11231 break;
11232 udelay(1000);
11233 }
11234
11235 if (value) {
11236 PRINTM(MERROR, "Failed to poll FW reset register %X=0x%x\n",
11237 reset_reg, value);
11238 ret = -EFAULT;
11239 goto done;
11240 }
11241 mlan_pm_wakeup_card(handle->pmlan_adapter, MFALSE);
11242 reload_fw:
11243 /* Download FW */
11244 ret = woal_request_fw(handle);
11245 if (ret) {
11246 ret = -EFAULT;
11247 goto done;
11248 }
11249 PRINTM(MMSG, "FW Reload successfully.");
11250 done:
11251 LEAVE();
11252 return ret;
11253 }
11254 #endif
11255
11256 /**
11257 * @brief This function reload fw
11258 *
11259 * @param handle A pointer to moal_handle structure
11260 *
11261 * @return 0--success, otherwise failure
11262 */
11263 static int woal_reload_fw(moal_handle *handle)
11264 {
11265 int ret = 0;
11266 ENTER();
11267 /* Download FW */
11268 ret = woal_request_fw(handle);
11269 if (ret) {
11270 ret = -EFAULT;
11271 goto done;
11272 }
11273 PRINTM(MMSG, "FW Reload successfully.");
11274 done:
11275 LEAVE();
11276 return ret;
11277 }
11278
11279 /**
11280 * @brief This function handle the pre_reset
11281 *
11282 * @param handle A pointer to moal_handle structure
11283 *
11284 * @return NULL;
11285 */
11286 static void woal_pre_reset(moal_handle *handle)
11287 {
11288 int intf_num;
11289 t_u8 driver_status = handle->driver_status;
11290 t_u8 i;
11291 moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_STA);
11292 mlan_debug_info *info = &(handle->debug_info);
11293 int ioctl_pending = 0;
11294
11295 ENTER();
11296 if (!driver_status && priv)
11297 woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
11298 handle->driver_status = MTRUE;
11299
11300 if (!driver_status)
11301 woal_sched_timeout_uninterruptible(MOAL_TIMER_1S);
11302
11303 // wait for IOCTL return
11304 if (!driver_status && priv) {
11305 for (i = 0; i < 5; i++) {
11306 if (woal_get_debug_info(priv, MOAL_IOCTL_WAIT, info))
11307 PRINTM(MERROR,
11308 "Could not retrieve debug information from MLAN\n");
11309 ioctl_pending = atomic_read(&handle->ioctl_pending);
11310 if (!info->pending_cmd && !ioctl_pending) {
11311 PRINTM(MCMND,
11312 "fw_reload: No pending command and IOCTL\n");
11313 break;
11314 }
11315 woal_sched_timeout_uninterruptible(MOAL_TIMER_1S);
11316 }
11317 }
11318 #ifdef WIFI_DIRECT_SUPPORT
11319 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
11320 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
11321 /* Remove virtual interface */
11322 woal_remove_virtual_interface(handle);
11323 #endif
11324 #endif
11325 #endif
11326
11327 /** detach network interface */
11328 for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
11329 if (handle->priv[intf_num]) {
11330 woal_stop_queue(handle->priv[intf_num]->netdev);
11331 netif_device_detach(handle->priv[intf_num]->netdev);
11332 }
11333 }
11334 /** mask host interrupt from firmware */
11335 mlan_disable_host_int(handle->pmlan_adapter);
11336 /** cancel all pending commands */
11337 mlan_ioctl(handle->pmlan_adapter, NULL);
11338 woal_flush_workqueue(handle);
11339
11340 handle->fw_reload = MTRUE;
11341 woal_update_firmware_name(handle);
11342 #ifdef USB
11343 if (IS_USB(handle->card_type))
11344 woal_kill_urbs(handle);
11345 #endif
11346 LEAVE();
11347 }
11348
11349 /**
11350 * @brief This function handle pose_reset
11351 *
11352 * @param handle A pointer to moal_handle structure
11353 *
11354 * @return NULL;
11355 */
11356 static void woal_post_reset(moal_handle *handle)
11357 {
11358 mlan_ioctl_req *req = NULL;
11359 mlan_ds_misc_cfg *misc = NULL;
11360 int intf_num;
11361 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
11362 moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
11363 t_u8 country_code[COUNTRY_CODE_LEN];
11364 #endif
11365 #ifdef WIFI_DIRECT_SUPPORT
11366 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
11367 #if defined(STA_WEXT) || defined(UAP_WEXT)
11368 t_u8 bss_role = MLAN_BSS_ROLE_STA;
11369 #endif
11370 #endif
11371 #endif /* WIFI_DIRECT_SUPPORT */
11372
11373 ENTER();
11374 /** un-block IOCTL */
11375 handle->fw_reload = MFALSE;
11376 /* Restart the firmware */
11377 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
11378 if (req) {
11379 misc = (mlan_ds_misc_cfg *)req->pbuf;
11380 misc->sub_command = MLAN_OID_MISC_WARM_RESET;
11381 misc->param.fw_reload = MTRUE;
11382 req->req_id = MLAN_IOCTL_MISC_CFG;
11383 req->action = MLAN_ACT_SET;
11384 if (MLAN_STATUS_SUCCESS !=
11385 woal_request_ioctl(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
11386 req, MOAL_IOCTL_WAIT_TIMEOUT)) {
11387 PRINTM(MERROR, "%s: warm reset failed \n", __func__);
11388 kfree(req);
11389 goto done;
11390 }
11391 kfree(req);
11392 }
11393 #ifdef DEBUG_LEVEL1
11394 drvdbg = handle->params.drvdbg;
11395 #endif
11396 handle->fw_dump_status = MFALSE;
11397 handle->driver_status = MFALSE;
11398 handle->hardware_status = HardwareStatusReady;
11399 #ifdef STA_CFG80211
11400 handle->scan_timeout = SCAN_TIMEOUT_25S;
11401 #endif
11402 if (!handle->wifi_hal_flag) {
11403 PRINTM(MMSG, "wlan: post_reset remove/add interface\n");
11404 handle->surprise_removed = MTRUE;
11405 for (intf_num = 0;
11406 intf_num < MIN(MLAN_MAX_BSS_NUM, handle->priv_num);
11407 intf_num++)
11408 woal_remove_interface(handle, intf_num);
11409 handle->priv_num = 0;
11410 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
11411 /* Unregister wiphy device and free */
11412 if (handle->wiphy) {
11413 wiphy_unregister(handle->wiphy);
11414 woal_cfg80211_free_bands(handle->wiphy);
11415 wiphy_free(handle->wiphy);
11416 handle->wiphy = NULL;
11417 }
11418 #endif
11419 handle->surprise_removed = MFALSE;
11420
11421 for (intf_num = 0; intf_num < handle->drv_mode.intf_num;
11422 intf_num++) {
11423 if (handle->drv_mode.bss_attr[intf_num].bss_virtual)
11424 continue;
11425 if (!woal_add_interface(handle, handle->priv_num,
11426 handle->drv_mode
11427 .bss_attr[intf_num]
11428 .bss_type)) {
11429 PRINTM(MERROR, "%s: add interface %d failed \n",
11430 __func__, handle->priv_num);
11431 goto done;
11432 }
11433 }
11434 PRINTM(MMSG, "wlan: post_reset remove/add interface done\n");
11435 goto done;
11436 }
11437 /* Reset all interfaces */
11438 woal_reset_intf(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
11439 MOAL_IOCTL_WAIT, MTRUE);
11440 /* Initialize private structures */
11441 for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
11442 if (handle->priv[intf_num]) {
11443 woal_init_priv(handle->priv[intf_num], MOAL_IOCTL_WAIT);
11444 #ifdef WIFI_DIRECT_SUPPORT
11445 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
11446 #if defined(STA_WEXT) || defined(UAP_WEXT)
11447 if ((handle->priv[intf_num]->bss_type ==
11448 MLAN_BSS_TYPE_WIFIDIRECT) &&
11449 (GET_BSS_ROLE(handle->priv[intf_num]) ==
11450 MLAN_BSS_ROLE_UAP)) {
11451 if (MLAN_STATUS_SUCCESS !=
11452 woal_bss_role_cfg(handle->priv[intf_num],
11453 MLAN_ACT_SET,
11454 MOAL_IOCTL_WAIT,
11455 &bss_role)) {
11456 goto done;
11457 }
11458 }
11459 #endif /* STA_WEXT || UAP_WEXT */
11460 #endif /* STA_SUPPORT && UAP_SUPPORT */
11461 #endif /* WIFI_DIRECT_SUPPORT */
11462 }
11463 }
11464
11465 /* Enable interfaces */
11466 for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
11467 if (handle->priv[intf_num]) {
11468 netif_device_attach(handle->priv[intf_num]->netdev);
11469 woal_start_queue(handle->priv[intf_num]->netdev);
11470 }
11471 }
11472 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
11473 if (handle->country_code[0] && handle->country_code[1]) {
11474 memset(country_code, 0, sizeof(country_code));
11475 if (MTRUE ==
11476 is_cfg80211_special_region_code(handle->country_code)) {
11477 country_code[0] = 'W';
11478 country_code[1] = 'W';
11479 } else {
11480 country_code[0] = handle->country_code[0];
11481 country_code[1] = handle->country_code[1];
11482 }
11483
11484 if (handle->params.cntry_txpwr && priv)
11485 woal_request_country_power_table(priv, country_code);
11486 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
11487 if (handle->params.cntry_txpwr == CNTRY_RGPOWER_MODE)
11488 queue_work(handle->evt_workqueue,
11489 &handle->regulatory_work);
11490 #endif
11491 }
11492 #endif
11493
11494 done:
11495 if (handle->dpd_data) {
11496 release_firmware(handle->dpd_data);
11497 handle->dpd_data = NULL;
11498 }
11499 if (handle->txpwr_data) {
11500 release_firmware(handle->txpwr_data);
11501 handle->txpwr_data = NULL;
11502 }
11503 if (handle->user_data) {
11504 release_firmware(handle->user_data);
11505 handle->user_data = NULL;
11506 }
11507 LEAVE();
11508 return;
11509 }
11510
11511 /**
11512 * @brief This function reload fw
11513 *
11514 * @param phandle A pointer to moal_handle structure
11515 * @param mode FW reload mode
11516 *
11517 * @return 0--success, otherwise failure
11518 */
11519 int woal_request_fw_reload(moal_handle *phandle, t_u8 mode)
11520 {
11521 int ret = 0;
11522
11523 #ifdef PCIE
11524 ppcie_service_card card = NULL;
11525 struct pci_dev *pdev = NULL;
11526 #endif
11527 moal_handle *handle = phandle;
11528 moal_handle *ref_handle = NULL;
11529
11530 ENTER();
11531 wifi_status = WIFI_STATUS_FW_RELOAD;
11532 #ifdef PCIE
11533 if (mode == FW_RELOAD_PCIE_RESET) {
11534 card = (pcie_service_card *)handle->card;
11535 pdev = card->dev;
11536 if (pci_reset_function(pdev)) {
11537 PRINTM(MERROR, "%s: pci_reset_function failed \n",
11538 __func__);
11539 ret = -1;
11540 }
11541 LEAVE();
11542 return ret;
11543 }
11544 #endif
11545
11546 // handle-> mac0 , ref_handle->second mac
11547 if (handle->pref_mac) {
11548 if (phandle->second_mac) {
11549 handle = (moal_handle *)handle->pref_mac;
11550 ref_handle = phandle;
11551 } else {
11552 ref_handle = (moal_handle *)handle->pref_mac;
11553 }
11554 }
11555
11556 if (mode == FW_RELOAD_WITH_EMULATION) {
11557 fw_reload = FW_RELOAD_WITH_EMULATION;
11558 PRINTM(MMSG, "FW reload with re-emulation...\n");
11559 LEAVE();
11560 return ret;
11561 }
11562 woal_pre_reset(handle);
11563 if (ref_handle)
11564 woal_pre_reset(ref_handle);
11565 if (mode == FW_RELOAD_NO_EMULATION) {
11566 ret = woal_reload_fw(handle);
11567 if (ret) {
11568 PRINTM(MERROR, "woal_reload_fw fail\n");
11569 goto done;
11570 }
11571 if (ref_handle) {
11572 ret = woal_reload_fw(ref_handle);
11573 if (ret) {
11574 PRINTM(MERROR, "woal_reload_fw fail\n");
11575 goto done;
11576 }
11577 }
11578 }
11579 #ifdef SDIO_MMC
11580 else if ((mode == FW_RELOAD_SDIO_INBAND_RESET ||
11581 mode == FW_RELOAD_SDIO_HW_RESET) &&
11582 IS_SD(handle->card_type)) {
11583 ret = woal_reset_and_reload_fw(handle, mode);
11584 if (ret) {
11585 PRINTM(MERROR, "woal_reset_and_reload_fw fail\n");
11586 goto done;
11587 }
11588 if (ref_handle) {
11589 ret = woal_reload_fw(ref_handle);
11590 if (ret) {
11591 PRINTM(MERROR, "woal_reload_fw fail\n");
11592 goto done;
11593 }
11594 }
11595 }
11596 #endif
11597 else
11598 ret = -EFAULT;
11599 if (ret) {
11600 PRINTM(MERROR, "FW reload fail\n");
11601 goto done;
11602 }
11603 woal_post_reset(handle);
11604 if (ref_handle)
11605 woal_post_reset(ref_handle);
11606 wifi_status = WIFI_STATUS_OK;
11607 done:
11608 LEAVE();
11609 return ret;
11610 }
11611
11612 /**
11613 * @brief This function register to bus driver
11614 *
11615 * @param work a pointer to struct work_struct
11616 *
11617 * @return N/A
11618 */
11619 static void woal_bus_register(struct work_struct *work)
11620 {
11621 mlan_status ret = MLAN_STATUS_SUCCESS;
11622 PRINTM(MMSG, "wlan: Register to Bus Driver...\n");
11623 #ifdef SDIO
11624 #ifdef SDIO_MMC
11625 /* Register SDIO driver */
11626 ret = woal_sdiommc_bus_register();
11627 if (ret != MLAN_STATUS_SUCCESS) {
11628 PRINTM(MERROR, "Failed to register sdio_mmc bus driver\n");
11629 goto out;
11630 }
11631 #else
11632 ret = woal_sdio_bus_register();
11633 if (ret != MLAN_STATUS_SUCCESS) {
11634 PRINTM(MERROR, "Failed to register sdio_mmc bus driver\n");
11635 goto out;
11636 }
11637 #endif
11638 #endif
11639 #ifdef USB
11640 /* Register USB driver */
11641 ret = woal_usb_bus_register();
11642 if (ret != MLAN_STATUS_SUCCESS) {
11643 PRINTM(MERROR, "Failed to register usb bus driver\n");
11644 goto out;
11645 }
11646 #endif
11647 #ifdef PCIE
11648 /* Register PCIE driver */
11649 ret = woal_pcie_bus_register();
11650 if (ret != MLAN_STATUS_SUCCESS) {
11651 PRINTM(MERROR, "Failed to register pcie bus driver\n");
11652 goto out;
11653 }
11654 #endif
11655 PRINTM(MMSG, "wlan: Register to Bus Driver Done\n");
11656 out:
11657 return;
11658 }
11659
11660 /**
11661 * @brief This function unregister from bus driver
11662 *
11663 *
11664 * @return N/A
11665 */
11666 static void woal_bus_unregister(void)
11667 {
11668 #ifdef SDIO
11669 #ifdef SDIO_MMC
11670 /* Unregister SDIO driver */
11671 woal_sdiommc_bus_unregister();
11672 #else
11673 woal_sdio_bus_unregister();
11674 #endif
11675 #endif
11676 #ifdef USB
11677 /* Unregister USB driver */
11678 woal_usb_bus_unregister();
11679 #endif
11680 #ifdef PCIE
11681 /* Unregister PCIE driver */
11682 woal_pcie_bus_unregister();
11683 #endif
11684 }
11685
11686 /**
11687 * @brief This function initializes module.
11688 *
11689 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
11690 */
11691 static int woal_init_module(void)
11692 {
11693 int ret = (int)MLAN_STATUS_SUCCESS;
11694 int index = 0;
11695
11696 ENTER();
11697
11698 PRINTM(MMSG, "wlan: Loading MWLAN driver\n");
11699 /* Init the wlan_private pointer array first */
11700 for (index = 0; index < MAX_MLAN_ADAPTER; index++)
11701 m_handle[index] = NULL;
11702 /* Init mutex */
11703 MOAL_INIT_SEMAPHORE(&AddRemoveCardSem);
11704
11705 if (woal_root_proc_init() != MLAN_STATUS_SUCCESS) {
11706 PRINTM(MERROR,
11707 "woal_init_module: Unable to create /proc/mwlan/ directory\n");
11708 LEAVE();
11709 return -EFAULT;
11710 }
11711
11712 #ifdef CONFIG_OF
11713 woal_init_from_dev_tree();
11714 #endif
11715
11716 /* Create workqueue for hang process */
11717 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
11718 /* For kernel less than 2.6.14 name can not be greater than 10
11719 characters */
11720 hang_workqueue = create_workqueue("MOAL_HANG_WORKQ");
11721 #else
11722 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
11723 hang_workqueue =
11724 alloc_workqueue("MOAL_HANG_WORK_QUEUE",
11725 WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
11726 #else
11727 hang_workqueue = create_workqueue("MOAL_HANG_WORK_QUEUE");
11728 #endif
11729 #endif
11730 MLAN_INIT_WORK(&hang_work, woal_hang_work_queue);
11731
11732 if (reg_work) {
11733 /* Create workqueue for hang process */
11734 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
11735 /* For kernel less than 2.6.14 name can not be greater than 10
11736 characters */
11737 register_workqueue = create_workqueue("MOAL_REGISTER_WORKQ");
11738 #else
11739 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
11740 register_workqueue = alloc_workqueue(
11741 "MOAL_REGISTER_WORK_QUEUE",
11742 WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
11743 #else
11744 register_workqueue =
11745 create_workqueue("MOAL_REGISTER_WORK_QUEUE");
11746 #endif
11747 #endif
11748
11749 MLAN_INIT_WORK(®ister_work, woal_bus_register);
11750 queue_work(register_workqueue, ®ister_work);
11751 } else {
11752 woal_bus_register(NULL);
11753 }
11754 PRINTM(MMSG, "wlan: Driver loaded successfully\n");
11755 LEAVE();
11756 return ret;
11757 }
11758
11759 /**
11760 * @brief This function cleans module
11761 *
11762 * @return N/A
11763 */
11764 static void woal_cleanup_module(void)
11765 {
11766 moal_handle *handle = NULL;
11767 int index = 0;
11768 int i;
11769 #if defined(STA_SUPPORT) && defined(STA_CFG80211)
11770 unsigned long flags;
11771 #endif
11772
11773 ENTER();
11774
11775 PRINTM(MMSG, "wlan: Unloading MWLAN driver\n");
11776 if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
11777 goto exit_sem_err;
11778 for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
11779 handle = m_handle[index];
11780 if (!handle)
11781 continue;
11782 if (!handle->priv_num)
11783 goto exit;
11784 if (MTRUE == woal_check_driver_status(handle))
11785 goto exit;
11786
11787 #ifdef USB
11788 #ifdef CONFIG_USB_SUSPEND
11789 if (IS_USB(handle->card_type) &&
11790 handle->is_suspended == MTRUE) {
11791 woal_exit_usb_suspend(handle);
11792 }
11793 #endif /* CONFIG_USB_SUSPEND */
11794 #endif
11795
11796 #ifdef SDIO
11797 #ifdef SDIO_SUSPEND_RESUME
11798 #ifdef MMC_PM_KEEP_POWER
11799 if (handle->is_suspended == MTRUE) {
11800 woal_sdio_resume(
11801 &(((struct sdio_mmc_card *)handle->card)->func)
11802 ->dev);
11803 }
11804 #endif /* MMC_PM_KEEP_POWER */
11805 #endif /* SDIO_SUSPEND_RESUME */
11806 #endif
11807
11808 if (handle->rf_test_mode)
11809 woal_process_rf_test_mode(handle,
11810 MFG_CMD_UNSET_TEST_MODE);
11811 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
11812 /* Unregister all connected radiotap net devices */
11813 if (handle->mon_if) {
11814 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
11815 woal_set_net_monitor(handle->mon_if->priv,
11816 MOAL_IOCTL_WAIT, MFALSE, 0, NULL);
11817 if (handle->ioctl_timeout) {
11818 woal_ioctl_timeout(handle);
11819 goto exit;
11820 }
11821 #endif
11822 netif_device_detach(handle->mon_if->mon_ndev);
11823 if (handle->mon_if->mon_ndev->reg_state ==
11824 NETREG_REGISTERED)
11825 unregister_netdev(handle->mon_if->mon_ndev);
11826 handle->mon_if = NULL;
11827 }
11828 #endif
11829
11830 for (i = 0; i < handle->priv_num; i++) {
11831 /** cancel dfs monitor on deinit */
11832 if (handle->priv[i] &&
11833 handle->priv[i]->bss_type == MLAN_BSS_TYPE_DFS) {
11834 woal_11h_cancel_chan_report_ioctl(
11835 handle->priv[i], MOAL_IOCTL_WAIT);
11836 continue;
11837 }
11838 #ifdef STA_SUPPORT
11839 if (GET_BSS_ROLE(handle->priv[i]) ==
11840 MLAN_BSS_ROLE_STA) {
11841 if (handle->priv[i]->media_connected == MTRUE) {
11842 woal_disconnect(handle->priv[i],
11843 MOAL_IOCTL_WAIT_TIMEOUT,
11844 NULL,
11845 DEF_DEAUTH_REASON_CODE);
11846 if (handle->ioctl_timeout) {
11847 woal_ioctl_timeout(handle);
11848 goto exit;
11849 }
11850 }
11851 #ifdef STA_CFG80211
11852 if (IS_STA_CFG80211(
11853 handle->params.cfg80211_wext))
11854 woal_clear_conn_params(handle->priv[i]);
11855 spin_lock_irqsave(&handle->scan_req_lock,
11856 flags);
11857 if (IS_STA_CFG80211(
11858 handle->params.cfg80211_wext) &&
11859 handle->scan_request) {
11860 cancel_delayed_work(
11861 &handle->scan_timeout_work);
11862 woal_cfg80211_scan_done(
11863 handle->scan_request, MTRUE);
11864 handle->scan_request = NULL;
11865 handle->scan_priv = NULL;
11866 }
11867 spin_unlock_irqrestore(&handle->scan_req_lock,
11868 flags);
11869 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
11870 if (IS_STA_CFG80211(
11871 handle->params.cfg80211_wext) &&
11872 handle->priv[i]->sched_scanning) {
11873 woal_stop_bg_scan(
11874 handle->priv[i],
11875 MOAL_IOCTL_WAIT_TIMEOUT);
11876 if (handle->ioctl_timeout) {
11877 woal_ioctl_timeout(handle);
11878 goto exit;
11879 }
11880 handle->priv[i]->bg_scan_start = MFALSE;
11881 handle->priv[i]->bg_scan_reported =
11882 MFALSE;
11883 cfg80211_sched_scan_stopped(
11884 handle->priv[i]->wdev->wiphy
11885 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
11886 ,
11887 handle->priv[i]->bg_scan_reqid
11888 #endif
11889 );
11890 handle->priv[i]->sched_scanning =
11891 MFALSE;
11892 }
11893 #endif
11894 #endif
11895 }
11896 #endif
11897 #ifdef UAP_SUPPORT
11898 if (GET_BSS_ROLE(handle->priv[i]) ==
11899 MLAN_BSS_ROLE_UAP) {
11900 #ifdef MFG_CMD_SUPPORT
11901 if (handle->params.mfg_mode !=
11902 MLAN_INIT_PARA_ENABLED)
11903 #endif
11904 {
11905 woal_disconnect(handle->priv[i],
11906 MOAL_IOCTL_WAIT_TIMEOUT,
11907 NULL,
11908 DEF_DEAUTH_REASON_CODE);
11909 if (handle->ioctl_timeout) {
11910 woal_ioctl_timeout(handle);
11911 goto exit;
11912 }
11913 }
11914 }
11915 #endif
11916 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
11917 woal_clear_all_mgmt_ies(handle->priv[i],
11918 MOAL_IOCTL_WAIT_TIMEOUT);
11919 if (handle->ioctl_timeout) {
11920 woal_ioctl_timeout(handle);
11921 goto exit;
11922 }
11923 woal_flush_tx_stat_queue(handle->priv[i]);
11924 #endif
11925 }
11926
11927 #ifdef MFG_CMD_SUPPORT
11928 if (handle->params.mfg_mode != MLAN_INIT_PARA_ENABLED)
11929 #endif
11930 {
11931 woal_set_deep_sleep(woal_get_priv(handle,
11932 MLAN_BSS_ROLE_ANY),
11933 MOAL_IOCTL_WAIT_TIMEOUT, MFALSE, 0);
11934 }
11935
11936 #ifdef MFG_CMD_SUPPORT
11937 if (handle->params.mfg_mode != MLAN_INIT_PARA_ENABLED)
11938 #endif
11939 {
11940 woal_shutdown_fw(woal_get_priv(handle,
11941 MLAN_BSS_ROLE_ANY),
11942 MOAL_IOCTL_WAIT_TIMEOUT);
11943 if (handle->ioctl_timeout) {
11944 woal_ioctl_timeout(handle);
11945 goto exit;
11946 }
11947 }
11948 }
11949
11950 exit:
11951 MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
11952 exit_sem_err:
11953 /* Unregister from bus */
11954 woal_bus_unregister();
11955 PRINTM(MMSG, "wlan: Driver unloaded\n");
11956 if (hang_workqueue) {
11957 flush_workqueue(hang_workqueue);
11958 destroy_workqueue(hang_workqueue);
11959 hang_workqueue = NULL;
11960 }
11961 if (reg_work && register_workqueue) {
11962 flush_workqueue(register_workqueue);
11963 destroy_workqueue(register_workqueue);
11964 register_workqueue = NULL;
11965 }
11966
11967 woal_root_proc_remove();
11968
11969 LEAVE();
11970 }
11971
11972 #ifndef MODULE
11973 #ifdef MFG_CMD_SUPPORT
11974 /**
11975 * @brief This function handle the mfg_mode from kernel boot command
11976 *
11977 * @param str buffer for mfg_mode
11978 * @return N/A
11979 */
11980 static int __init mfg_mode_setup(char *str)
11981 {
11982 int val = -1;
11983 get_option(&str, &val);
11984 if (val > 0)
11985 mfg_mode = 1;
11986 PRINTM(MMSG, "mfg_mode=%d\n", mfg_mode);
11987 return 1;
11988 }
11989 __setup("mfg_mode=", mfg_mode_setup);
11990 #endif
11991 #endif
11992
11993 module_init(woal_init_module);
11994 module_exit(woal_cleanup_module);
11995
11996 module_param(reg_work, int, 0);
11997 MODULE_PARM_DESC(
11998 reg_work,
11999 "0: disable register work_queue; 1: enable register work_queue");
12000
12001 MODULE_DESCRIPTION("M-WLAN Driver");
12002 MODULE_AUTHOR("NXP");
12003 MODULE_VERSION(MLAN_RELEASE_VERSION);
12004 MODULE_LICENSE("GPL");
12005 MODULE_LICENSE("GPL");
12006