xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlinux/moal_main.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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(&param, 0, sizeof(mlan_init_param));
3946 
3947 	ret = woal_req_dpd_data(handle, &param);
3948 	if (ret != MLAN_STATUS_SUCCESS)
3949 		goto done;
3950 
3951 	ret = woal_req_txpwr_data(handle, &param);
3952 	if (ret != MLAN_STATUS_SUCCESS)
3953 		goto done;
3954 
3955 	ret = woal_req_cal_data(handle, &param);
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, &param);
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(&register_work, woal_bus_register);
11750 		queue_work(register_workqueue, &register_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