xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/mvl88w8977/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   * Copyright (C) 2008-2017, Marvell International Ltd.
7   *
8   * This software file (the "File") is distributed by Marvell International
9   * Ltd. under the terms of the GNU General Public License Version 2, June 1991
10   * (the "License").  You may use, redistribute and/or modify this File in
11   * accordance with the terms and conditions of the License, a copy of which
12   * is available by writing to the Free Software Foundation, Inc.,
13   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
14   * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
15   *
16   * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
17   * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
18   * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
19   * this warranty disclaimer.
20   *
21   */
22 
23 /********************************************************
24 Change log:
25     10/21/2008: initial version
26 ********************************************************/
27 
28 #include	"moal_main.h"
29 #include    "moal_sdio.h"
30 #ifdef UAP_SUPPORT
31 #include    "moal_uap.h"
32 #endif
33 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
34 #include    "moal_cfg80211.h"
35 #include    "moal_cfgvendor.h"
36 #endif
37 #ifdef STA_CFG80211
38 #ifdef STA_SUPPORT
39 #include    "moal_sta_cfg80211.h"
40 #endif
41 #endif
42 #ifdef UAP_CFG80211
43 #ifdef UAP_SUPPORT
44 #include    "moal_uap_cfg80211.h"
45 #endif
46 #endif
47 #include "moal_eth_ioctl.h"
48 
49 #include <linux/if_ether.h>
50 #include <linux/in.h>
51 #include <linux/tcp.h>
52 #include <net/tcp.h>
53 #include <net/dsfield.h>
54 
55 #ifdef CONFIG_OF
56 #include <linux/of.h>
57 #endif
58 
59 /********************************************************
60 		Local Variables
61 ********************************************************/
62 
63 #define KERN_VERSION    "4X"
64 
65 /** Driver version */
66 char driver_version[] =
67 	"SD8977-%s-C" KERN_VERSION "16" MLAN_RELEASE_VERSION
68 	"-GPL" "-(" "FP" FPNUM ")"
69 #ifdef	DEBUG_LEVEL2
70 	"-dbg"
71 #endif
72 	" ";
73 
74 /** Firmware name */
75 char *fw_name;
76 int req_fw_nowait;
77 int fw_reload;
78 
79 /** MAC address */
80 char *mac_addr;
81 
82 #ifdef MFG_CMD_SUPPORT
83 /** Mfg mode */
84 int mfg_mode;
85 #endif
86 
87 /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
88 int intmode = INT_MODE_SDIO;
89 /** GPIO interrupt pin number */
90 int gpiopin;
91 
92 #ifdef CONFIG_OF
93 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
94 /** Region alpha2 string */
95 extern char *reg_alpha2;
96 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
97 extern int country_ie_ignore;
98 extern int beacon_hints;
99 #endif
100 #endif
101 extern int cfg80211_drcs;
102 #endif
103 
104 int drcs_chantime_mode = 0;
105 
106 /** Auto deep sleep */
107 int auto_ds;
108 
109 /** IEEE PS mode */
110 int ps_mode;
111 
112 /** Max Tx buffer size */
113 int max_tx_buf;
114 
115 #ifdef STA_SUPPORT
116 /** Max STA interfaces */
117 int max_sta_bss = DEF_STA_BSS;
118 /** STA interface name */
119 char *sta_name;
120 #endif
121 
122 #ifdef UAP_SUPPORT
123 /** Max uAP interfaces */
124 int max_uap_bss = DEF_UAP_BSS;
125 /** uAP interface name */
126 char *uap_name;
127 #endif
128 
129 #if defined(WIFI_DIRECT_SUPPORT)
130 /** Max WIFIDIRECT interfaces */
131 int max_wfd_bss = DEF_WIFIDIRECT_BSS;
132 /** WIFIDIRECT interface name */
133 char *wfd_name;
134 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
135 /** max VIRTUAL bss */
136 int max_vir_bss = DEF_VIRTUAL_BSS;
137 #endif
138 #endif
139 
140 /** Max NAN interfaces */
141 int max_nan_bss = DEF_NAN_BSS;
142 /** NAN interface name */
143 char *nan_name;
144 
145 #ifdef SDIO_SUSPEND_RESUME
146 /** PM keep power */
147 int pm_keep_power = 1;
148 /** HS when shutdown */
149 int shutdown_hs;
150 #endif
151 
152 #if defined(STA_SUPPORT)
153 /** 802.11d configuration */
154 int cfg_11d;
155 #endif
156 
157 /** fw serial download check */
158 int fw_serial = 1;
159 
160 /** napi support*/
161 int napi;
162 
163 /** DPD data config file */
164 char *dpd_data_cfg;
165 
166 /** CAL data config file */
167 char *cal_data_cfg;
168 /** Init config file (MAC address, register etc.) */
169 char *init_cfg;
170 
171 /** Set configuration data of Tx power limitation */
172 char *txpwrlimit_cfg;
173 /** Set configuration data of Tx power limitatio */
174 char *country_txpwrlimit;
175 /** Allow setting tx power table of country */
176 int cntry_txpwr = 0;
177 
178 /** Init hostcmd file */
179 char *init_hostcmd_cfg;
180 
181 #if defined(STA_WEXT) || defined(UAP_WEXT)
182 /** CFG80211 and WEXT mode */
183 int cfg80211_wext = STA_WEXT_MASK | UAP_WEXT_MASK;
184 #else
185 /** CFG80211 mode */
186 int cfg80211_wext = STA_CFG80211_MASK | UAP_CFG80211_MASK;
187 #endif
188 
189 int fw_region = 1;
190 
191 /** Work queue priority */
192 int wq_sched_prio;
193 /** Work queue scheduling policy */
194 int wq_sched_policy = SCHED_NORMAL;
195 /** rx_work flag */
196 int rx_work;
197 
198 int hw_test;
199 
200 #ifdef CONFIG_OF
201 int dts_enable = 1;
202 #endif
203 
204 #if defined(WIFI_DIRECT_SUPPORT)
205 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
206 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
207 int p2p_enh;
208 #endif
209 #endif
210 #endif
211 
212 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
213 int dfs_offload = 0;
214 #endif
215 
216 int roamoffload_in_hs = 0;
217 
218 #ifdef ANDROID_KERNEL
219 int wakelock_timeout = WAKE_LOCK_TIMEOUT;
220 #endif
221 
222 /** woal_callbacks */
223 static mlan_callbacks woal_callbacks = {
224 	.moal_get_fw_data = moal_get_fw_data,
225 	.moal_get_hw_spec_complete = moal_get_hw_spec_complete,
226 	.moal_init_fw_complete = moal_init_fw_complete,
227 	.moal_shutdown_fw_complete = moal_shutdown_fw_complete,
228 	.moal_send_packet_complete = moal_send_packet_complete,
229 	.moal_recv_packet = moal_recv_packet,
230 	.moal_recv_event = moal_recv_event,
231 	.moal_ioctl_complete = moal_ioctl_complete,
232 	.moal_alloc_mlan_buffer = moal_alloc_mlan_buffer,
233 	.moal_free_mlan_buffer = moal_free_mlan_buffer,
234 
235 	.moal_write_reg = moal_write_reg,
236 	.moal_read_reg = moal_read_reg,
237 	.moal_write_data_sync = moal_write_data_sync,
238 	.moal_read_data_sync = moal_read_data_sync,
239 	.moal_malloc = moal_malloc,
240 	.moal_mfree = moal_mfree,
241 	.moal_vmalloc = moal_vmalloc,
242 	.moal_vfree = moal_vfree,
243 	.moal_memset = moal_memset,
244 	.moal_memcpy = moal_memcpy,
245 	.moal_memmove = moal_memmove,
246 	.moal_memcmp = moal_memcmp,
247 	.moal_udelay = moal_udelay,
248 	.moal_get_system_time = moal_get_system_time,
249 	.moal_init_timer = moal_init_timer,
250 	.moal_free_timer = moal_free_timer,
251 	.moal_start_timer = moal_start_timer,
252 	.moal_stop_timer = moal_stop_timer,
253 	.moal_init_lock = moal_init_lock,
254 	.moal_free_lock = moal_free_lock,
255 	.moal_spin_lock = moal_spin_lock,
256 	.moal_spin_unlock = moal_spin_unlock,
257 	.moal_print = moal_print,
258 	.moal_print_netintf = moal_print_netintf,
259 	.moal_assert = moal_assert,
260 	.moal_hist_data_add = moal_hist_data_add,
261 	.moal_updata_peer_signal = moal_updata_peer_signal,
262 	.moal_get_host_time_ns = moal_get_host_time_ns,
263 	.moal_do_div = moal_do_div,
264 };
265 
266 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
267 #if defined(WIFI_DIRECT_SUPPORT)
268 int drv_mode = (DRV_MODE_STA | DRV_MODE_UAP | DRV_MODE_WIFIDIRECT);
269 #else
270 int drv_mode = (DRV_MODE_STA | DRV_MODE_UAP);
271 #endif
272 #else
273 #ifdef STA_SUPPORT
274 int drv_mode = DRV_MODE_STA;
275 #else
276 int drv_mode = DRV_MODE_UAP;
277 #endif /* STA_SUPPORT */
278 #endif /* STA_SUPPORT & UAP_SUPPORT */
279 
280 int gtk_rekey_offload = GTK_REKEY_OFFLOAD_DISABLE;
281 
282 int pmic = 0;
283 
284 t_u32 uap_oper_ctrl = 0;
285 
286 int hs_wake_interval = 400;
287 int indication_gpio = 0xff;
288 
289 int indrstcfg = 0xffffffff;
290 
291 /** all the feature are enabled */
292 #define DEFAULT_DEV_CAP_MASK 0xffffffff
293 t_u32 dev_cap_mask = DEFAULT_DEV_CAP_MASK;
294 int sdio_rx_aggr = MTRUE;
295 /********************************************************
296 		Global Variables
297 ********************************************************/
298 
299 /** Semaphore for add/remove card */
300 struct semaphore AddRemoveCardSem;
301 /**
302  * The global variable of a pointer to moal_handle
303  * structure variable
304  **/
305 moal_handle *m_handle[MAX_MLAN_ADAPTER];
306 
307 /** The global variable of scan beacon buffer **/
308 int fixed_beacon_buffer = 0;
309 /** the pointer of new fwdump fname for each dump**/
310 char *fwdump_fname = NULL;
311 
312 #ifdef WIFI_DIRECT_SUPPORT
313 int GoAgeoutTime = 0;
314 #endif
315 
316 int multi_dtim = 0;
317 
318 int inact_tmo = 0;
319 
320 #ifdef DEBUG_LEVEL1
321 #ifdef DEBUG_LEVEL2
322 #define	DEFAULT_DEBUG_MASK	(0xffffffff)
323 #else
324 #define DEFAULT_DEBUG_MASK	(MMSG | MFATAL | MERROR)
325 #endif /* DEBUG_LEVEL2 */
326 t_u32 drvdbg = DEFAULT_DEBUG_MASK;
327 
328 #endif /* DEBUG_LEVEL1 */
329 
330 int woal_open(struct net_device *dev);
331 int woal_close(struct net_device *dev);
332 int woal_set_mac_address(struct net_device *dev, void *addr);
333 void woal_tx_timeout(struct net_device *dev);
334 struct net_device_stats *woal_get_stats(struct net_device *dev);
335 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
336 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
337 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
338 u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb,
339 		      void *accel_priv, select_queue_fallback_t fallback);
340 #else
341 u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb,
342 		      void *accel_priv);
343 #endif
344 #else
345 u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb);
346 #endif
347 #endif
348 
349 void woal_sdio_reg_dbg(moal_handle *phandle);
350 
351 mlan_debug_info info;
352 
353 static moal_handle *reset_handle;
354 /** Hang workqueue */
355 static struct workqueue_struct *hang_workqueue;
356 /** Hang work */
357 static struct work_struct hang_work;
358 
359 /**
360  *  @brief This function process FW hang
361  *
362  *  @param handle       Pointer to structure moal_handle
363  *
364  *  @return        N/A
365  */
366 static void
woal_hang_work_queue(struct work_struct * work)367 woal_hang_work_queue(struct work_struct *work)
368 {
369 	int i;
370 	ENTER();
371 	if (!reset_handle) {
372 		LEAVE();
373 		return;
374 	}
375 	for (i = 0; i < reset_handle->priv_num; i++) {
376 		if (reset_handle->priv[i] && reset_handle->priv[i]->netdev) {
377 			PRINTM(MMSG, "Close netdev %s\n",
378 			       reset_handle->priv[i]->netdev->name);
379 			rtnl_lock();
380 			dev_close(reset_handle->priv[i]->netdev);
381 			rtnl_unlock();
382 			break;
383 		}
384 	}
385 	reset_handle = NULL;
386 	LEAVE();
387 }
388 
389 /**
390  *  @brief This function process FW hang
391  *
392  *  @param handle       Pointer to structure moal_handle
393  *
394  *  @return        N/A
395  */
396 void
woal_process_hang(moal_handle * handle)397 woal_process_hang(moal_handle *handle)
398 {
399 	ENTER();
400 	if (reset_handle == NULL) {
401 		PRINTM(MMSG, "Start to process hanging\n");
402 		reset_handle = handle;
403 		mlan_ioctl(handle->pmlan_adapter, NULL);
404 		queue_work(hang_workqueue, &hang_work);
405 #ifdef ANDROID_KERNEL
406 #define WAKE_LOCK_HANG 5000
407 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
408 		__pm_wakeup_event(&reset_handle->ws, WAKE_LOCK_HANG);
409 #else
410 		wake_lock_timeout(&reset_handle->wake_lock, WAKE_LOCK_HANG);
411 #endif
412 #endif
413 	}
414 	LEAVE();
415 }
416 
417 /**
418  *  @brief Check if any interface is active
419  *
420  *  @param handle        A pointer to moal_handle
421  *
422  *
423  *  @return              MTRUE/MFALSE;
424  */
425 t_u8
woal_is_any_interface_active(moal_handle * handle)426 woal_is_any_interface_active(moal_handle *handle)
427 {
428 	int i;
429 	for (i = 0; i < handle->priv_num; i++) {
430 #ifdef STA_SUPPORT
431 		if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) {
432 			if (handle->priv[i]->media_connected == MTRUE)
433 				return MTRUE;
434 		}
435 #endif
436 #ifdef UAP_SUPPORT
437 		if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) {
438 			if (handle->priv[i]->bss_started == MTRUE)
439 				return MTRUE;
440 		}
441 #endif
442 	}
443 	return MFALSE;
444 }
445 
446 /**  @brief This function set/clear pmk to FW
447  *
448  *  @param priv     A Pointer to the moal_private structure
449  *  @param action     set/clear action
450  *
451  *  @return      0: success  fail otherwise
452  */
453 int
woal_set_clear_pmk(moal_private * priv,t_u8 action)454 woal_set_clear_pmk(moal_private *priv, t_u8 action)
455 {
456 	mlan_ioctl_req *req;
457 	mlan_ds_sec_cfg *sec;
458 	mlan_status status;
459 	int ret = 0;
460 	t_u8 zero[MLAN_MAX_KEY_LENGTH] = { 0 };
461 	ENTER();
462 
463 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
464 
465 	if (req == NULL) {
466 		ret = -ENOMEM;
467 	} else {
468 		sec = (mlan_ds_sec_cfg *)req->pbuf;
469 		sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
470 		req->req_id = MLAN_IOCTL_SEC_CFG;
471 		req->action = action;
472 
473 		if (action == MLAN_ACT_SET) {
474 			sec->param.passphrase.psk_type = MLAN_PSK_PMK;
475 			if (memcmp(priv->pmk.pmk, zero, MLAN_MAX_KEY_LENGTH))
476 				memcpy(&sec->param.passphrase.psk.pmk.pmk,
477 				       priv->pmk.pmk, MLAN_MAX_KEY_LENGTH);
478 			if (memcmp(priv->pmk.pmk_r0, zero, MLAN_MAX_KEY_LENGTH)
479 			    && memcmp(priv->pmk.pmk_r0_name, zero,
480 				      MLAN_MAX_PMKR0_NAME_LENGTH)) {
481 				memcpy(&sec->param.passphrase.psk.pmk.pmk_r0,
482 				       priv->pmk.pmk_r0, MLAN_MAX_KEY_LENGTH);
483 				memcpy(&sec->param.passphrase.psk.pmk.
484 				       pmk_r0_name, priv->pmk.pmk_r0_name,
485 				       MLAN_MAX_PMKR0_NAME_LENGTH);
486 			}
487 		}
488 
489 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
490 		if (MLAN_STATUS_SUCCESS != status)
491 			ret = -EFAULT;
492 		if (status != MLAN_STATUS_PENDING)
493 			kfree(req);
494 	}
495 
496 	LEAVE();
497 	return ret;
498 }
499 
500 /**
501  *  @brief This function handle the net interface ipaddr change event
502  *
503  *  @param nb      pointer to the notifier_block
504  *  @param event   event type
505  *  @param ptr     pointer to event struct
506  *
507  *  @return        NOTIFY_DONE or NOTIFY_OK
508  */
509 static int
woal_netdevice_event(struct notifier_block * nb,unsigned long event,void * ptr)510 woal_netdevice_event(struct notifier_block *nb, unsigned long event, void *ptr)
511 {
512 	struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
513 	struct net_device *ndev;
514 	moal_private *priv;
515 
516 	int ret = NOTIFY_OK;
517 #ifdef STA_CFG80211
518 	char rssi_low[11];
519 #endif
520 	ENTER();
521 
522 	ndev = ifa->ifa_dev->dev;
523 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
524 	if (!ndev || ndev->netdev_ops->ndo_open != woal_open)
525 #else
526 	if (!ndev || ndev->open != woal_open)
527 #endif
528 	{
529 		PRINTM(MIOCTL, "IP changes not for us, ignore. ndev[%p]\n",
530 		       ndev);
531 		if (ndev)
532 			PRINTM(MIOCTL, "changes on %s\n", ndev->name);
533 		ret = NOTIFY_DONE;
534 		goto done;
535 	}
536 	priv = (moal_private *)netdev_priv(ndev);
537 	if (priv->bss_type != MLAN_BSS_TYPE_STA
538 #if defined(WIFI_DIRECT_SUPPORT)
539 	    && priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT
540 #endif
541 	    && priv->bss_type != MLAN_BSS_TYPE_NAN) {
542 		PRINTM(MIOCTL, "Bss type [%d] is not STA/P2P, ignore\n",
543 		       (int)priv->bss_type);
544 		ret = NOTIFY_DONE;
545 		goto done;
546 	}
547 
548 	switch (event) {
549 	case NETDEV_UP:
550 		PRINTM(MIOCTL, "[%s]: New ip addr: 0x%08x\n", ndev->name,
551 		       ifa->ifa_address);
552 		/* Save the IP addr now */
553 		memcpy(priv->ip_addr, &ifa->ifa_address,
554 		       sizeof(ifa->ifa_address));
555 		priv->ip_addr_type = IPADDR_TYPE_IPV4;
556 #ifdef STA_CFG80211
557 		if (!hw_test && priv->roaming_enabled) {
558 			sprintf(rssi_low, "%d", priv->rssi_low);
559 			woal_set_rssi_low_threshold(priv, rssi_low,
560 						    MOAL_IOCTL_WAIT);
561 		}
562 #endif
563 #ifdef STA_CFG80211
564 		if (priv->phandle->fw_roam_enable &&
565 		    (priv->phandle->fw_roam_enable != AUTO_RECONNECT)
566 		    && !roamoffload_in_hs) {
567 			sprintf(rssi_low, "%d", priv->rssi_low);
568 			woal_set_rssi_low_threshold(priv, rssi_low,
569 						    MOAL_IOCTL_WAIT);
570 			if (priv->pmk_saved) {
571 				woal_set_clear_pmk(priv, MLAN_ACT_SET);
572 				priv->pmk_saved = false;
573 			}
574 		}
575 #endif
576 		break;
577 	case NETDEV_DOWN:
578 		PRINTM(MIOCTL, "[%s]: Ip addr removed.\n", ndev->name);
579 		priv->ip_addr_type = IPADDR_TYPE_NONE;
580 		memset(priv->ip_addr, 0, sizeof(priv->ip_addr));
581 		break;
582 	default:
583 		PRINTM(MIOCTL, "[%s]: Ignore event: %u\n", ndev->name,
584 		       (unsigned int)event);
585 		ret = NOTIFY_DONE;
586 		goto done;
587 	}
588 
589 done:
590 	LEAVE();
591 	return ret;
592 }
593 
594 /**
595  *  @brief This function validates a SSID as being able to be printed
596  *
597  *  @param pssid   SSID structure to validate
598  *
599  *  @return        MTRUE or MFALSE
600  */
601 BOOLEAN
woal_ssid_valid(mlan_802_11_ssid * pssid)602 woal_ssid_valid(mlan_802_11_ssid *pssid)
603 {
604 #ifdef ASCII_SSID_CHECK
605 	unsigned int ssid_idx;
606 
607 	ENTER();
608 
609 	for (ssid_idx = 0; ssid_idx < pssid->ssid_len; ssid_idx++) {
610 		if ((pssid->ssid[ssid_idx] < 0x20) ||
611 		    (pssid->ssid[ssid_idx] > 0x7e)) {
612 			LEAVE();
613 			return MFALSE;
614 		}
615 	}
616 	LEAVE();
617 #endif
618 	return MTRUE;
619 }
620 
621 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
622 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
623 /**
624  *  @brief Remain on Channel timeout function
625  *
626  *  @param context  A pointer to context
627  *  @return         N/A
628  */
629 void
woal_remain_timer_func(void * context)630 woal_remain_timer_func(void *context)
631 {
632 	moal_handle *handle = (moal_handle *)context;
633 	moal_private *priv = handle->priv[handle->remain_bss_index];
634 
635 	ENTER();
636 
637 	PRINTM(MEVENT, "remain_timer fired.\n");
638 	if (handle->cookie) {
639 		cfg80211_remain_on_channel_expired(
640 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
641 							  priv->netdev,
642 #else
643 							  priv->wdev,
644 #endif
645 							  handle->cookie,
646 							  &handle->chan,
647 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
648 							  handle->channel_type,
649 #endif
650 							  GFP_ATOMIC);
651 		handle->cookie = 0;
652 	}
653 	handle->is_remain_timer_set = MFALSE;
654 
655 	LEAVE();
656 	return;
657 }
658 #endif
659 #endif
660 
661 #if defined(WIFI_DIRECT_SUPPORT)
662 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
663 /**
664  *  @brief GO timeout function
665  *
666  *  @param context  A pointer to context
667  *  @return         N/A
668  */
669 void
woal_go_timer_func(void * context)670 woal_go_timer_func(void *context)
671 {
672 	moal_handle *handle = (moal_handle *)context;
673 
674 	ENTER();
675 
676 	PRINTM(MEVENT, "go_timer fired.\n");
677 	handle->is_go_timer_set = MFALSE;
678 
679 	LEAVE();
680 	return;
681 }
682 #endif
683 #endif
684 
685 /**
686  *  @brief check if we already connect to the AP.
687  *  @param priv         A pointer to moal_private structure
688  *  @param ssid_bssid   A pointer to mlan_ssid_bssid structure
689  *
690  *  @return             MTRUE/MFALSE;
691  */
692 int
woal_is_connected(moal_private * priv,mlan_ssid_bssid * ssid_bssid)693 woal_is_connected(moal_private *priv, mlan_ssid_bssid *ssid_bssid)
694 {
695 	mlan_bss_info bss_info;
696 	int ret = MFALSE;
697 	t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
698 	ENTER();
699 	memset(&bss_info, 0, sizeof(bss_info));
700 	if (MLAN_STATUS_SUCCESS !=
701 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info))
702 		goto done;
703 	if (bss_info.media_connected) {
704 		if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) {
705 			if (ssid_bssid->ssid.ssid_len) {	/* compare ssid and bssid */
706 				if ((ssid_bssid->ssid.ssid_len ==
707 				     bss_info.ssid.ssid_len) &&
708 				    !memcmp(ssid_bssid->ssid.ssid,
709 					    bss_info.ssid.ssid,
710 					    bss_info.ssid.ssid_len) &&
711 				    !memcmp(ssid_bssid->bssid, bss_info.bssid,
712 					    MLAN_MAC_ADDR_LENGTH))
713 					ret = MTRUE;
714 			} else {	/* compare bssid */
715 				if (!memcmp
716 				    (ssid_bssid->bssid, bss_info.bssid,
717 				     MLAN_MAC_ADDR_LENGTH)) {
718 					memcpy(&ssid_bssid->ssid,
719 					       &bss_info.ssid,
720 					       sizeof(bss_info.ssid));
721 					ret = MTRUE;
722 				}
723 			}
724 		} else {	/* compare ssid */
725 			if (ssid_bssid->ssid.ssid_len &&
726 			    (ssid_bssid->ssid.ssid_len ==
727 			     bss_info.ssid.ssid_len) &&
728 			    !memcmp(ssid_bssid->ssid.ssid, bss_info.ssid.ssid,
729 				    bss_info.ssid.ssid_len)) {
730 				memcpy(&ssid_bssid->bssid, &bss_info.bssid,
731 				       MLAN_MAC_ADDR_LENGTH);
732 				ret = MTRUE;
733 			}
734 		}
735 	}
736 done:
737 	LEAVE();
738 	return ret;
739 }
740 
741 /**
742  * @brief Look up specific IE in a buf
743  *
744  * @param ie              Pointer to IEs
745  * @param len             Total length of ie
746  * @param id              Element id to lookup
747  *
748  * @return                Pointer of the specific IE -- success, NULL -- fail
749  */
750 const t_u8 *
woal_parse_ie_tlv(const t_u8 * ie,int len,t_u8 id)751 woal_parse_ie_tlv(const t_u8 *ie, int len, t_u8 id)
752 {
753 	int left_len = len;
754 	const t_u8 *pos = ie;
755 	int length;
756 
757 	/* IE format:
758 	 * |   u8  |   id   |
759 	 * |   u8  |   len  |
760 	 * |   var |   data |
761 	 */
762 	while (left_len >= 2) {
763 		length = *(pos + 1);
764 		if ((*pos == id) && (length + 2) <= left_len)
765 			return pos;
766 		pos += (length + 2);
767 		left_len -= (length + 2);
768 	}
769 
770 	return NULL;
771 }
772 
773 /**
774  *  @brief Get mode
775  *
776  *  @param priv          A pointer to moal_private structure
777  *  @param wait_option   Wait option (MOAL_IOCTL_WAIT or MOAL_NO_WAIT)
778  *
779  *  @return              Wireless mode
780  */
781 t_u32
woal_get_mode(moal_private * priv,t_u8 wait_option)782 woal_get_mode(moal_private *priv, t_u8 wait_option)
783 {
784 	int ret = 0;
785 	mlan_ds_bss *bss = NULL;
786 	mlan_ioctl_req *req = NULL;
787 	mlan_status status = MLAN_STATUS_SUCCESS;
788 	t_u32 mode = 0;
789 
790 	ENTER();
791 
792 #if defined(STA_WEXT) || defined(UAP_WEXT)
793 	mode = priv->w_stats.status;
794 #endif
795 	/* Allocate an IOCTL request buffer */
796 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
797 	if (req == NULL) {
798 		ret = -ENOMEM;
799 		goto done;
800 	}
801 
802 	/* Fill request buffer */
803 	bss = (mlan_ds_bss *)req->pbuf;
804 	bss->sub_command = MLAN_OID_BSS_MODE;
805 	req->req_id = MLAN_IOCTL_BSS;
806 	req->action = MLAN_ACT_GET;
807 
808 	/* Send IOCTL request to MLAN */
809 	status = woal_request_ioctl(priv, req, wait_option);
810 	if (status == MLAN_STATUS_SUCCESS) {
811 		switch (bss->param.bss_mode) {
812 		case MLAN_BSS_MODE_INFRA:
813 			mode = MW_MODE_INFRA;
814 			break;
815 		case MLAN_BSS_MODE_IBSS:
816 			mode = MW_MODE_ADHOC;
817 			break;
818 		default:
819 			mode = MW_MODE_AUTO;
820 			break;
821 		}
822 	}
823 done:
824 	if (status != MLAN_STATUS_PENDING)
825 		kfree(req);
826 	LEAVE();
827 	return mode;
828 }
829 
830 /********************************************************
831 		Local Functions
832 ********************************************************/
833 /**
834  *  @brief This function update the default firmware name
835  *
836  *  @param handle           A pointer to moal_handle structure
837  *
838  *  @return        N/A
839  */
840 static void
woal_update_firmware_name(moal_handle * handle)841 woal_update_firmware_name(moal_handle *handle)
842 {
843 	if (fw_name) {
844 		handle->drv_mode.fw_name = fw_name;
845 	} else {
846 		if (!fw_serial || handle->fw_reload || fw_reload)
847 			handle->drv_mode.fw_name = DEFAULT_WLAN_FW_NAME;
848 		else
849 #if defined(UAP_SUPPORT) && defined(STA_SUPPORT)
850 			handle->drv_mode.fw_name = DEFAULT_AP_STA_FW_NAME;
851 #else
852 #ifdef UAP_SUPPORT
853 			handle->drv_mode.fw_name = DEFAULT_AP_FW_NAME;
854 #else
855 			handle->drv_mode.fw_name = DEFAULT_FW_NAME;
856 #endif /* UAP_SUPPORT */
857 #endif /* UAP_SUPPORT && STA_SUPPORT */
858 	}
859 }
860 
861 /**
862  *  @brief This function dynamically populates the driver mode table
863  *
864  *  @param handle           A pointer to moal_handle structure
865  *  @param drv_mode_local   Driver mode
866  *
867  *  @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
868  */
869 mlan_status
woal_update_drv_tbl(moal_handle * handle,int drv_mode_local)870 woal_update_drv_tbl(moal_handle *handle, int drv_mode_local)
871 {
872 	mlan_status ret = MLAN_STATUS_SUCCESS;
873 	unsigned int intf_num = 0;
874 	int i = 0, j = 0;
875 	mlan_bss_attr *bss_tbl = NULL;
876 #if defined(WIFI_DIRECT_SUPPORT)
877 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
878 	int last_wfd_index = 0;
879 #endif
880 #endif
881 
882 	ENTER();
883 
884 	/* Calculate number of interfaces */
885 #ifdef STA_SUPPORT
886 	if (drv_mode_local & DRV_MODE_STA) {
887 		if ((max_sta_bss < 1) || (max_sta_bss > MAX_STA_BSS)) {
888 			PRINTM(MWARN,
889 			       "Unsupported max_sta_bss (%d), setting to default\n",
890 			       max_sta_bss);
891 			max_sta_bss = DEF_STA_BSS;
892 		}
893 		intf_num += max_sta_bss;
894 	}
895 #endif /* STA_SUPPORT */
896 
897 #ifdef UAP_SUPPORT
898 	if (drv_mode_local & DRV_MODE_UAP) {
899 		if ((max_uap_bss < 1) || (max_uap_bss > MAX_UAP_BSS)) {
900 			PRINTM(MWARN,
901 			       "Unsupported max_uap_bss (%d), setting to default\n",
902 			       max_uap_bss);
903 			max_uap_bss = DEF_UAP_BSS;
904 		}
905 		intf_num += max_uap_bss;
906 	}
907 #endif /* UAP_SUPPORT */
908 
909 #if defined(WIFI_DIRECT_SUPPORT)
910 	if (drv_mode_local & DRV_MODE_WIFIDIRECT) {
911 		if ((max_wfd_bss < 1) || (max_wfd_bss > MAX_WIFIDIRECT_BSS)) {
912 			PRINTM(MWARN,
913 			       "Unsupported max_wfd_bss (%d), setting to default\n",
914 			       max_wfd_bss);
915 			max_wfd_bss = DEF_WIFIDIRECT_BSS;
916 		}
917 		intf_num += max_wfd_bss;
918 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
919 		intf_num += max_vir_bss;
920 #endif
921 	}
922 #endif /* WIFI_DIRECT_SUPPORT  && V14_FEATURE */
923 
924 	if (drv_mode_local & DRV_MODE_NAN) {
925 		if ((max_nan_bss < 1) || (max_nan_bss > MAX_NAN_BSS)) {
926 			PRINTM(MWARN,
927 			       "Unsupported max_nan_bss (%d), setting to default\n",
928 			       max_nan_bss);
929 			max_nan_bss = DEF_NAN_BSS;
930 		}
931 		intf_num += max_nan_bss;
932 	}
933 
934 	/* Create BSS attribute table */
935 	if ((intf_num == 0) || (intf_num > MLAN_MAX_BSS_NUM)) {
936 		PRINTM(MERROR, "Unsupported number of BSS %d\n", intf_num);
937 		ret = MLAN_STATUS_FAILURE;
938 		goto done;
939 	} else {
940 		/* Create new table */
941 		bss_tbl = kmalloc(sizeof(mlan_bss_attr) * intf_num, GFP_KERNEL);
942 		if (!bss_tbl) {
943 			PRINTM(MERROR,
944 			       "Could not create BSS attribute table\n");
945 			ret = MLAN_STATUS_FAILURE;
946 			goto done;
947 		}
948 	}
949 
950 	/* Populate BSS attribute table */
951 #ifdef STA_SUPPORT
952 	if (drv_mode_local & DRV_MODE_STA) {
953 		for (j = 0; j < max_sta_bss; j++) {
954 			if (i >= intf_num)
955 				break;
956 			bss_tbl[i].bss_type = MLAN_BSS_TYPE_STA;
957 			bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
958 			bss_tbl[i].active = MTRUE;
959 			bss_tbl[i].bss_priority = 0;
960 			bss_tbl[i].bss_num = j;
961 			bss_tbl[i].bss_virtual = MFALSE;
962 			i++;
963 		}
964 	}
965 #endif /* STA_SUPPORT */
966 
967 #ifdef UAP_SUPPORT
968 	if (drv_mode_local & DRV_MODE_UAP) {
969 		for (j = 0; j < max_uap_bss; j++) {
970 			if (i >= intf_num)
971 				break;
972 			bss_tbl[i].bss_type = MLAN_BSS_TYPE_UAP;
973 			bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
974 			bss_tbl[i].active = MTRUE;
975 			bss_tbl[i].bss_priority = 0;
976 			bss_tbl[i].bss_num = j;
977 			bss_tbl[i].bss_virtual = MFALSE;
978 			i++;
979 		}
980 	}
981 #endif /* UAP_SUPPORT */
982 
983 #if defined(WIFI_DIRECT_SUPPORT)
984 	if (drv_mode_local & DRV_MODE_WIFIDIRECT) {
985 		for (j = 0; j < max_wfd_bss; j++) {
986 			if (i >= intf_num)
987 				break;
988 			bss_tbl[i].bss_type = MLAN_BSS_TYPE_WIFIDIRECT;
989 			bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
990 			bss_tbl[i].active = MTRUE;
991 			bss_tbl[i].bss_priority = 0;
992 			bss_tbl[i].bss_num = j;
993 			bss_tbl[i].bss_virtual = MFALSE;
994 			i++;
995 		}
996 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
997 		last_wfd_index = j;
998 #endif
999 	}
1000 #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
1001 
1002 	if (drv_mode_local & DRV_MODE_NAN) {
1003 		for (j = 0; j < max_nan_bss; j++) {
1004 			if (i >= intf_num)
1005 				break;
1006 			bss_tbl[i].bss_type = MLAN_BSS_TYPE_NAN;
1007 			bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
1008 			bss_tbl[i].active = MTRUE;
1009 			bss_tbl[i].bss_priority = 0;
1010 			bss_tbl[i].bss_num = j;
1011 			bss_tbl[i].bss_virtual = MFALSE;
1012 			i++;
1013 		}
1014 	}
1015 
1016 #if defined(WIFI_DIRECT_SUPPORT)
1017 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
1018     /** append virtual interface at the end of table */
1019 	for (j = 0; j < max_vir_bss; j++) {
1020 		if (i >= intf_num)
1021 			break;
1022 		bss_tbl[i].bss_type = MLAN_BSS_TYPE_WIFIDIRECT;
1023 		bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
1024 		bss_tbl[i].active = MTRUE;
1025 		bss_tbl[i].bss_priority = 0;
1026 		bss_tbl[i].bss_num = j + last_wfd_index;
1027 		bss_tbl[i].bss_virtual = MTRUE;
1028 		i++;
1029 	}
1030 #endif
1031 #endif
1032 	/* Clear existing table, if any */
1033 	kfree(handle->drv_mode.bss_attr);
1034 	handle->drv_mode.bss_attr = NULL;
1035 
1036 	/* Create moal_drv_mode entry */
1037 	handle->drv_mode.drv_mode = drv_mode;
1038 	handle->drv_mode.intf_num = intf_num;
1039 	handle->drv_mode.bss_attr = bss_tbl;
1040 
1041 	/* update default firmware name */
1042 	woal_update_firmware_name(handle);
1043 done:
1044 	LEAVE();
1045 	return ret;
1046 }
1047 
1048 #ifdef CONFIG_OF
1049 /**
1050  *  @brief This function read the initial parameter from device tress
1051  *
1052  *  @return         N/A
1053  */
1054 static void
woal_init_from_dev_tree(void)1055 woal_init_from_dev_tree(void)
1056 {
1057 	struct device_node *dt_node = NULL;
1058 	struct property *prop;
1059 	t_u32 data;
1060 	const char *string_data;
1061 
1062 	ENTER();
1063 
1064 	if (!dts_enable) {
1065 		PRINTM(MIOCTL, "DTS is disabled!");
1066 		return;
1067 	}
1068 
1069 	dt_node = of_find_node_by_name(NULL, "sd8xxx-wlan");
1070 	if (!dt_node) {
1071 		LEAVE();
1072 		return;
1073 	}
1074 	for_each_property_of_node(dt_node, prop) {
1075 		if (!strncmp(prop->name, "drv_mode", strlen("drv_mode"))) {
1076 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1077 				PRINTM(MIOCTL, "drv_mode=0x%x\n", data);
1078 				drv_mode = data;
1079 			}
1080 		}
1081 #ifdef DEBUG_LEVEL1
1082 		else if (!strncmp(prop->name, "drvdbg", strlen("drvdbg"))) {
1083 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1084 				PRINTM(MIOCTL, "drvdbg=0x%x\n", data);
1085 				drvdbg = data;
1086 			}
1087 		}
1088 #endif
1089 		else if (!strncmp
1090 			 (prop->name, "dev_cap_mask", strlen("dev_cap_mask"))) {
1091 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1092 				PRINTM(MIOCTL, "dev_cap_mask=0x%x\n", data);
1093 				dev_cap_mask = data;
1094 			}
1095 		} else if (!strncmp(prop->name, "hw_test", strlen("hw_test"))) {
1096 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1097 				PRINTM(MIOCTL, "hw_test=0x%x\n", data);
1098 				hw_test = data;
1099 			}
1100 		}
1101 #ifdef MFG_CMD_SUPPORT
1102 		else if (!strncmp(prop->name, "mfg_mode", strlen("mfg_mode"))) {
1103 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1104 				PRINTM(MIOCTL, "mfg_mode=0x%x\n", data);
1105 				mfg_mode = data;
1106 			}
1107 		}
1108 #endif
1109 		else if (!strncmp(prop->name, "mac_addr", strlen("mac_addr"))) {
1110 			if (!of_property_read_string
1111 			    (dt_node, prop->name, &string_data)) {
1112 				mac_addr = (char *)string_data;
1113 				PRINTM(MIOCTL, "mac_addr=%s\n", mac_addr);
1114 			}
1115 		} else if (!strncmp(prop->name, "fw_name", strlen("fw_name"))) {
1116 			if (!of_property_read_string
1117 			    (dt_node, prop->name, &string_data)) {
1118 				fw_name = (char *)string_data;
1119 				PRINTM(MIOCTL, "fw_name=%s\n", fw_name);
1120 			}
1121 		}
1122 #if defined(STA_WEXT) || defined(UAP_WEXT)
1123 		else if (!strncmp
1124 			 (prop->name, "cfg80211_wext",
1125 			  strlen("cfg80211_wext"))) {
1126 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1127 				PRINTM(MIOCTL, "cfg80211_wext=0x%x\n", data);
1128 				cfg80211_wext = data;
1129 			}
1130 		}
1131 #endif
1132 #ifdef STA_SUPPORT
1133 		else if (!strncmp(prop->name, "sta_name", strlen("sta_name"))) {
1134 			if (!of_property_read_string
1135 			    (dt_node, prop->name, &string_data)) {
1136 				sta_name = (char *)string_data;
1137 				PRINTM(MIOCTL, "sta_name=%s\n", sta_name);
1138 			}
1139 		}
1140 #endif
1141 #if defined(WIFI_DIRECT_SUPPORT)
1142 		else if (!strncmp(prop->name, "wfd_name", strlen("wfd_name"))) {
1143 			if (!of_property_read_string
1144 			    (dt_node, prop->name, &string_data)) {
1145 				wfd_name = (char *)string_data;
1146 				PRINTM(MIOCTL, "wfd_name=%s\n", wfd_name);
1147 			}
1148 		}
1149 #endif
1150 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
1151 		else if (!strncmp
1152 			 (prop->name, "reg_alpha2", strlen("reg_alpha2"))) {
1153 			if (!of_property_read_string
1154 			    (dt_node, prop->name, &string_data)) {
1155 				reg_alpha2 = (char *)string_data;
1156 				PRINTM(MIOCTL, "reg_alpha2=%s\n", reg_alpha2);
1157 			}
1158 		}
1159 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1160 		else if (!strncmp
1161 			 (prop->name, "country_ie_ignore",
1162 			  strlen("country_ie_ignore"))) {
1163 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1164 				PRINTM(MIOCTL, "country_ie_ignore=0x%x\n",
1165 				       data);
1166 				country_ie_ignore = data;
1167 			}
1168 		} else if (!strncmp
1169 			   (prop->name, "beacon_hints",
1170 			    strlen("beacon_hints"))) {
1171 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1172 				PRINTM(MIOCTL, "beacon_hints=0x%x\n", data);
1173 				beacon_hints = data;
1174 			}
1175 		}
1176 #endif
1177 #endif
1178 #if defined(WIFI_DIRECT_SUPPORT)
1179 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
1180 		else if (!strncmp
1181 			 (prop->name, "max_vir_bss", strlen("max_vir_bss"))) {
1182 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1183 				PRINTM(MIOCTL, "max_vir_bss=0x%x\n", data);
1184 				max_vir_bss = data;
1185 			}
1186 		} else if (!strncmp(prop->name, "p2p_enh", strlen("p2p_enh"))) {
1187 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1188 				PRINTM(MIOCTL, "p2p_enh=0x%x\n", data);
1189 				p2p_enh = data;
1190 			}
1191 		} else if (!strncmp
1192 			   (prop->name, "cfg80211_drcs",
1193 			    strlen("cfg80211_drcs"))) {
1194 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1195 				PRINTM(MIOCTL, "cfg80211_drcs=0x%x\n", data);
1196 				cfg80211_drcs = data;
1197 			}
1198 		}
1199 #endif
1200 #endif
1201 		else if (!strncmp
1202 			 (prop->name, "dpd_data_cfg", strlen("dpd_data_cfg"))) {
1203 			if (!of_property_read_string
1204 			    (dt_node, prop->name, &string_data)) {
1205 				dpd_data_cfg = (char *)string_data;
1206 				PRINTM(MIOCTL, "dpd_data_cfg=%s\n",
1207 				       dpd_data_cfg);
1208 			}
1209 		} else if (!strncmp(prop->name, "init_cfg", strlen("init_cfg"))) {
1210 			if (!of_property_read_string
1211 			    (dt_node, prop->name, &string_data)) {
1212 				init_cfg = (char *)string_data;
1213 				PRINTM(MIOCTL, "init_cfg=%s\n", init_cfg);
1214 			}
1215 		} else if (!strncmp
1216 			   (prop->name, "cal_data_cfg",
1217 			    strlen("cal_data_cfg"))) {
1218 			if (!of_property_read_string
1219 			    (dt_node, prop->name, &string_data)) {
1220 				cal_data_cfg = (char *)string_data;
1221 				PRINTM(MIOCTL, "cal_data_cfg=%s\n",
1222 				       cal_data_cfg);
1223 			}
1224 		} else if (!strncmp
1225 			   (prop->name, "txpwrlimit_cfg",
1226 			    strlen("txpwrlimit_cfg"))) {
1227 			if (!of_property_read_string
1228 			    (dt_node, prop->name, &string_data)) {
1229 				txpwrlimit_cfg = (char *)string_data;
1230 				PRINTM(MIOCTL, "txpwrlimit_cfg=%s\n",
1231 				       txpwrlimit_cfg);
1232 			}
1233 		} else if (!strncmp
1234 			   (prop->name, "cntry_txpwr", strlen("cntry_txpwr"))) {
1235 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1236 				cntry_txpwr = data;
1237 				PRINTM(MIOCTL, "cntry_txpwr=%d\n", cntry_txpwr);
1238 			}
1239 		} else if (!strncmp(prop->name, "pmic", strlen("pmic"))) {
1240 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1241 				pmic = data;
1242 				PRINTM(MIOCTL, "pmic=%d\n", pmic);
1243 			}
1244 		} else if (!strncmp
1245 			   (prop->name, "hs_wake_interval",
1246 			    strlen("hs_wake_interval"))) {
1247 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1248 				hs_wake_interval = data;
1249 				PRINTM(MIOCTL, "hs_wake_interval=%d\n",
1250 				       hs_wake_interval);
1251 			}
1252 		} else if (!strncmp
1253 			   (prop->name, "indication_gpio",
1254 			    strlen("indication_gpio"))) {
1255 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1256 				indication_gpio = (t_u8)data;
1257 				PRINTM(MIOCTL, "indication_gpio=%d\n",
1258 				       indication_gpio);
1259 			}
1260 		}
1261 #ifdef WIFI_DIRECT_SUPPORT
1262 		else if (!strncmp
1263 			 (prop->name, "GoAgeoutTime", strlen("GoAgeoutTime"))) {
1264 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1265 				GoAgeoutTime = data;
1266 				PRINTM(MIOCTL, "GoAgeoutTime=%d\n",
1267 				       GoAgeoutTime);
1268 			}
1269 		}
1270 #endif
1271 		else if (!strncmp(prop->name, "indrstcfg", strlen("indrstcfg"))) {
1272 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1273 				indrstcfg = data;
1274 				PRINTM(MIOCTL, "indrstcfg=%d\n", indrstcfg);
1275 			}
1276 		} else if (!strncmp
1277 			   (prop->name, "drcs_chantime_mode",
1278 			    strlen("drcs_chantime_mode"))) {
1279 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1280 				drcs_chantime_mode = data;
1281 				PRINTM(MIOCTL, "drcs_chantime_mode=%d\n",
1282 				       drcs_chantime_mode);
1283 			}
1284 		} else if (!strncmp
1285 			   (prop->name, "fixed_beacon_buffer",
1286 			    strlen("fixed_beacon_buffer"))) {
1287 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1288 				fixed_beacon_buffer = data;
1289 				PRINTM(MIOCTL, "fixed_beacon_buffer=%d\n",
1290 				       fixed_beacon_buffer);
1291 			}
1292 		} else if (!strncmp
1293 			   (prop->name, "multi_dtim", strlen("multi_dtim"))) {
1294 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1295 				multi_dtim = data;
1296 				PRINTM(MIOCTL, "multi_dtim=%d\n", multi_dtim);
1297 			}
1298 		} else if (!strncmp
1299 			   (prop->name, "inact_tmo", strlen("inact_tmo"))) {
1300 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1301 				inact_tmo = data;
1302 				PRINTM(MIOCTL, "inact_tmo=%d\n", inact_tmo);
1303 			}
1304 		}
1305 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1306 		else if (!strncmp
1307 			 (prop->name, "dfs_offload", strlen("dfs_offload"))) {
1308 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1309 				dfs_offload = data;
1310 				PRINTM(MIOCTL, "dfs_offload=%d\n", dfs_offload);
1311 			}
1312 		}
1313 #endif
1314 		else if (!strncmp
1315 			 (prop->name, "roamoffload_in_hs",
1316 			  strlen("roamoffload_in_hs"))) {
1317 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1318 				roamoffload_in_hs = data;
1319 				PRINTM(MIOCTL, "roamoffload_in_hs=%d\n",
1320 				       roamoffload_in_hs);
1321 			}
1322 		} else if (!strncmp
1323 			   (prop->name, "gtk_rekey_offload",
1324 			    strlen("gtk_rekey_offload"))) {
1325 			if (!of_property_read_u32(dt_node, prop->name, &data)) {
1326 				gtk_rekey_offload = data;
1327 				PRINTM(MIOCTL, "gtk_rekey_offload=%d\n",
1328 				       gtk_rekey_offload);
1329 			}
1330 		}
1331 	}
1332 	LEAVE();
1333 	return;
1334 }
1335 #endif
1336 
1337 /**
1338  *  @brief This function initializes software
1339  *
1340  *  @param handle   A pointer to moal_handle structure
1341  *
1342  *  @return         MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1343  */
1344 static mlan_status
woal_init_sw(moal_handle * handle)1345 woal_init_sw(moal_handle *handle)
1346 {
1347 	mlan_status ret = MLAN_STATUS_SUCCESS;
1348 	unsigned int i;
1349 	mlan_device device;
1350 	t_void *pmlan;
1351 
1352 	ENTER();
1353 
1354 	/* Initialize moal_handle structure */
1355 	handle->hardware_status = HardwareStatusInitializing;
1356 	handle->main_state = MOAL_STATE_IDLE;
1357 
1358 #ifdef STA_SUPPORT
1359 	if ((drv_mode & DRV_MODE_STA)
1360 #ifdef STA_WEXT
1361 	    && !IS_STA_WEXT(cfg80211_wext)
1362 #endif
1363 #ifdef STA_CFG80211
1364 	    && !IS_STA_CFG80211(cfg80211_wext)
1365 #endif
1366 		) {
1367 		PRINTM(MERROR,
1368 		       "STA without WEXT or CFG80211 bit definition!\n");
1369 		LEAVE();
1370 		return MLAN_STATUS_FAILURE;
1371 	}
1372 #endif /* STA_SUPPORT */
1373 
1374 #if defined(STA_CFG80211) && defined(STA_SUPPORT)
1375 	if (IS_STA_CFG80211(cfg80211_wext))
1376 		cfg80211_wext |= STA_CFG80211_MASK | UAP_CFG80211_MASK;
1377 #endif
1378 
1379 #if defined(UAP_CFG80211) && defined(UAP_SUPPORT)
1380 	if (IS_UAP_CFG80211(cfg80211_wext))
1381 		cfg80211_wext |= STA_CFG80211_MASK | UAP_CFG80211_MASK;
1382 #endif
1383 
1384 	memcpy(handle->driver_version, driver_version, strlen(driver_version));
1385 
1386 	if (woal_update_drv_tbl(handle, drv_mode) != MLAN_STATUS_SUCCESS) {
1387 		PRINTM(MERROR, "Could not update driver mode table\n");
1388 		LEAVE();
1389 		return MLAN_STATUS_FAILURE;
1390 	}
1391 
1392     /** user config file */
1393 	init_waitqueue_head(&handle->init_user_conf_wait_q);
1394 
1395 	/* PnP and power profile */
1396 	handle->surprise_removed = MFALSE;
1397 	init_waitqueue_head(&handle->init_wait_q);
1398 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
1399 	spin_lock_init(&handle->queue_lock);
1400 #endif
1401 	spin_lock_init(&handle->driver_lock);
1402 	spin_lock_init(&handle->ioctl_lock);
1403 	spin_lock_init(&handle->scan_req_lock);
1404 
1405 #if defined(SDIO_SUSPEND_RESUME)
1406 	handle->is_suspended = MFALSE;
1407 	handle->hs_activated = MFALSE;
1408 	handle->hs_auto_arp = MTRUE;
1409 	handle->suspend_fail = MFALSE;
1410 #ifdef SDIO_SUSPEND_RESUME
1411 	handle->suspend_notify_req = MFALSE;
1412 #endif
1413 	handle->hs_skip_count = 0;
1414 	handle->hs_force_count = 0;
1415 	handle->cmd52_func = 0;
1416 	handle->cmd52_reg = 0;
1417 	handle->cmd52_val = 0;
1418 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
1419 	handle->scan_chan_gap = DEF_SCAN_CHAN_GAP;
1420 #ifdef WIFI_DIRECT_SUPPORT
1421 	handle->miracast_scan_time = DEF_MIRACAST_SCAN_TIME;
1422 #define DEF_NOA_DURATION    0
1423 #define DEF_NOA_INTERVAL    100
1424 	handle->noa_duration = DEF_NOA_DURATION;
1425 	handle->noa_interval = DEF_NOA_INTERVAL;
1426 #endif
1427 #endif
1428 	init_waitqueue_head(&handle->hs_activate_wait_q);
1429 #endif
1430 
1431 	/* Initialize measurement wait queue */
1432 	handle->meas_wait_q_woken = MFALSE;
1433 	handle->meas_start_jiffies = 0;
1434 	handle->cac_period = MFALSE;
1435 	handle->delay_bss_start = MFALSE;
1436 	init_waitqueue_head(&handle->meas_wait_q);
1437 #if defined(UAP_SUPPORT)
1438 	handle->chsw_wait_q_woken = MFALSE;
1439 	init_waitqueue_head(&handle->chsw_wait_q);
1440 #endif
1441 
1442 #ifdef DFS_TESTING_SUPPORT
1443 	handle->cac_period_jiffies = 0;
1444 #endif
1445 #ifdef UAP_CFG80211
1446 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
1447 	memset(&handle->dfs_channel, 0, sizeof(struct cfg80211_chan_def));
1448 	woal_initialize_timer(&handle->cac_timer, woal_cac_timer_func, handle);
1449 	handle->is_cac_timer_set = MFALSE;
1450 	handle->cac_bss_index = 0xff;
1451 #endif
1452 #endif
1453 	handle->mon_if = NULL;
1454 
1455 #ifdef REASSOCIATION
1456 	MOAL_INIT_SEMAPHORE(&handle->reassoc_sem);
1457 	handle->reassoc_on = 0;
1458 
1459 	/* Initialize the timer for the reassociation */
1460 	woal_initialize_timer(&handle->reassoc_timer,
1461 			      woal_reassoc_timer_func, handle);
1462 
1463 	handle->is_reassoc_timer_set = MFALSE;
1464 #endif /* REASSOCIATION */
1465 
1466 #if defined(WIFI_DIRECT_SUPPORT)
1467 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
1468 	/* Initialize the timer for GO timeout */
1469 	woal_initialize_timer(&handle->go_timer, woal_go_timer_func, handle);
1470 
1471 	handle->is_go_timer_set = MFALSE;
1472 #endif
1473 #endif
1474 
1475 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
1476 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
1477 	handle->remain_on_channel = MFALSE;
1478 
1479 	/* Initialize the timer for remain on channel */
1480 	woal_initialize_timer(&handle->remain_timer,
1481 			      woal_remain_timer_func, handle);
1482 
1483 	handle->is_remain_timer_set = MFALSE;
1484 #endif
1485 #endif
1486 
1487 	/* Register to MLAN */
1488 	memset(&device, 0, sizeof(mlan_device));
1489 	device.pmoal_handle = handle;
1490 
1491 	device.sdio_rx_aggr_enable = sdio_rx_aggr;
1492 
1493 #ifdef MFG_CMD_SUPPORT
1494 	device.mfg_mode = (t_u32)mfg_mode;
1495 #endif
1496 	device.int_mode = (t_u32)intmode;
1497 	device.gpio_pin = (t_u32)gpiopin;
1498 #ifdef DEBUG_LEVEL1
1499 	device.drvdbg = drvdbg;
1500 #endif
1501 	device.fixed_beacon_buffer = (t_u32)fixed_beacon_buffer;
1502 	device.auto_ds = (t_u32)auto_ds;
1503 	device.ps_mode = (t_u32)ps_mode;
1504 	device.max_tx_buf = (t_u32)max_tx_buf;
1505 #if defined(STA_SUPPORT)
1506 	device.cfg_11d = (t_u32)cfg_11d;
1507 #endif
1508 	device.indrstcfg = (t_u32)indrstcfg;
1509 	device.drcs_chantime_mode = (t_u32)drcs_chantime_mode;
1510 #if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
1511 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)
1512 	device.max_segs =
1513 		((struct sdio_mmc_card *)handle->card)->func->card->host->
1514 		max_segs;
1515 	device.max_seg_size =
1516 		((struct sdio_mmc_card *)handle->card)->func->card->host->
1517 		max_seg_size;
1518 #endif
1519 	PRINTM(MMSG, "SDIO: max_segs=%d max_seg_size=%d\n", device.max_segs,
1520 	       device.max_seg_size);
1521 #endif
1522 #ifdef SDIO_MULTI_PORT_TX_AGGR
1523 #ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
1524 	device.mpa_tx_cfg = MLAN_INIT_PARA_ENABLED;
1525 #else
1526 	device.mpa_tx_cfg = MLAN_INIT_PARA_DISABLED;
1527 #endif
1528 #endif
1529 #ifdef SDIO_MULTI_PORT_RX_AGGR
1530 #ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
1531 	device.mpa_rx_cfg = MLAN_INIT_PARA_ENABLED;
1532 #else
1533 	device.mpa_rx_cfg = MLAN_INIT_PARA_DISABLED;
1534 #endif
1535 #endif
1536 
1537 	if (rx_work == MLAN_INIT_PARA_ENABLED)
1538 		device.rx_work = MTRUE;
1539 	else if (rx_work == MLAN_INIT_PARA_DISABLED)
1540 		device.rx_work = MFALSE;
1541 	else {
1542 		if (num_possible_cpus() > 1)
1543 			device.rx_work = MTRUE;
1544 		else
1545 			device.rx_work = MFALSE;
1546 	}
1547 	PRINTM(MMSG, "rx_work=%d cpu_num=%d\n", device.rx_work,
1548 	       num_possible_cpus());
1549 	if (napi)
1550 		device.rx_work = MTRUE;
1551 
1552 	device.dev_cap_mask = dev_cap_mask;
1553 
1554 	device.multi_dtim = multi_dtim;
1555 
1556 	device.inact_tmo = inact_tmo;
1557 	device.hs_wake_interval = hs_wake_interval;
1558 	device.indication_gpio = indication_gpio;
1559 
1560 	for (i = 0; i < handle->drv_mode.intf_num; i++) {
1561 		device.bss_attr[i].bss_type =
1562 			handle->drv_mode.bss_attr[i].bss_type;
1563 		device.bss_attr[i].frame_type =
1564 			handle->drv_mode.bss_attr[i].frame_type;
1565 		device.bss_attr[i].active = handle->drv_mode.bss_attr[i].active;
1566 		device.bss_attr[i].bss_priority =
1567 			handle->drv_mode.bss_attr[i].bss_priority;
1568 		device.bss_attr[i].bss_num =
1569 			handle->drv_mode.bss_attr[i].bss_num;
1570 		device.bss_attr[i].bss_virtual =
1571 			handle->drv_mode.bss_attr[i].bss_virtual;
1572 	}
1573 	memcpy(&device.callbacks, &woal_callbacks, sizeof(mlan_callbacks));
1574 	if (fw_region)
1575 		device.fw_region = MTRUE;
1576 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
1577 	sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
1578 #endif
1579 	if (MLAN_STATUS_SUCCESS == mlan_register(&device, &pmlan))
1580 		handle->pmlan_adapter = pmlan;
1581 	else
1582 		ret = MLAN_STATUS_FAILURE;
1583 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
1584 	sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
1585 #endif
1586 
1587 	LEAVE();
1588 	return ret;
1589 }
1590 
1591 /**
1592  *  @brief This function frees the structure of moal_handle
1593  *
1594  *  @param handle   A pointer to moal_handle structure
1595  *
1596  *  @return         N/A
1597  */
1598 static void
woal_free_moal_handle(moal_handle * handle)1599 woal_free_moal_handle(moal_handle *handle)
1600 {
1601 	ENTER();
1602 	if (!handle) {
1603 		PRINTM(MERROR, "The handle is NULL\n");
1604 		LEAVE();
1605 		return;
1606 	}
1607 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
1608 	/* Unregister wiphy device and free */
1609 	if (handle->wiphy) {
1610 		wiphy_unregister(handle->wiphy);
1611 		wiphy_free(handle->wiphy);
1612 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1613 		kfree(handle->regd);
1614 #endif
1615 		handle->wiphy = NULL;
1616 	}
1617 #endif
1618 
1619 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
1620 	if ((handle->nl_sk) && ((handle->nl_sk)->sk_socket)) {
1621 		sock_release((handle->nl_sk)->sk_socket);
1622 		handle->nl_sk = NULL;
1623 	}
1624 #else
1625 	netlink_kernel_release(handle->nl_sk);
1626 #endif
1627 
1628 	if (handle->pmlan_adapter)
1629 		mlan_unregister(handle->pmlan_adapter);
1630 
1631 	/* Free BSS attribute table */
1632 	kfree(handle->drv_mode.bss_attr);
1633 	handle->drv_mode.bss_attr = NULL;
1634 	PRINTM(MINFO, "Free Adapter\n");
1635 	if (atomic_read(&handle->lock_count) ||
1636 	    atomic_read(&handle->malloc_count) ||
1637 	    atomic_read(&handle->mbufalloc_count)) {
1638 		PRINTM(MERROR,
1639 		       "mlan has memory leak: lock_count=%d, malloc_count=%d, mbufalloc_count=%d\n",
1640 		       atomic_read(&handle->lock_count),
1641 		       atomic_read(&handle->malloc_count),
1642 		       atomic_read(&handle->mbufalloc_count));
1643 	}
1644 	/* Free allocated memory for fwdump filename */
1645 	kfree(handle->fwdump_fname);
1646 	if (fwdump_fname) {
1647 		kfree(fwdump_fname);
1648 		fwdump_fname = NULL;
1649 	}
1650 	/* Free the moal handle itself */
1651 	kfree(handle);
1652 	LEAVE();
1653 }
1654 
1655 /**
1656  *    @brief WOAL get one line data from ASCII format data
1657  *
1658  *    @param data         Source data
1659  *    @param size         Source data length
1660  *    @param line_pos     Destination data
1661  *    @return             routnine status
1662  */
1663 static t_size
parse_cfg_get_line(t_u8 * data,t_size size,t_u8 * line_pos)1664 parse_cfg_get_line(t_u8 *data, t_size size, t_u8 *line_pos)
1665 {
1666 	t_u8 *src, *dest;
1667 	static t_s32 pos;
1668 
1669 	ENTER();
1670 
1671 	if (pos >= size) {	/* reach the end */
1672 		pos = 0;	/* Reset position for rfkill */
1673 		LEAVE();
1674 		return -1;
1675 	}
1676 	memset(line_pos, 0, MAX_LINE_LEN);
1677 	src = data + pos;
1678 	dest = line_pos;
1679 
1680 	while (pos < size && *src != '\x0A' && *src != '\0') {
1681 		if (*src != ' ' && *src != '\t')	/* parse space */
1682 			*dest++ = *src++;
1683 		else
1684 			src++;
1685 		pos++;
1686 	}
1687 	/* parse new line */
1688 	pos++;
1689 	*dest = '\0';
1690 	LEAVE();
1691 	return strlen(line_pos);
1692 }
1693 
1694 /**
1695  *  @brief Process register access request
1696  *  @param type_string     String format Register type
1697  *  @param offset_string   String format Register offset
1698  *  @param value_string    String format Pointer to value
1699  *  @return                MLAN_STATUS_SUCCESS--success, otherwise--fail
1700  */
1701 static t_u32
woal_process_regrdwr(moal_handle * handle,t_u8 * type_string,t_u8 * offset_string,t_u8 * value_string)1702 woal_process_regrdwr(moal_handle *handle, t_u8 *type_string,
1703 		     t_u8 *offset_string, t_u8 *value_string)
1704 {
1705 	mlan_status ret = MLAN_STATUS_FAILURE;
1706 	int type, offset, value;
1707 	pmlan_ioctl_req ioctl_req = NULL;
1708 	mlan_ds_reg_mem *reg = NULL;
1709 
1710 	ENTER();
1711 
1712 	/* Alloc ioctl_req */
1713 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
1714 
1715 	if (ioctl_req == NULL) {
1716 		PRINTM(MERROR, "Can't alloc memory\n");
1717 		goto done;
1718 	}
1719 
1720 	if (MLAN_STATUS_SUCCESS != woal_atoi(&type, type_string))
1721 		goto done;
1722 	if (MLAN_STATUS_SUCCESS != woal_atoi(&offset, offset_string))
1723 		goto done;
1724 	if (MLAN_STATUS_SUCCESS != woal_atoi(&value, value_string))
1725 		goto done;
1726 
1727 	ioctl_req->req_id = MLAN_IOCTL_REG_MEM;
1728 	ioctl_req->action = MLAN_ACT_SET;
1729 
1730 	reg = (mlan_ds_reg_mem *)ioctl_req->pbuf;
1731 	reg->sub_command = MLAN_OID_REG_RW;
1732 	if (type < 5) {
1733 		reg->param.reg_rw.type = type;
1734 	} else {
1735 		PRINTM(MERROR, "Unsupported Type\n");
1736 		goto done;
1737 	}
1738 	reg->param.reg_rw.offset = offset;
1739 	reg->param.reg_rw.value = value;
1740 
1741 	/* request ioctl for STA */
1742 	ret = woal_request_ioctl(handle->priv[0], ioctl_req, MOAL_IOCTL_WAIT);
1743 	if (ret != MLAN_STATUS_SUCCESS)
1744 		goto done;
1745 	PRINTM(MINFO, "Register type: %d, offset: 0x%x, value: 0x%x\n", type,
1746 	       offset, value);
1747 	ret = MLAN_STATUS_SUCCESS;
1748 
1749 done:
1750 	if (ret != MLAN_STATUS_PENDING)
1751 		kfree(ioctl_req);
1752 	LEAVE();
1753 	return ret;
1754 }
1755 
1756 #ifdef UAP_SUPPORT
1757 /**
1758  *    @brief set uap operation contrl value
1759  *
1760  *    @param handle       MOAL handle
1761  *    @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1762  */
1763 static mlan_status
woal_set_uap_operation_ctrl(moal_handle * handle)1764 woal_set_uap_operation_ctrl(moal_handle *handle)
1765 {
1766 	mlan_status ret = MLAN_STATUS_SUCCESS;
1767 	moal_private *priv = NULL;
1768 	mlan_ds_bss *bss = NULL;
1769 	mlan_ioctl_req *req = NULL;
1770 
1771 	ENTER();
1772 
1773 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_UAP);
1774 	if (!priv) {
1775 		PRINTM(MERROR,
1776 		       "woal_set_uap_operation_ctrl failed, no uap interface\n");
1777 		LEAVE();
1778 		return ret;
1779 	}
1780 
1781 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
1782 	if (req == NULL) {
1783 		ret = MLAN_STATUS_FAILURE;
1784 		goto done;
1785 	}
1786 
1787 	bss = (mlan_ds_bss *)req->pbuf;
1788 	bss->sub_command = MLAN_OID_UAP_OPER_CTRL;
1789 	req->req_id = MLAN_IOCTL_BSS;
1790 	req->action = MLAN_ACT_SET;
1791 
1792 	bss->param.ap_oper_ctrl.ctrl_value =
1793 		(t_u16)((uap_oper_ctrl & 0xffff0000) >> 16);
1794 	bss->param.ap_oper_ctrl.chan_opt = (t_u16)(uap_oper_ctrl & 0xffff);
1795 	PRINTM(MMSG, "Uap oper_ctrl=0x%x chan_opt=0x%x\n",
1796 	       bss->param.ap_oper_ctrl.ctrl_value,
1797 	       bss->param.ap_oper_ctrl.chan_opt);
1798 	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1799 
1800 done:
1801 	if (ret != MLAN_STATUS_PENDING)
1802 		kfree(req);
1803 
1804 	LEAVE();
1805 	return ret;
1806 
1807 }
1808 #endif
1809 
1810 /**
1811  *    @brief WOAL parse ASCII format data to MAC address
1812  *
1813  *    @param handle       MOAL handle
1814  *    @param data         Source data
1815  *    @param size         data length
1816  *    @return             MLAN_STATUS_SUCCESS--success, otherwise--fail
1817  */
1818 static t_u32
woal_process_init_cfg(moal_handle * handle,t_u8 * data,t_size size)1819 woal_process_init_cfg(moal_handle *handle, t_u8 *data, t_size size)
1820 {
1821 	mlan_status ret = MLAN_STATUS_FAILURE;
1822 	t_u8 *pos;
1823 	t_u8 *intf_s, *intf_e;
1824 	t_u8 s[MAX_LINE_LEN];	/* 1 line data */
1825 	t_size line_len;
1826 	t_u8 index = 0;
1827 	t_u32 i;
1828 	t_u8 bss_mac_addr[MAX_MAC_ADDR_LEN];
1829 	t_u8 bss_mac_name[MAX_PARAM_LEN];
1830 	t_u8 type[MAX_PARAM_LEN];
1831 	t_u8 offset[MAX_PARAM_LEN];
1832 	t_u8 value[MAX_PARAM_LEN];
1833 
1834 	ENTER();
1835 
1836 	while ((line_len = parse_cfg_get_line(data, size, s)) != -1) {
1837 
1838 		pos = s;
1839 		while (*pos == ' ' || *pos == '\t')
1840 			pos++;
1841 
1842 		if (*pos == '#' || (*pos == '\r' && *(pos + 1) == '\n') ||
1843 		    *pos == '\n' || *pos == '\0')
1844 			continue;	/* Needn't process this line */
1845 
1846 		/* Process MAC addr */
1847 		if (strncmp(pos, "mac_addr", 8) == 0) {
1848 			intf_s = strchr(pos, '=');
1849 			if (intf_s != NULL)
1850 				intf_e = strchr(intf_s, ':');
1851 			else
1852 				intf_e = NULL;
1853 			if (intf_s != NULL && intf_e != NULL) {
1854 				strncpy(bss_mac_addr, intf_e + 1,
1855 					MAX_MAC_ADDR_LEN - 1);
1856 				bss_mac_addr[MAX_MAC_ADDR_LEN - 1] = '\0';
1857 				if ((intf_e - intf_s) > MAX_PARAM_LEN) {
1858 					PRINTM(MERROR,
1859 					       "Too long interface name %d\n",
1860 					       __LINE__);
1861 					goto done;
1862 				}
1863 				strncpy(bss_mac_name, intf_s + 1,
1864 					intf_e - intf_s - 1);
1865 				bss_mac_name[intf_e - intf_s - 1] = '\0';
1866 				for (i = 0; i < handle->priv_num; i++) {
1867 					if (strcmp
1868 					    (bss_mac_name,
1869 					     handle->priv[i]->netdev->name) ==
1870 					    0) {
1871 						memset(handle->priv[i]->
1872 						       current_addr, 0,
1873 						       ETH_ALEN);
1874 						PRINTM(MINFO,
1875 						       "Interface name: %s mac: %s\n",
1876 						       bss_mac_name,
1877 						       bss_mac_addr);
1878 						woal_mac2u8(handle->priv[i]->
1879 							    current_addr,
1880 							    bss_mac_addr);
1881 #if defined(WIFI_DIRECT_SUPPORT)
1882 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
1883 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
1884 						if (handle->priv[i]->bss_type ==
1885 						    MLAN_BSS_TYPE_WIFIDIRECT) {
1886 							handle->priv[i]->
1887 								current_addr[0]
1888 								|= 0x02;
1889 							PRINTM(MCMND,
1890 							       "Set WFD device addr: "
1891 							       MACSTR "\n",
1892 							       MAC2STR(handle->
1893 								       priv[i]->
1894 								       current_addr));
1895 						}
1896 #endif
1897 #endif
1898 #endif
1899 						/* Set WLAN MAC addresses */
1900 						if (MLAN_STATUS_SUCCESS !=
1901 						    woal_request_set_mac_address
1902 						    (handle->priv[i])) {
1903 							PRINTM(MERROR,
1904 							       "Set MAC address failed\n");
1905 							goto done;
1906 						}
1907 						memcpy(handle->priv[i]->netdev->
1908 						       dev_addr,
1909 						       handle->priv[i]->
1910 						       current_addr, ETH_ALEN);
1911 						index++;	/* Mark found one interface matching */
1912 					}
1913 				}
1914 			} else {
1915 				PRINTM(MERROR, "Wrong config file format %d\n",
1916 				       __LINE__);
1917 				goto done;
1918 			}
1919 		}
1920 		/* Process REG value */
1921 		else if (strncmp(pos, "wlan_reg", 8) == 0) {
1922 			intf_s = strchr(pos, '=');
1923 			if (intf_s != NULL)
1924 				intf_e = strchr(intf_s, ',');
1925 			else
1926 				intf_e = NULL;
1927 			if (intf_s != NULL && intf_e != NULL) {
1928 				/* Copy type */
1929 				strncpy(type, intf_s + 1, 1);
1930 				type[1] = '\0';
1931 			} else {
1932 				PRINTM(MERROR, "Wrong config file format %d\n",
1933 				       __LINE__);
1934 				goto done;
1935 			}
1936 			intf_s = intf_e + 1;
1937 			intf_e = strchr(intf_s, ',');
1938 			if (intf_e != NULL) {
1939 				if ((intf_e - intf_s) >= MAX_PARAM_LEN) {
1940 					PRINTM(MERROR,
1941 					       "Regsier offset is too long %d\n",
1942 					       __LINE__);
1943 					goto done;
1944 				}
1945 				/* Copy offset */
1946 				strncpy(offset, intf_s, intf_e - intf_s);
1947 				offset[intf_e - intf_s] = '\0';
1948 			} else {
1949 				PRINTM(MERROR, "Wrong config file format %d\n",
1950 				       __LINE__);
1951 				goto done;
1952 			}
1953 			intf_s = intf_e + 1;
1954 			if ((strlen(intf_s) >= MAX_PARAM_LEN)) {
1955 				PRINTM(MERROR, "Regsier value is too long %d\n",
1956 				       __LINE__);
1957 				goto done;
1958 			}
1959 			/* Copy value */
1960 			strncpy(value, intf_s,
1961 				MIN((MAX_PARAM_LEN - 1), strlen(intf_s)));
1962 
1963 			if (MLAN_STATUS_SUCCESS !=
1964 			    woal_process_regrdwr(handle, type, offset, value)) {
1965 				PRINTM(MERROR, "Access Reg failed\n");
1966 				goto done;
1967 			}
1968 			PRINTM(MINFO, "Reg type: %s, offset: %s, value: %s\n",
1969 			       type, offset, value);
1970 		}
1971 	}
1972 
1973 	if (index == 0)
1974 		PRINTM(MINFO, "Can't find any matching MAC Address");
1975 	ret = MLAN_STATUS_SUCCESS;
1976 
1977 done:
1978 	LEAVE();
1979 	return ret;
1980 }
1981 
1982 /**
1983  *    @brief WOAL parse ASCII format raw data to hex format
1984  *
1985  *    @param handle       MOAL handle
1986  *    @param data         Source data
1987  *    @param size         data length
1988  *    @param wait_option  wait option
1989  *    @return             MLAN_STATUS_SUCCESS--success, otherwise--fail
1990  */
1991 static t_u32
woal_process_hostcmd_cfg(moal_handle * handle,t_u8 * data,t_size size,t_u8 wait_option)1992 woal_process_hostcmd_cfg(moal_handle *handle, t_u8 *data, t_size size,
1993 			 t_u8 wait_option)
1994 {
1995 	mlan_status ret = MLAN_STATUS_SUCCESS;
1996 	t_u8 *pos = data;
1997 	t_u8 *intf_s, *intf_e;
1998 	t_u8 *buf = NULL;
1999 	t_u8 *ptr = NULL;
2000 	t_u32 cmd_len = 0;
2001 	t_u8 start_raw = MFALSE;
2002 	gfp_t flag;
2003 
2004 #define CMD_STR     "MRVL_CMDhostcmd"
2005 #define CMD_BUF_LEN 2048
2006 
2007 	ENTER();
2008 	flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL;
2009 	buf = kzalloc(CMD_BUF_LEN, flag);
2010 	if (!buf) {
2011 		PRINTM(MERROR, "Could not allocate buffer space!\n");
2012 		goto done;
2013 	}
2014 	ptr = buf;
2015 	strcpy(ptr, CMD_STR);
2016 	ptr = buf + strlen(CMD_STR) + sizeof(t_u32);
2017 	while ((pos - data) < size) {
2018 		while (*pos == ' ' || *pos == '\t')
2019 			pos++;
2020 		if (*pos == '#') {	/* Line comment */
2021 			while (*pos != '\n')
2022 				pos++;
2023 			pos++;
2024 		}
2025 		if ((*pos == '\r' && *(pos + 1) == '\n') ||
2026 		    *pos == '\n' || *pos == '\0') {
2027 			pos++;
2028 			continue;	/* Needn't process this line */
2029 		}
2030 
2031 		if (*pos == '}') {
2032 			cmd_len =
2033 				*((t_u16 *)(buf + strlen(CMD_STR) +
2034 					    sizeof(t_u32) + sizeof(t_u16)));
2035 			memcpy(buf + strlen(CMD_STR), &cmd_len, sizeof(t_u32));
2036 
2037 			/* fire the hostcommand from here */
2038 			woal_priv_hostcmd(handle->priv[0], buf, CMD_BUF_LEN,
2039 					  wait_option);
2040 			memset(buf + strlen(CMD_STR), 0,
2041 			       CMD_BUF_LEN - strlen(CMD_STR));
2042 			ptr = buf + strlen(CMD_STR) + sizeof(t_u32);
2043 			start_raw = MFALSE;
2044 			pos++;
2045 			continue;
2046 		}
2047 
2048 		if (start_raw == MFALSE) {
2049 			intf_s = strchr(pos, '=');
2050 			if (intf_s)
2051 				intf_e = strchr(intf_s, '{');
2052 			else
2053 				intf_e = NULL;
2054 
2055 			if (intf_s && intf_e) {
2056 				start_raw = MTRUE;
2057 				pos = intf_e + 1;
2058 				continue;
2059 			}
2060 		}
2061 
2062 		if (start_raw) {
2063 			/* Raw data block exists */
2064 			while (*pos != '\n') {
2065 				if ((*pos <= 'f' && *pos >= 'a') ||
2066 				    (*pos <= 'F' && *pos >= 'A') ||
2067 				    (*pos <= '9' && *pos >= '0')) {
2068 					*ptr++ = woal_atox(pos);
2069 					pos += 2;
2070 				} else
2071 					pos++;
2072 			}
2073 		}
2074 	}
2075 
2076 done:
2077 	kfree(buf);
2078 	LEAVE();
2079 	return ret;
2080 }
2081 
2082 #define INIT_CFG_DATA           0x00
2083 #define INIT_HOSTCMD_CFG_DATA   0x02
2084 #define COUNTRY_POWER_TABLE     0x04
2085 
2086 /**
2087  * @brief Request init conf firmware callback
2088  *        This function is invoked by request_firmware_nowait system call
2089  *
2090  * @param firmware  A pointer to firmware image
2091  * @param context   A pointer to moal_handle structure
2092  *
2093  * @return          N/A
2094  */
2095 static void
woal_request_init_user_conf_callback(const struct firmware * firmware,void * context)2096 woal_request_init_user_conf_callback(const struct firmware *firmware,
2097 				     void *context)
2098 {
2099 	moal_handle *handle;
2100 
2101 	ENTER();
2102 
2103 	handle = (moal_handle *)context;
2104 	if (!handle) {
2105 		LEAVE();
2106 		return;
2107 	}
2108 	if (firmware)
2109 		handle->user_data = firmware;
2110 	else
2111 		PRINTM(MERROR, "User init config request firmware failed\n");
2112 
2113 	handle->init_user_conf_wait_flag = MTRUE;
2114 	wake_up_interruptible(&handle->init_user_conf_wait_q);
2115 
2116 	LEAVE();
2117 	return;
2118 }
2119 
2120 /**
2121  * @brief Request init conf firmware callback
2122  *        This function is invoked by request_firmware_nowait system call
2123  *
2124  * @param firmware  A pointer to firmware image
2125  * @param context   A pointer to moal_handle structure
2126  *
2127  * @return          N/A
2128  */
2129 static void
woal_request_init_dpd_conf_callback(const struct firmware * firmware,void * context)2130 woal_request_init_dpd_conf_callback(const struct firmware *firmware,
2131 				    void *context)
2132 {
2133 	moal_handle *handle;
2134 
2135 	ENTER();
2136 
2137 	handle = (moal_handle *)context;
2138 	if (!handle) {
2139 		LEAVE();
2140 		return;
2141 	}
2142 	if (firmware && handle)
2143 		handle->dpd_data = firmware;
2144 	else
2145 		PRINTM(MERROR, "User init cfg data request firmware failed\n");
2146 
2147 	handle->init_user_conf_wait_flag = MTRUE;
2148 	wake_up_interruptible(&handle->init_user_conf_wait_q);
2149 
2150 	LEAVE();
2151 	return;
2152 }
2153 
2154 /**
2155  * @brief Request init conf firmware callback
2156  *        This function is invoked by request_firmware_nowait system call
2157  *
2158  * @param firmware  A pointer to firmware image
2159  * @param context   A pointer to moal_handle structure
2160  *
2161  * @return          N/A
2162  */
2163 static void
woal_request_init_txpwr_conf_callback(const struct firmware * firmware,void * context)2164 woal_request_init_txpwr_conf_callback(const struct firmware *firmware,
2165 				      void *context)
2166 {
2167 	moal_handle *handle;
2168 
2169 	ENTER();
2170 
2171 	handle = (moal_handle *)context;
2172 	if (!handle) {
2173 		LEAVE();
2174 		return;
2175 	}
2176 	if (firmware && handle)
2177 		handle->txpwr_data = firmware;
2178 	else
2179 		PRINTM(MERROR, "User init cfg data request firmware failed\n");
2180 
2181 	handle->init_user_conf_wait_flag = MTRUE;
2182 	wake_up_interruptible(&handle->init_user_conf_wait_q);
2183 
2184 	LEAVE();
2185 	return;
2186 }
2187 
2188 /**
2189  * @brief Request init conf firmware callback
2190  *        This function is invoked by request_firmware_nowait system call
2191  *
2192  * @param firmware  A pointer to firmware image
2193  * @param context   A pointer to moal_handle structure
2194  *
2195  * @return          N/A
2196  */
2197 static void
woal_request_init_cfg_data_callback(const struct firmware * firmware,void * context)2198 woal_request_init_cfg_data_callback(const struct firmware *firmware,
2199 				    void *context)
2200 {
2201 	moal_handle *handle;
2202 
2203 	ENTER();
2204 
2205 	handle = (moal_handle *)context;
2206 	if (!handle) {
2207 		LEAVE();
2208 		return;
2209 	}
2210 	if (firmware && handle)
2211 		handle->init_cfg_data = firmware;
2212 	else
2213 		PRINTM(MERROR, "User init cfg data request firmware failed\n");
2214 
2215 	handle->init_user_conf_wait_flag = MTRUE;
2216 	wake_up_interruptible(&handle->init_user_conf_wait_q);
2217 
2218 	LEAVE();
2219 	return;
2220 }
2221 
2222 /**
2223  *    @brief WOAL set user defined init data and param
2224  *
2225  *    @param handle       MOAL handle structure
2226  *    @param type         type argument
2227  *    @param wait_option  wait option
2228  *    @return             MLAN_STATUS_SUCCESS--success, otherwise--fail
2229  */
2230 static t_u32
woal_set_user_init_data(moal_handle * handle,int type,t_u8 wait_option)2231 woal_set_user_init_data(moal_handle *handle, int type, t_u8 wait_option)
2232 {
2233 	mlan_status ret = MLAN_STATUS_FAILURE;
2234 	t_u8 *cfg_data = NULL;
2235 	t_size len;
2236 
2237 	ENTER();
2238 
2239 	if (type == INIT_CFG_DATA) {
2240 		if (req_fw_nowait) {
2241 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
2242 			if ((request_firmware_nowait
2243 			     (THIS_MODULE, FW_ACTION_HOTPLUG, init_cfg,
2244 			      handle->hotplug_device, GFP_KERNEL, handle,
2245 			      woal_request_init_cfg_data_callback)) < 0) {
2246 #else
2247 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
2248 			if ((request_firmware_nowait
2249 			     (THIS_MODULE, FW_ACTION_HOTPLUG, init_cfg,
2250 			      handle->hotplug_device, handle,
2251 			      woal_request_init_cfg_data_callback)) < 0) {
2252 #else
2253 			if ((request_firmware_nowait
2254 			     (THIS_MODULE, init_cfg, handle->hotplug_device,
2255 			      handle,
2256 			      woal_request_init_cfg_data_callback)) < 0) {
2257 #endif
2258 #endif
2259 				PRINTM(MERROR,
2260 				       "Init config file request_firmware_nowait() failed\n");
2261 				goto done;
2262 			}
2263 			handle->init_user_conf_wait_flag = MFALSE;
2264 			wait_event_interruptible(handle->init_user_conf_wait_q,
2265 						 handle->
2266 						 init_user_conf_wait_flag);
2267 		} else {
2268 			if ((request_firmware
2269 			     (&handle->init_cfg_data, init_cfg,
2270 			      handle->hotplug_device)) < 0) {
2271 				PRINTM(MERROR,
2272 				       "Init config file request_firmware() failed\n");
2273 				goto done;
2274 			}
2275 		}
2276 	} else if (type == COUNTRY_POWER_TABLE) {
2277 		if (req_fw_nowait) {
2278 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
2279 			if ((request_firmware_nowait
2280 			     (THIS_MODULE, FW_ACTION_HOTPLUG,
2281 			      country_txpwrlimit, handle->hotplug_device,
2282 			      GFP_KERNEL, handle,
2283 			      woal_request_init_user_conf_callback)) < 0) {
2284 #else
2285 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
2286 			if ((request_firmware_nowait
2287 			     (THIS_MODULE, FW_ACTION_HOTPLUG,
2288 			      country_txpwrlimit, handle->hotplug_device,
2289 			      handle,
2290 			      woal_request_init_user_conf_callback)) < 0) {
2291 #else
2292 			if ((request_firmware_nowait
2293 			     (THIS_MODULE, country_txpwrlimit,
2294 			      handle->hotplug_device, handle,
2295 			      woal_request_init_user_conf_callback)) < 0) {
2296 #endif
2297 #endif
2298 				PRINTM(MERROR,
2299 				       "country txpwrlimit config file request_firmware_nowait() failed\n");
2300 				goto done;
2301 			}
2302 			handle->init_user_conf_wait_flag = MFALSE;
2303 			wait_event_interruptible(handle->init_user_conf_wait_q,
2304 						 handle->
2305 						 init_user_conf_wait_flag);
2306 		} else {
2307 			int status =
2308 				request_firmware(&handle->user_data,
2309 						 country_txpwrlimit,
2310 						 handle->hotplug_device);
2311 			/* File does not exist, skip download */
2312 			if (status == -ENOENT) {
2313 				PRINTM(MIOCTL,
2314 				       "Country power table file does not exist\n");
2315 				LEAVE();
2316 				return MLAN_STATUS_SUCCESS;
2317 			} else if (status) {
2318 				PRINTM(MERROR,
2319 				       "country txpwrlimit config file request_firmware() failed\n");
2320 				goto done;
2321 			}
2322 		}
2323 	} else if (type == INIT_HOSTCMD_CFG_DATA) {
2324 		if (req_fw_nowait) {
2325 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
2326 			if ((request_firmware_nowait
2327 			     (THIS_MODULE, FW_ACTION_HOTPLUG, init_hostcmd_cfg,
2328 			      handle->hotplug_device, GFP_KERNEL, handle,
2329 			      woal_request_init_user_conf_callback)) < 0) {
2330 #else
2331 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
2332 			if ((request_firmware_nowait
2333 			     (THIS_MODULE, FW_ACTION_HOTPLUG, init_hostcmd_cfg,
2334 			      handle->hotplug_device, handle,
2335 			      woal_request_init_user_conf_callback)) < 0) {
2336 #else
2337 			if ((request_firmware_nowait
2338 			     (THIS_MODULE, init_hostcmd_cfg,
2339 			      handle->hotplug_device, handle,
2340 			      woal_request_init_user_conf_callback)) < 0) {
2341 #endif
2342 #endif
2343 				PRINTM(MERROR,
2344 				       "Init hostcmd config file request_firmware_nowait() failed\n");
2345 				goto done;
2346 			}
2347 			handle->init_user_conf_wait_flag = MFALSE;
2348 			wait_event_interruptible(handle->init_user_conf_wait_q,
2349 						 handle->
2350 						 init_user_conf_wait_flag);
2351 		} else {
2352 			if ((request_firmware
2353 			     (&handle->user_data, init_hostcmd_cfg,
2354 			      handle->hotplug_device)) < 0) {
2355 				PRINTM(MERROR,
2356 				       "Init hostcmd config file request_firmware() failed\n");
2357 				goto done;
2358 			}
2359 		}
2360 	}
2361 
2362 	if (handle->user_data) {
2363 		cfg_data = (t_u8 *)(handle->user_data)->data;
2364 		len = (handle->user_data)->size;
2365 		if (type == INIT_HOSTCMD_CFG_DATA
2366 		    || type == COUNTRY_POWER_TABLE) {
2367 			if (MLAN_STATUS_SUCCESS !=
2368 			    woal_process_hostcmd_cfg(handle, cfg_data, len,
2369 						     wait_option)) {
2370 				PRINTM(MERROR,
2371 				       "Can't process hostcmd config file\n");
2372 				goto done;
2373 			}
2374 		}
2375 		ret = MLAN_STATUS_SUCCESS;
2376 	} else if (type == INIT_CFG_DATA && handle->init_cfg_data) {
2377 		PRINTM(MIOCTL, "Load init_cfg success\n");
2378 		ret = MLAN_STATUS_SUCCESS;
2379 	}
2380 done:
2381 	if (handle->user_data) {
2382 		release_firmware(handle->user_data);
2383 		handle->user_data = NULL;
2384 	}
2385 
2386 	LEAVE();
2387 	return ret;
2388 }
2389 
2390 static int woal_netdevice_event(struct notifier_block *nb,
2391 				unsigned long event, void *ptr);
2392 
2393 /**
2394  * @brief Add interfaces DPC
2395  *
2396  * @param handle    A pointer to moal_handle structure
2397  *
2398  * @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2399  */
2400 static mlan_status
2401 woal_add_card_dpc(moal_handle *handle)
2402 {
2403 	mlan_status ret = MLAN_STATUS_SUCCESS;
2404 	int i;
2405 	char str_buf[MLAN_MAX_VER_STR_LEN];
2406 	ENTER();
2407 
2408 #ifdef CONFIG_PROC_FS
2409 	/* Initialize proc fs */
2410 	woal_proc_init(handle);
2411 #endif /* CONFIG_PROC_FS */
2412 
2413 	/* Add interfaces */
2414 	for (i = 0; i < handle->drv_mode.intf_num; i++) {
2415 		if (handle->drv_mode.bss_attr[i].bss_virtual)
2416 			continue;
2417 		if (!woal_add_interface
2418 		    (handle, handle->priv_num,
2419 		     handle->drv_mode.bss_attr[i].bss_type)) {
2420 			ret = MLAN_STATUS_FAILURE;
2421 			goto err;
2422 		}
2423 	}
2424 	woal_get_version(handle, str_buf, sizeof(str_buf) - 1);
2425 	PRINTM(MMSG, "wlan: version = %s\n", str_buf);
2426 
2427 	handle->woal_notifier.notifier_call = woal_netdevice_event;
2428 	if (register_inetaddr_notifier(&handle->woal_notifier)) {
2429 		PRINTM(MFATAL,
2430 		       "Error registering register_inetaddr_notifier\n");
2431 		goto err;
2432 	}
2433 #ifdef MFG_CMD_SUPPORT
2434 	if (mfg_mode == MLAN_INIT_PARA_ENABLED)
2435 		goto done;
2436 #endif
2437 
2438 	if (init_cfg && handle->init_cfg_data) {
2439 		if (MLAN_STATUS_SUCCESS !=
2440 		    woal_process_init_cfg(handle,
2441 					  (t_u8 *)(handle->init_cfg_data)->data,
2442 					  (handle->init_cfg_data)->size)) {
2443 			PRINTM(MERROR, "Can't process init config file\n");
2444 			ret = MLAN_STATUS_FAILURE;
2445 			goto err;
2446 		}
2447 	}
2448 
2449 	if (pmic) {
2450 		if (MLAN_STATUS_SUCCESS !=
2451 		    woal_pmic_configure(handle, MOAL_IOCTL_WAIT)) {
2452 			PRINTM(MFATAL, "Failed to configure PMIC\n");
2453 			ret = MLAN_STATUS_FAILURE;
2454 			goto err;
2455 		}
2456 	}
2457 
2458 #ifdef UAP_SUPPORT
2459 	if (uap_oper_ctrl)
2460 		woal_set_uap_operation_ctrl(handle);
2461 #endif
2462 
2463 #ifdef MFG_CMD_SUPPORT
2464 done:
2465 #endif
2466 err:
2467 	if (init_cfg && handle->init_cfg_data) {
2468 		release_firmware(handle->init_cfg_data);
2469 		handle->init_cfg_data = NULL;
2470 	}
2471 	if (ret != MLAN_STATUS_SUCCESS) {
2472 		PRINTM(MERROR, "Failed to add interface\n");
2473 		unregister_inetaddr_notifier(&handle->woal_notifier);
2474 
2475 		for (i = 0; i < MIN(MLAN_MAX_BSS_NUM, handle->priv_num); i++)
2476 			woal_remove_interface(handle, i);
2477 		handle->priv_num = 0;
2478 #ifdef CONFIG_PROC_FS
2479 		woal_proc_exit(handle);
2480 #endif
2481 	}
2482 	LEAVE();
2483 	return ret;
2484 }
2485 
2486 /**
2487  * @brief Download and Initialize firmware DPC
2488  *
2489  * @param handle    A pointer to moal_handle structure
2490  *
2491  * @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2492  */
2493 static mlan_status
2494 woal_init_fw_dpc(moal_handle *handle)
2495 {
2496 	mlan_status ret = MLAN_STATUS_SUCCESS;
2497 	mlan_fw_image fw;
2498 	t_u8 retry = 0;
2499 
2500 	mlan_init_param param;
2501 
2502 	ENTER();
2503 
2504 	if (handle->firmware) {
2505 		memset(&fw, 0, sizeof(mlan_fw_image));
2506 		fw.pfw_buf = (t_u8 *)handle->firmware->data;
2507 		fw.fw_len = handle->firmware->size;
2508 		if (fw_reload == FW_RELOAD_SDIO_INBAND_RESET)
2509 			fw.fw_reload = fw_reload;
2510 		else
2511 			fw.fw_reload = 0;
2512 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
2513 		sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
2514 #endif
2515 		ret = mlan_dnld_fw(handle->pmlan_adapter, &fw);
2516 #ifdef MFG_CMD_SUPPORT
2517 		if (mfg_mode == MLAN_INIT_PARA_ENABLED)
2518 			fw_name = NULL;
2519 #endif
2520 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
2521 		sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
2522 #endif
2523 		if (ret == MLAN_STATUS_FAILURE) {
2524 			PRINTM(MERROR,
2525 			       "WLAN: Fail download FW with nowwait: %d\n",
2526 			       req_fw_nowait);
2527 			woal_sdio_reg_dbg(handle);
2528 			goto done;
2529 		}
2530 		PRINTM(MMSG, "WLAN FW is active\n");
2531 	}
2532 
2533     /** data request */
2534 	memset(&param, 0, sizeof(mlan_init_param));
2535 
2536 	if (dpd_data_cfg && strncmp(dpd_data_cfg, "none", strlen("none"))) {
2537 		if (req_fw_nowait) {
2538 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
2539 			if ((request_firmware_nowait
2540 			     (THIS_MODULE, FW_ACTION_HOTPLUG, dpd_data_cfg,
2541 			      handle->hotplug_device, GFP_KERNEL, handle,
2542 			      woal_request_init_dpd_conf_callback)) < 0) {
2543 #else
2544 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
2545 			if ((request_firmware_nowait
2546 			     (THIS_MODULE, FW_ACTION_HOTPLUG, dpd_data_cfg,
2547 			      handle->hotplug_device, handle,
2548 			      woal_request_init_dpd_conf_callback)) < 0) {
2549 #else
2550 			if ((request_firmware_nowait
2551 			     (THIS_MODULE, dpd_data_cfg, handle->hotplug_device,
2552 			      handle,
2553 			      woal_request_init_dpd_conf_callback)) < 0) {
2554 #endif
2555 #endif
2556 				PRINTM(MERROR,
2557 				       "DPD data request_firmware_nowait() failed\n");
2558 				ret = MLAN_STATUS_FAILURE;
2559 				goto done;
2560 			}
2561 			handle->init_user_conf_wait_flag = MFALSE;
2562 			wait_event_interruptible(handle->init_user_conf_wait_q,
2563 						 handle->
2564 						 init_user_conf_wait_flag);
2565 		} else {
2566 			if ((request_firmware
2567 			     (&handle->dpd_data, dpd_data_cfg,
2568 			      handle->hotplug_device)) < 0) {
2569 				PRINTM(MERROR,
2570 				       "DPD data request_firmware() failed\n");
2571 				ret = MLAN_STATUS_FAILURE;
2572 				goto done;
2573 			}
2574 		}
2575 		if (handle->dpd_data) {
2576 			param.pdpd_data_buf = (t_u8 *)handle->dpd_data->data;
2577 			param.dpd_data_len = handle->dpd_data->size;
2578 		}
2579 	}
2580 	if (txpwrlimit_cfg && strncmp(txpwrlimit_cfg, "none", strlen("none"))) {
2581 		if (req_fw_nowait) {
2582 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
2583 			if ((request_firmware_nowait
2584 			     (THIS_MODULE, FW_ACTION_HOTPLUG, txpwrlimit_cfg,
2585 			      handle->hotplug_device, GFP_KERNEL, handle,
2586 			      woal_request_init_txpwr_conf_callback)) < 0) {
2587 #else
2588 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
2589 			if ((request_firmware_nowait
2590 			     (THIS_MODULE, FW_ACTION_HOTPLUG, txpwrlimit_cfg,
2591 			      handle->hotplug_device, handle,
2592 			      woal_request_init_txpwr_conf_callback)) < 0) {
2593 #else
2594 			if ((request_firmware_nowait
2595 			     (THIS_MODULE, txpwrlimit_cfg,
2596 			      handle->hotplug_device, handle,
2597 			      woal_request_init_txpwr_conf_callback)) < 0) {
2598 #endif
2599 #endif
2600 				PRINTM(MERROR, "Region txpwrlimit cfg data "
2601 				       "request_firmware_nowait() failed\n");
2602 				ret = MLAN_STATUS_FAILURE;
2603 				goto done;
2604 			}
2605 			handle->init_user_conf_wait_flag = MFALSE;
2606 			wait_event_interruptible(handle->init_user_conf_wait_q,
2607 						 handle->
2608 						 init_user_conf_wait_flag);
2609 		} else {
2610 			if ((request_firmware
2611 			     (&handle->txpwr_data, txpwrlimit_cfg,
2612 			      handle->hotplug_device)) < 0) {
2613 				PRINTM(MERROR,
2614 				       "Region txpwrlimit cfg data "
2615 				       "request_firmware() failed\n");
2616 				ret = MLAN_STATUS_FAILURE;
2617 				goto done;
2618 			}
2619 		}
2620 		if (handle->txpwr_data) {
2621 			param.ptxpwr_data_buf =
2622 				(t_u8 *)handle->txpwr_data->data;
2623 			param.txpwr_data_len = handle->txpwr_data->size;
2624 		}
2625 	}
2626 
2627 	if (cal_data_cfg && strncmp(cal_data_cfg, "none", strlen("none"))) {
2628 		if (req_fw_nowait) {
2629 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
2630 			if ((request_firmware_nowait
2631 			     (THIS_MODULE, FW_ACTION_HOTPLUG, cal_data_cfg,
2632 			      handle->hotplug_device, GFP_KERNEL, handle,
2633 			      woal_request_init_user_conf_callback)) < 0) {
2634 #else
2635 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
2636 			if ((request_firmware_nowait
2637 			     (THIS_MODULE, FW_ACTION_HOTPLUG, cal_data_cfg,
2638 			      handle->hotplug_device, handle,
2639 			      woal_request_init_user_conf_callback)) < 0) {
2640 #else
2641 			if ((request_firmware_nowait
2642 			     (THIS_MODULE, cal_data_cfg, handle->hotplug_device,
2643 			      handle,
2644 			      woal_request_init_user_conf_callback)) < 0) {
2645 #endif
2646 #endif
2647 				PRINTM(MERROR,
2648 				       "Cal data request_firmware_nowait() failed\n");
2649 				ret = MLAN_STATUS_FAILURE;
2650 				goto done;
2651 			}
2652 			handle->init_user_conf_wait_flag = MFALSE;
2653 			wait_event_interruptible(handle->init_user_conf_wait_q,
2654 						 handle->
2655 						 init_user_conf_wait_flag);
2656 		} else {
2657 			if ((request_firmware
2658 			     (&handle->user_data, cal_data_cfg,
2659 			      handle->hotplug_device)) < 0) {
2660 				PRINTM(MERROR,
2661 				       "Cal data request_firmware() failed\n");
2662 				ret = MLAN_STATUS_FAILURE;
2663 				goto done;
2664 			}
2665 		}
2666 	} else if (!cal_data_cfg) {
2667 		PRINTM(MERROR,
2668 		       "Please add cal_data_cfg for 8887/8977/8997/8987/9098\n");
2669 		ret = MLAN_STATUS_FAILURE;
2670 		goto done;
2671 	}
2672 	if (handle->user_data) {
2673 		param.pcal_data_buf = (t_u8 *)handle->user_data->data;
2674 		param.cal_data_len = handle->user_data->size;
2675 	}
2676 
2677 	handle->hardware_status = HardwareStatusFwReady;
2678 	if (ret != MLAN_STATUS_SUCCESS)
2679 		goto done;
2680 	if (handle->fw_reload)
2681 		goto done;
2682 	handle->init_wait_q_woken = MFALSE;
2683 
2684 	ret = mlan_set_init_param(handle->pmlan_adapter, &param);
2685 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
2686 	sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
2687 #endif
2688 	ret = mlan_init_fw(handle->pmlan_adapter);
2689 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
2690 	sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
2691 #endif
2692 	if (ret == MLAN_STATUS_FAILURE)
2693 		goto done;
2694 	else if (ret == MLAN_STATUS_SUCCESS) {
2695 		handle->hardware_status = HardwareStatusReady;
2696 		goto done;
2697 	}
2698 	/* Wait for mlan_init to complete */
2699 	while (wait_event_interruptible(handle->init_wait_q,
2700 					handle->init_wait_q_woken) ==
2701 	       -ERESTARTSYS && retry < MAX_RETRY_CNT) {
2702 		retry++;
2703 	}
2704 	if (handle->hardware_status != HardwareStatusReady) {
2705 		woal_moal_debug_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
2706 				     handle, MTRUE);
2707 #if defined(DEBUG_LEVEL1)
2708 		if (drvdbg & MFW_D) {
2709 			drvdbg &= ~MFW_D;
2710 			woal_dump_firmware_info_v3(handle);
2711 		}
2712 #endif
2713 		ret = MLAN_STATUS_FAILURE;
2714 		goto done;
2715 	}
2716 	ret = MLAN_STATUS_SUCCESS;
2717 done:
2718 	if (handle->dpd_data) {
2719 		release_firmware(handle->dpd_data);
2720 		handle->dpd_data = NULL;
2721 	}
2722 	if (handle->txpwr_data) {
2723 		release_firmware(handle->txpwr_data);
2724 		handle->txpwr_data = NULL;
2725 	}
2726 	if (handle->user_data) {
2727 		release_firmware(handle->user_data);
2728 		handle->user_data = NULL;
2729 	}
2730 	LEAVE();
2731 	return ret;
2732 }
2733 
2734 /**
2735  * @brief Request firmware DPC
2736  *
2737  * @param handle    A pointer to moal_handle structure
2738  * @param firmware  A pointer to firmware image
2739  *
2740  * @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2741  */
2742 static mlan_status
2743 woal_request_fw_dpc(moal_handle *handle, const struct firmware *firmware)
2744 {
2745 	mlan_status ret = MLAN_STATUS_SUCCESS;
2746 	struct timeval tstamp;
2747 
2748 	ENTER();
2749 
2750 	if (!firmware) {
2751 		do_gettimeofday(&tstamp);
2752 		if (tstamp.tv_sec >
2753 		    (handle->req_fw_time.tv_sec + REQUEST_FW_TIMEOUT)) {
2754 			PRINTM(MERROR,
2755 			       "No firmware image found. Skipping download\n");
2756 			ret = MLAN_STATUS_FAILURE;
2757 			goto done;
2758 		}
2759 		PRINTM(MERROR,
2760 		       "request_firmware_nowait failed for %s. Retrying..\n",
2761 		       handle->drv_mode.fw_name);
2762 		woal_sched_timeout(MOAL_TIMER_1S);
2763 		woal_request_fw(handle);
2764 		LEAVE();
2765 		return ret;
2766 	}
2767 	handle->firmware = firmware;
2768 
2769 	ret = woal_init_fw_dpc(handle);
2770 	if (ret)
2771 		goto done;
2772 	ret = woal_add_card_dpc(handle);
2773 	if (ret)
2774 		goto done;
2775 
2776 done:
2777 	/* We should hold the semaphore until callback finishes execution */
2778 	MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
2779 	LEAVE();
2780 	return ret;
2781 }
2782 
2783 /**
2784  * @brief Request firmware callback
2785  *        This function is invoked by request_firmware_nowait system call
2786  *
2787  * @param firmware  A pointer to firmware image
2788  * @param context   A pointer to moal_handle structure
2789  *
2790  * @return          N/A
2791  */
2792 static void
2793 woal_request_fw_callback(const struct firmware *firmware, void *context)
2794 {
2795 	ENTER();
2796 	woal_request_fw_dpc((moal_handle *)context, firmware);
2797 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
2798 	if (firmware)
2799 		release_firmware(firmware);
2800 #endif
2801 	LEAVE();
2802 	return;
2803 }
2804 
2805 /**
2806  * @brief   Download firmware using helper
2807  *
2808  * @param handle  A pointer to moal_handle structure
2809  *
2810  * @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2811  */
2812 mlan_status
2813 woal_request_fw(moal_handle *handle)
2814 {
2815 	mlan_status ret = MLAN_STATUS_SUCCESS;
2816 	int err;
2817 	t_u32 revision_id = 0;
2818 
2819 	ENTER();
2820 
2821 	if (!fw_name) {
2822 #define REV_ID_REG      0xc8
2823 /** Revision ID register */
2824 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
2825 		sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
2826 #endif
2827 		woal_read_reg(handle, REV_ID_REG, &revision_id);
2828 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
2829 		sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
2830 #endif
2831 		switch (revision_id) {
2832 		case SD8977_V0:
2833 			if (fw_serial && !handle->fw_reload && !fw_reload)
2834 				handle->drv_mode.fw_name = SD8977_V0_FW_NAME;
2835 			else
2836 				handle->drv_mode.fw_name =
2837 					SD8977_WLAN_V0_FW_NAME;
2838 			break;
2839 		case SD8977_V1:
2840 			if (fw_serial && !handle->fw_reload && !fw_reload)
2841 				handle->drv_mode.fw_name = SD8977_V1_FW_NAME;
2842 			else
2843 				handle->drv_mode.fw_name =
2844 					SD8977_WLAN_V1_FW_NAME;
2845 			break;
2846 		case SD8977_V2:
2847 			if (fw_serial && !handle->fw_reload && !fw_reload)
2848 				handle->drv_mode.fw_name = SD8977_V2_FW_NAME;
2849 			else
2850 				handle->drv_mode.fw_name =
2851 					SD8977_WLAN_V2_FW_NAME;
2852 			break;
2853 		default:
2854 			break;
2855 		}
2856 	}
2857 
2858 	PRINTM(MMSG, "Request firmware: %s\n", handle->drv_mode.fw_name);
2859 	if (req_fw_nowait) {
2860 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
2861 		err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
2862 					      handle->drv_mode.fw_name,
2863 					      handle->hotplug_device,
2864 					      GFP_KERNEL, handle,
2865 					      woal_request_fw_callback);
2866 #else
2867 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
2868 		err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
2869 					      handle->drv_mode.fw_name,
2870 					      handle->hotplug_device, handle,
2871 					      woal_request_fw_callback);
2872 #else
2873 		err = request_firmware_nowait(THIS_MODULE,
2874 					      handle->drv_mode.fw_name,
2875 					      handle->hotplug_device, handle,
2876 					      woal_request_fw_callback);
2877 #endif
2878 #endif
2879 		if (err < 0) {
2880 			PRINTM(MFATAL,
2881 			       "WLAN: request_firmware_nowait() failed, error code = %d\n",
2882 			       err);
2883 			ret = MLAN_STATUS_FAILURE;
2884 		}
2885 	} else {
2886 		err = request_firmware(&handle->firmware,
2887 				       handle->drv_mode.fw_name,
2888 				       handle->hotplug_device);
2889 		if (err < 0) {
2890 			PRINTM(MFATAL,
2891 			       "WLAN: request_firmware() failed, error code = %d\n",
2892 			       err);
2893 			ret = MLAN_STATUS_FAILURE;
2894 		} else {
2895 			if (handle->fw_reload)
2896 				ret = woal_init_fw_dpc(handle);
2897 			else
2898 				ret = woal_request_fw_dpc(handle,
2899 							  handle->firmware);
2900 			release_firmware(handle->firmware);
2901 		}
2902 	}
2903 
2904 	LEAVE();
2905 	return ret;
2906 }
2907 
2908 /**
2909  *  @brief This function initializes firmware
2910  *
2911  *  @param handle   A pointer to moal_handle structure
2912  *
2913  *  @return         MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2914  */
2915 static mlan_status
2916 woal_init_fw(moal_handle *handle)
2917 {
2918 	mlan_status ret = MLAN_STATUS_SUCCESS;
2919 
2920 	ENTER();
2921 
2922 	do_gettimeofday(&handle->req_fw_time);
2923 
2924 	ret = woal_request_fw(handle);
2925 	if (ret < 0) {
2926 		PRINTM(MFATAL, "woal_request_fw failed\n");
2927 		ret = MLAN_STATUS_FAILURE;
2928 		goto done;
2929 	}
2930 
2931 done:
2932 	LEAVE();
2933 	return ret;
2934 }
2935 
2936 /**
2937  *  @brief This function will fill in the mlan_buffer
2938  *
2939  *  @param pmbuf   A pointer to mlan_buffer
2940  *  @param skb     A pointer to struct sk_buff
2941  *
2942  *  @return        N/A
2943  */
2944 static void
2945 woal_fill_mlan_buffer(moal_private *priv,
2946 		      mlan_buffer *pmbuf, struct sk_buff *skb)
2947 {
2948 	struct timeval tstamp;
2949 	struct ethhdr *eth;
2950 	t_u8 tid;
2951 	dot11_txcontrol *txcontrol;
2952 	t_u8 tx_ctrl_flag = MFALSE;
2953 	int i = 0;
2954 	ENTER();
2955 	/*
2956 	 * skb->priority values from 256->263 are magic values to
2957 	 * directly indicate a specific 802.1d priority.  This is used
2958 	 * to allow 802.1d priority to be passed directly in from VLAN
2959 	 * tags, etc.
2960 	 */
2961 	if (IS_SKB_MAGIC_VLAN(skb)) {
2962 		tid = GET_VLAN_PRIO(skb);
2963 	} else {
2964 		eth = (struct ethhdr *)skb->data;
2965 
2966 		switch (eth->h_proto) {
2967 		case __constant_htons(ETH_P_IP):
2968 			tid = priv->dscp_map[SKB_TOS(skb) >> DSCP_OFFSET];
2969 			if (tid == 0xFF)
2970 				tid = (IPTOS_PREC(SKB_TOS(skb)) >>
2971 				       IPTOS_OFFSET);
2972 			PRINTM(MDAT_D,
2973 			       "packet type ETH_P_IP: dscp[%x], map[%x], tid=%d\n",
2974 			       SKB_TOS(skb) >> DSCP_OFFSET,
2975 			       priv->dscp_map[SKB_TOS(skb) >> DSCP_OFFSET],
2976 			       tid);
2977 			break;
2978 		case __constant_htons(ETH_P_IPV6):
2979 			tid = SKB_TIDV6(skb);
2980 			PRINTM(MDAT_D,
2981 			       "packet type ETH_P_IPV6: %04x, tid=%#x prio=%#x\n",
2982 			       eth->h_proto, tid, skb->priority);
2983 			break;
2984 		case __constant_htons(ETH_P_ARP):
2985 			tid = 0;
2986 			PRINTM(MDATA, "ARP packet %04x\n", eth->h_proto);
2987 			break;
2988 		default:
2989 			tid = 0;
2990 			if (priv->tx_protocols.protocol_num) {
2991 				for (i = 0; i < priv->tx_protocols.protocol_num;
2992 				     i++) {
2993 					if (eth->h_proto ==
2994 					    __constant_htons(priv->tx_protocols.
2995 							     protocols[i]))
2996 						tx_ctrl_flag = MTRUE;
2997 				}
2998 			}
2999 			if (tx_ctrl_flag) {
3000 				txcontrol =
3001 					(dot11_txcontrol *) (skb->data +
3002 							     sizeof(struct
3003 								    ethhdr));
3004 				pmbuf->u.tx_info.data_rate =
3005 					txcontrol->datarate;
3006 				pmbuf->u.tx_info.channel = txcontrol->channel;
3007 				pmbuf->u.tx_info.bw = txcontrol->bw;
3008 				pmbuf->u.tx_info.tx_power.val =
3009 					txcontrol->power;
3010 				pmbuf->u.tx_info.retry_limit =
3011 					txcontrol->retry_limit;
3012 				tid = txcontrol->priority;
3013 				memmove(skb->data + sizeof(dot11_txcontrol),
3014 					skb->data, sizeof(struct ethhdr));
3015 				skb_pull(skb, sizeof(dot11_txcontrol));
3016 				pmbuf->flags |= MLAN_BUF_FLAG_TX_CTRL;
3017 			}
3018 			break;
3019 		}
3020 	}
3021 
3022 	skb->priority = tid;
3023 
3024 	/* Record the current time the packet was queued; used to determine
3025 	 *   the amount of time the packet was queued in the driver before it
3026 	 *   was sent to the firmware.  The delay is then sent along with the
3027 	 *   packet to the firmware for aggregate delay calculation for stats
3028 	 *   and MSDU lifetime expiry.
3029 	 */
3030 	do_gettimeofday(&tstamp);
3031 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
3032 	skb->tstamp = timeval_to_ktime(tstamp);
3033 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
3034 	skb_set_timestamp(skb, &tstamp);
3035 #else
3036 	memcpy(&skb->stamp, &tstamp, sizeof(skb->stamp));
3037 #endif
3038 
3039 	pmbuf->pdesc = skb;
3040 	pmbuf->pbuf = skb->head + sizeof(mlan_buffer);
3041 	pmbuf->data_offset = skb->data - (skb->head + sizeof(mlan_buffer));
3042 	pmbuf->data_len = skb->len;
3043 	pmbuf->priority = skb->priority;
3044 	pmbuf->buf_type = 0;
3045 	pmbuf->in_ts_sec = (t_u32)tstamp.tv_sec;
3046 	pmbuf->in_ts_usec = (t_u32)tstamp.tv_usec;
3047 
3048 	LEAVE();
3049 	return;
3050 }
3051 
3052 /**
3053  * @brief This function opens the network device for monitor interface
3054  *
3055  * @param dev             A pointer to net_device structure
3056  *
3057  * @return                0 -- success, otherwise fail
3058  */
3059 int
3060 woal_mon_open(struct net_device *ndev)
3061 {
3062 	ENTER();
3063 	LEAVE();
3064 	return 0;
3065 }
3066 
3067 /**
3068  * @brief This function closes the network device for monitor interface
3069  *
3070  * @param dev             A pointer to net_device structure
3071  *
3072  * @return                0 -- success, otherwise fail
3073  */
3074 int
3075 woal_mon_close(struct net_device *ndev)
3076 {
3077 	ENTER();
3078 	LEAVE();
3079 	return 0;
3080 }
3081 
3082 /**
3083  * @brief This function sets the MAC address to firmware for monitor interface
3084  *
3085  * @param dev             A pointer to net_device structure
3086  * @param addr            MAC address to set
3087  *
3088  * @return                0 -- success, otherwise fail
3089  */
3090 int
3091 woal_mon_set_mac_address(struct net_device *ndev, void *addr)
3092 {
3093 	ENTER();
3094 	LEAVE();
3095 	return 0;
3096 }
3097 
3098 /**
3099  * @brief This function sets multicast address to firmware for monitor interface
3100  *
3101  * @param dev             A pointer to net_device structure
3102  *
3103  * @return                0 -- success, otherwise fail
3104  */
3105 void
3106 woal_mon_set_multicast_list(struct net_device *ndev)
3107 {
3108 	ENTER();
3109 	LEAVE();
3110 }
3111 
3112 /**
3113  * @brief This function handles packet transmission for monitor interface
3114  *
3115  * @param skb             A pointer to sk_buff structure
3116  * @param dev             A pointer to net_device structure
3117  *
3118  * @return                0 -- success, otherwise fail
3119  */
3120 int
3121 woal_mon_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
3122 {
3123 	int len_rthdr;
3124 	int qos_len = 0;
3125 	int dot11_hdr_len = 24;
3126 	int snap_len = 6;
3127 	unsigned char *pdata;
3128 	unsigned short fc;
3129 	unsigned char src_mac_addr[6];
3130 	unsigned char dst_mac_addr[6];
3131 	struct ieee80211_hdr *dot11_hdr;
3132 	struct ieee80211_radiotap_header *prthdr =
3133 		(struct ieee80211_radiotap_header *)skb->data;
3134 	monitor_iface *mon_if = netdev_priv(ndev);
3135 
3136 	ENTER();
3137 
3138 	if (mon_if == NULL || mon_if->base_ndev == NULL) {
3139 		goto fail;
3140 	}
3141 
3142 	/* check for not even having the fixed radiotap header part */
3143 	if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) {
3144 		PRINTM(MERROR, "Invalid radiotap hdr length,"
3145 		       "skb->len: %d\n", skb->len);
3146 		goto fail;	/* too short to be possibly valid */
3147 	}
3148 
3149 	/* is it a header version we can trust to find length from? */
3150 	if (unlikely(prthdr->it_version))
3151 		goto fail;	/* only version 0 is supported */
3152 
3153 	/* then there must be a radiotap header with a length we can use */
3154 	len_rthdr = ieee80211_get_radiotap_len(skb->data);
3155 
3156 	/* does the skb contain enough to deliver on the alleged length? */
3157 	if (unlikely(skb->len < len_rthdr)) {
3158 		PRINTM(MERROR, "Invalid data length,"
3159 		       "skb->len: %d\n", skb->len);
3160 		goto fail;	/* skb too short for claimed rt header extent */
3161 	}
3162 
3163 	/* Skip the ratiotap header */
3164 	skb_pull(skb, len_rthdr);
3165 
3166 	dot11_hdr = (struct ieee80211_hdr *)skb->data;
3167 	fc = le16_to_cpu(dot11_hdr->frame_control);
3168 	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
3169 		/* Check if this ia a Wireless Distribution System (WDS) frame
3170 		 * which has 4 MAC addresses
3171 		 */
3172 		if (dot11_hdr->frame_control & 0x0080)
3173 			qos_len = 2;
3174 		if ((dot11_hdr->frame_control & 0x0300) == 0x0300)
3175 			dot11_hdr_len += 6;
3176 
3177 		memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
3178 		memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
3179 
3180 		/* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
3181 		 * for two MAC addresses
3182 		 */
3183 		skb_pull(skb,
3184 			 dot11_hdr_len + qos_len + snap_len -
3185 			 sizeof(src_mac_addr) * 2);
3186 		pdata = (unsigned char *)skb->data;
3187 		memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr));
3188 		memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr,
3189 		       sizeof(src_mac_addr));
3190 
3191 		LEAVE();
3192 		return woal_hard_start_xmit(skb, mon_if->base_ndev);
3193 	}
3194 
3195 fail:
3196 	dev_kfree_skb(skb);
3197 	LEAVE();
3198 	return NETDEV_TX_OK;
3199 }
3200 
3201 /**
3202  *  @brief This function returns the network statistics
3203  *
3204  *  @param dev     A pointer to net_device structure
3205  *
3206  *  @return        A pointer to net_device_stats structure
3207  */
3208 struct net_device_stats *
3209 woal_mon_get_stats(struct net_device *dev)
3210 {
3211 	monitor_iface *mon_if = (monitor_iface *)netdev_priv(dev);
3212 	return &mon_if->stats;
3213 }
3214 
3215 static const struct net_device_ops woal_cfg80211_mon_if_ops = {
3216 	.ndo_open = woal_mon_open,
3217 	.ndo_start_xmit = woal_mon_hard_start_xmit,
3218 	.ndo_stop = woal_mon_close,
3219 	.ndo_get_stats = woal_mon_get_stats,
3220 	.ndo_set_mac_address = woal_mon_set_mac_address,
3221 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
3222 	.ndo_set_rx_mode = woal_mon_set_multicast_list,
3223 #else
3224 	.ndo_set_multicast_list = woal_mon_set_multicast_list,
3225 #endif
3226 };
3227 
3228 /**
3229  * @brief This function setup monitor interface
3230  *
3231  * @param dev             A pointer to net_device structure
3232  * @param addr            MAC address to set
3233  *
3234  * @return                0 -- success, otherwise fail
3235  */
3236 
3237 void
3238 woal_mon_if_setup(struct net_device *dev)
3239 {
3240 	ENTER();
3241 	ether_setup(dev);
3242 	dev->netdev_ops = &woal_cfg80211_mon_if_ops;
3243 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 11, 9)
3244 	dev->needs_free_netdev = true;
3245 #else
3246 	dev->destructor = free_netdev;
3247 #endif
3248 	LEAVE();
3249 }
3250 
3251 /**
3252  * @brief Request the driver to add a monitor interface
3253  *
3254  * @param priv             A pointer to moal_private
3255  * @param name              Virtual interface name
3256  * @param name_assign_type  Interface name assignment type
3257  * @param sniffer_mode           Sniffer mode
3258  *
3259  * @return                  A pointer to monitor_iface
3260  */
3261 monitor_iface *
3262 woal_prepare_mon_if(moal_private *priv,
3263 		    const char *name,
3264 		    unsigned char name_assign_type, int sniffer_mode)
3265 {
3266 	int ret = 0;
3267 	moal_handle *handle = priv->phandle;
3268 	struct net_device *ndev = NULL;
3269 	monitor_iface *mon_if = NULL;
3270 
3271 	ENTER();
3272 
3273 	if (sniffer_mode != CHANNEL_SPEC_SNIFFER_MODE) {
3274 		PRINTM(MERROR, "Sniffer mode is not valid\n");
3275 		ret = -EFAULT;
3276 		goto fail;
3277 	}
3278 	if ((sniffer_mode == CHANNEL_SPEC_SNIFFER_MODE) &&
3279 	    woal_is_any_interface_active(handle)) {
3280 		PRINTM(MERROR,
3281 		       "Cannot start channel specified net monitor when Interface Active\n");
3282 		ret = -EFAULT;
3283 		goto fail;
3284 	}
3285 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
3286 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
3287 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
3288 	ndev = alloc_netdev_mq(sizeof(*mon_if), name, name_assign_type,
3289 			       woal_mon_if_setup, 1);
3290 #else
3291 	ndev = alloc_netdev_mq(sizeof(*mon_if), name, NET_NAME_UNKNOWN,
3292 			       woal_mon_if_setup, 1);
3293 #endif
3294 #else
3295 	ndev = alloc_netdev_mq(sizeof(*mon_if), name, woal_mon_if_setup, 1);
3296 #endif
3297 #else
3298 	ndev = alloc_netdev_mq(sizeof(*mon_if), name, woal_mon_if_setup);
3299 #endif
3300 	if (!ndev) {
3301 		PRINTM(MFATAL, "Init virtual ethernet device failed\n");
3302 		ret = -EFAULT;
3303 		goto fail;
3304 	}
3305 
3306 	ret = dev_alloc_name(ndev, ndev->name);
3307 	if (ret < 0) {
3308 		PRINTM(MFATAL, "Net device alloc name fail.\n");
3309 		ret = -EFAULT;
3310 		goto fail;
3311 	}
3312 	//?memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
3313 
3314 	mon_if = netdev_priv(ndev);
3315 	memcpy(mon_if->ifname, ndev->name, IFNAMSIZ);
3316 
3317 	ndev->type = ARPHRD_IEEE80211_RADIOTAP;
3318 	ndev->netdev_ops = &woal_cfg80211_mon_if_ops;
3319 
3320 	mon_if->priv = priv;
3321 	mon_if->mon_ndev = ndev;
3322 	mon_if->base_ndev = priv->netdev;
3323 	mon_if->sniffer_mode = sniffer_mode;
3324 	mon_if->radiotap_enabled = 1;
3325 	mon_if->flag = 1;
3326 
3327 fail:
3328 	if (ret) {
3329 		if (ndev)
3330 			free_netdev(ndev);
3331 		LEAVE();
3332 		return NULL;
3333 	}
3334 
3335 	LEAVE();
3336 	return mon_if;
3337 }
3338 
3339 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
3340 static struct device_type wlan_type = {.name = "wlan", };
3341 #endif
3342 
3343 #ifdef STA_SUPPORT
3344 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
3345 /** Network device handlers */
3346 const struct net_device_ops woal_netdev_ops = {
3347 	.ndo_open = woal_open,
3348 	.ndo_start_xmit = woal_hard_start_xmit,
3349 	.ndo_stop = woal_close,
3350 	.ndo_do_ioctl = woal_do_ioctl,
3351 	.ndo_set_mac_address = woal_set_mac_address,
3352 	.ndo_tx_timeout = woal_tx_timeout,
3353 	.ndo_get_stats = woal_get_stats,
3354 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
3355 	.ndo_set_rx_mode = woal_set_multicast_list,
3356 #else
3357 	.ndo_set_multicast_list = woal_set_multicast_list,
3358 #endif
3359 	.ndo_select_queue = woal_select_queue,
3360 	.ndo_validate_addr = eth_validate_addr,
3361 };
3362 #endif
3363 
3364 /**
3365  *  @brief This function initializes the private structure
3366  *          and dev structure for station mode
3367  *
3368  *  @param dev      A pointer to net_device structure
3369  *  @param priv     A pointer to moal_private structure
3370  *
3371  *  @return         MLAN_STATUS_SUCCESS
3372  */
3373 mlan_status
3374 woal_init_sta_dev(struct net_device *dev, moal_private *priv)
3375 {
3376 	ENTER();
3377 
3378 	/* Setup the OS Interface to our functions */
3379 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
3380 	dev->open = woal_open;
3381 	dev->hard_start_xmit = woal_hard_start_xmit;
3382 	dev->stop = woal_close;
3383 	dev->do_ioctl = woal_do_ioctl;
3384 	dev->set_mac_address = woal_set_mac_address;
3385 	dev->tx_timeout = woal_tx_timeout;
3386 	dev->get_stats = woal_get_stats;
3387 	dev->set_multicast_list = woal_set_multicast_list;
3388 #else
3389 	dev->netdev_ops = &woal_netdev_ops;
3390 #endif
3391 	dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
3392 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
3393 	dev->needed_headroom += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer)
3394 		+ priv->extra_tx_head_len;
3395 #else
3396 	dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer)
3397 		+ priv->extra_tx_head_len;
3398 #endif
3399 #ifdef STA_WEXT
3400 	if (IS_STA_WEXT(cfg80211_wext)) {
3401 #if WIRELESS_EXT < 21
3402 		dev->get_wireless_stats = woal_get_wireless_stats;
3403 #endif
3404 		dev->wireless_handlers =
3405 			(struct iw_handler_def *)&woal_handler_def;
3406 	}
3407 #endif
3408 	dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
3409 
3410 #ifdef STA_CFG80211
3411 	if (IS_STA_CFG80211(cfg80211_wext))
3412 		init_waitqueue_head(&priv->ft_wait_q);
3413 #endif
3414 	LEAVE();
3415 	return MLAN_STATUS_SUCCESS;
3416 }
3417 #endif /* STA_SUPPORT */
3418 
3419 #ifdef UAP_SUPPORT
3420 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
3421 /** Network device handlers */
3422 const struct net_device_ops woal_uap_netdev_ops = {
3423 	.ndo_open = woal_open,
3424 	.ndo_start_xmit = woal_hard_start_xmit,
3425 	.ndo_stop = woal_close,
3426 	.ndo_do_ioctl = woal_uap_do_ioctl,
3427 	.ndo_set_mac_address = woal_set_mac_address,
3428 	.ndo_tx_timeout = woal_tx_timeout,
3429 	.ndo_get_stats = woal_get_stats,
3430 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
3431 	.ndo_set_rx_mode = woal_uap_set_multicast_list,
3432 #else
3433 	.ndo_set_multicast_list = woal_uap_set_multicast_list,
3434 #endif
3435 	.ndo_select_queue = woal_select_queue,
3436 	.ndo_validate_addr = eth_validate_addr,
3437 };
3438 #endif
3439 
3440 /**
3441  *  @brief This function initializes the private structure
3442  *          and dev structure for uap mode
3443  *
3444  *  @param dev      A pointer to net_device structure
3445  *  @param priv     A pointer to moal_private structure
3446  *
3447  *  @return         MLAN_STATUS_SUCCESS
3448  */
3449 mlan_status
3450 woal_init_uap_dev(struct net_device *dev, moal_private *priv)
3451 {
3452 	mlan_status status = MLAN_STATUS_SUCCESS;
3453 
3454 	ENTER();
3455 
3456 	/* Setup the OS Interface to our functions */
3457 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
3458 	dev->open = woal_open;
3459 	dev->hard_start_xmit = woal_hard_start_xmit;
3460 	dev->stop = woal_close;
3461 	dev->set_mac_address = woal_set_mac_address;
3462 	dev->tx_timeout = woal_tx_timeout;
3463 	dev->get_stats = woal_get_stats;
3464 	dev->do_ioctl = woal_uap_do_ioctl;
3465 	dev->set_multicast_list = woal_uap_set_multicast_list;
3466 #else
3467 	dev->netdev_ops = &woal_uap_netdev_ops;
3468 #endif
3469 	dev->watchdog_timeo = MRVDRV_DEFAULT_UAP_WATCHDOG_TIMEOUT;
3470 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
3471 	dev->needed_headroom += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer)
3472 		+ priv->extra_tx_head_len;
3473 #else
3474 	dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer)
3475 		+ priv->extra_tx_head_len;
3476 #endif
3477 #ifdef UAP_WEXT
3478 	if (IS_UAP_WEXT(cfg80211_wext)) {
3479 #if WIRELESS_EXT < 21
3480 		dev->get_wireless_stats = woal_get_uap_wireless_stats;
3481 #endif
3482 		dev->wireless_handlers =
3483 			(struct iw_handler_def *)&woal_uap_handler_def;
3484 	}
3485 #endif /* UAP_WEXT */
3486 	dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
3487 
3488 	LEAVE();
3489 	return status;
3490 }
3491 #endif /* UAP_SUPPORT */
3492 
3493 /**
3494  * @brief This function adds a new interface. It will
3495  *      allocate, initialize and register the device.
3496  *
3497  *  @param handle    A pointer to moal_handle structure
3498  *  @param bss_index BSS index number
3499  *  @param bss_type  BSS type
3500  *
3501  *  @return          A pointer to the new priv structure
3502  */
3503 moal_private *
3504 woal_add_interface(moal_handle *handle, t_u8 bss_index, t_u8 bss_type)
3505 {
3506 	struct net_device *dev = NULL;
3507 	moal_private *priv = NULL;
3508 	char name[256];
3509 	int i = 0;
3510 #ifdef UAP_CFG80211
3511 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
3512 	char csa_str[256];
3513 #endif
3514 #endif
3515 	ENTER();
3516 
3517 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
3518 #define MAX_WMM_QUEUE   4
3519 	/* Allocate an Ethernet device */
3520 	dev = alloc_etherdev_mq(sizeof(moal_private), MAX_WMM_QUEUE);
3521 #else
3522 	dev = alloc_etherdev(sizeof(moal_private));
3523 #endif
3524 	if (!dev) {
3525 		PRINTM(MFATAL, "Init virtual ethernet device failed\n");
3526 		goto error;
3527 	}
3528 	/* Allocate device name */
3529 #ifdef STA_SUPPORT
3530 	memset(name, 0, sizeof(name));
3531 	if (sta_name)
3532 		snprintf(name, sizeof(name), "%s%%d", sta_name);
3533 	else
3534 		sprintf(name, default_mlan_name);
3535 	if ((bss_type == MLAN_BSS_TYPE_STA) && (dev_alloc_name(dev, name) < 0)) {
3536 		PRINTM(MERROR, "Could not allocate mlan device name\n");
3537 		goto error;
3538 	}
3539 #endif
3540 #ifdef UAP_SUPPORT
3541 	memset(name, 0, sizeof(name));
3542 	if (uap_name)
3543 		snprintf(name, sizeof(name), "%s%%d", uap_name);
3544 	else
3545 		sprintf(name, default_uap_name);
3546 	if ((bss_type == MLAN_BSS_TYPE_UAP) && (dev_alloc_name(dev, name) < 0)) {
3547 		PRINTM(MERROR, "Could not allocate uap device name\n");
3548 		goto error;
3549 	}
3550 #endif
3551 #if defined(WIFI_DIRECT_SUPPORT)
3552 	memset(name, 0, sizeof(name));
3553 	if (wfd_name)
3554 		snprintf(name, sizeof(name), "%s%%d", wfd_name);
3555 	else
3556 		sprintf(name, default_wfd_name);
3557 	if ((bss_type == MLAN_BSS_TYPE_WIFIDIRECT) &&
3558 	    (dev_alloc_name(dev, name) < 0)) {
3559 		PRINTM(MERROR, "Could not allocate wifidirect device name\n");
3560 		goto error;
3561 	}
3562 #endif
3563 	memset(name, 0, sizeof(name));
3564 	if (nan_name)
3565 		snprintf(name, sizeof(name), "%s%%d", nan_name);
3566 	else
3567 		sprintf(name, default_nan_name);
3568 	if ((bss_type == MLAN_BSS_TYPE_NAN) && (dev_alloc_name(dev, name) < 0)) {
3569 		PRINTM(MERROR, "Could not allocate nan device name\n");
3570 		goto error;
3571 	}
3572 	priv = (moal_private *)netdev_priv(dev);
3573 	/* Save the priv to handle */
3574 	handle->priv[bss_index] = priv;
3575 
3576 	/* Use the same handle structure */
3577 	priv->phandle = handle;
3578 	priv->netdev = dev;
3579 	priv->bss_index = bss_index;
3580 	priv->bss_type = bss_type;
3581 	priv->extra_tx_head_len = 0;
3582 	if (bss_type == MLAN_BSS_TYPE_STA)
3583 		priv->bss_role = MLAN_BSS_ROLE_STA;
3584 	else if (bss_type == MLAN_BSS_TYPE_UAP)
3585 		priv->bss_role = MLAN_BSS_ROLE_UAP;
3586 #if defined(WIFI_DIRECT_SUPPORT)
3587 	else if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
3588 		priv->bss_role = MLAN_BSS_ROLE_STA;
3589 #endif
3590 	else if (bss_type == MLAN_BSS_TYPE_NAN)
3591 		priv->bss_role = MLAN_BSS_ROLE_STA;
3592 
3593 	INIT_LIST_HEAD(&priv->tcp_sess_queue);
3594 	spin_lock_init(&priv->tcp_sess_lock);
3595 #ifdef STA_SUPPORT
3596 	INIT_LIST_HEAD(&priv->tdls_list);
3597 	spin_lock_init(&priv->tdls_lock);
3598 #endif
3599 
3600 	INIT_LIST_HEAD(&priv->tx_stat_queue);
3601 	spin_lock_init(&priv->tx_stat_lock);
3602 #ifdef STA_CFG80211
3603 #ifdef STA_SUPPORT
3604 	spin_lock_init(&priv->connect_lock);
3605 #endif
3606 #endif
3607 
3608 #ifdef STA_SUPPORT
3609 	INIT_LIST_HEAD(&priv->pmksa_cache_list);
3610 	if (bss_type == MLAN_BSS_TYPE_STA) {
3611 		init_waitqueue_head(&priv->okc_wait_q);
3612 		spin_lock_init(&priv->pmksa_list_lock);
3613 		priv->okc_roaming_ie = NULL;
3614 		priv->okc_ie_len = 0;
3615 	}
3616 #endif
3617 
3618 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
3619 	SET_MODULE_OWNER(dev);
3620 #endif
3621 #ifdef STA_SUPPORT
3622 	if (bss_type == MLAN_BSS_TYPE_STA
3623 #if defined(WIFI_DIRECT_SUPPORT)
3624 	    || bss_type == MLAN_BSS_TYPE_WIFIDIRECT
3625 #endif
3626 	    || bss_type == MLAN_BSS_TYPE_NAN)
3627 		woal_init_sta_dev(dev, priv);
3628 #endif
3629 #ifdef UAP_SUPPORT
3630 	if (bss_type == MLAN_BSS_TYPE_UAP) {
3631 		if (MLAN_STATUS_SUCCESS != woal_init_uap_dev(dev, priv))
3632 			goto error;
3633 	}
3634 #endif
3635 	if (!handle->priv_num
3636 #ifdef MFG_CMD_SUPPORT
3637 	    && (mfg_mode != MLAN_INIT_PARA_ENABLED)
3638 #endif
3639 		) {
3640 		if (init_cfg) {
3641 			if (MLAN_STATUS_SUCCESS !=
3642 			    woal_set_user_init_data(handle, INIT_CFG_DATA,
3643 						    MOAL_IOCTL_WAIT)) {
3644 				PRINTM(MFATAL,
3645 				       "Set user init data and param failed\n");
3646 				goto error;
3647 			}
3648 		}
3649 		if (init_hostcmd_cfg) {
3650 			if (MLAN_STATUS_SUCCESS !=
3651 			    woal_set_user_init_data(handle,
3652 						    INIT_HOSTCMD_CFG_DATA,
3653 						    MOAL_IOCTL_WAIT)) {
3654 				PRINTM(MFATAL,
3655 				       "Set user init hostcmd data and param failed\n");
3656 				goto error;
3657 			}
3658 		}
3659 	}
3660 
3661 	handle->priv_num++;
3662 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
3663 	if (!priv->phandle->wiphy && IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
3664 		if (woal_register_cfg80211(priv)) {
3665 			PRINTM(MERROR, "Cannot register with cfg80211\n");
3666 			goto error;
3667 		}
3668 	}
3669 #endif
3670 
3671 #ifdef STA_CFG80211
3672 #ifdef STA_SUPPORT
3673 	if ((priv->bss_role == MLAN_BSS_ROLE_STA) &&
3674 	    IS_STA_CFG80211(cfg80211_wext)) {
3675 		if (bss_type == MLAN_BSS_TYPE_STA
3676 #if defined(WIFI_DIRECT_SUPPORT)
3677 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
3678 		    || bss_type == MLAN_BSS_TYPE_WIFIDIRECT
3679 #endif
3680 #endif
3681 		    || bss_type == MLAN_BSS_TYPE_NAN)
3682 			/* Register cfg80211 for STA or Wifi direct */
3683 			if (woal_register_sta_cfg80211(dev, bss_type)) {
3684 				PRINTM(MERROR,
3685 				       "Cannot register STA with cfg80211\n");
3686 				goto error;
3687 			}
3688 	}
3689 #endif /* STA_SUPPORT */
3690 #endif /* STA_CFG80211 */
3691 #ifdef UAP_CFG80211
3692 #ifdef UAP_SUPPORT
3693 	if ((priv->bss_role == MLAN_BSS_ROLE_UAP) &&
3694 	    IS_UAP_CFG80211(cfg80211_wext)) {
3695 		/* Register cfg80211 for UAP */
3696 		if (woal_register_uap_cfg80211(dev, bss_type)) {
3697 			PRINTM(MERROR, "Cannot register UAP with cfg80211\n");
3698 			goto error;
3699 		}
3700 	}
3701 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
3702 	strcpy(csa_str, "CSA");
3703 	strcat(csa_str, name);
3704 	priv->csa_workqueue =
3705 		alloc_workqueue(csa_str,
3706 				WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
3707 	if (!priv->csa_workqueue) {
3708 		PRINTM(MERROR, "cannot alloc csa workqueue \n");
3709 		goto error;
3710 	}
3711 	INIT_DELAYED_WORK(&priv->csa_work, woal_csa_work_queue);
3712 #endif
3713 #endif
3714 #endif /*UAP_CFG80211 */
3715 
3716 	/* Initialize priv structure */
3717 	woal_init_priv(priv, MOAL_IOCTL_WAIT);
3718 
3719 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
3720 	SET_NETDEV_DEV(dev, handle->hotplug_device);
3721 #endif
3722 
3723 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
3724 	SET_NETDEV_DEVTYPE(dev, &wlan_type);
3725 #endif
3726 
3727 	/* Register network device */
3728 	if (register_netdev(dev)) {
3729 		PRINTM(MERROR, "Cannot register virtual network device\n");
3730 		goto error;
3731 	}
3732 	netif_carrier_off(dev);
3733 	woal_stop_queue(dev);
3734 
3735 	PRINTM(MINFO, "%s: Marvell 802.11 Adapter\n", dev->name);
3736 	/* Set MAC address from the insmod command line */
3737 	if (handle->set_mac_addr) {
3738 		memset(priv->current_addr, 0, ETH_ALEN);
3739 		memcpy(priv->current_addr, handle->mac_addr, ETH_ALEN);
3740 #if defined(WIFI_DIRECT_SUPPORT)
3741 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
3742 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
3743 		if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
3744 			priv->current_addr[0] |= 0x02;
3745 			PRINTM(MCMND, "Set WFD device addr: " MACSTR "\n",
3746 			       MAC2STR(priv->current_addr));
3747 		}
3748 #endif
3749 #endif
3750 #endif
3751 
3752 		if (MLAN_STATUS_SUCCESS != woal_request_set_mac_address(priv)) {
3753 			PRINTM(MERROR, "Set MAC address failed\n");
3754 			goto error;
3755 		}
3756 		memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN);
3757 	}
3758 	/* Set MAC address for UAPx/MLANx/WFDx and let them different with each other */
3759 	if (priv->bss_index > 0
3760 #ifdef WIFI_DIRECT_SUPPORT
3761 	    && priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT
3762 #endif
3763 		) {
3764 		priv->current_addr[4] += priv->bss_index;
3765 		woal_request_set_mac_address(priv);
3766 		memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN);
3767 		PRINTM(MCMND, "Set %s interface addr: " MACSTR "\n", dev->name,
3768 		       MAC2STR(priv->current_addr));
3769 	}
3770 	if (bss_type == MLAN_BSS_TYPE_STA ||
3771 	    priv->bss_type == MLAN_BSS_TYPE_UAP) {
3772 		mlan_fw_info fw_info;
3773 		woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
3774 
3775 		for (i = 0; i < handle->histogram_table_num; i++) {
3776 			priv->hist_data[i] = kmalloc(sizeof(hgm_data) +
3777 						     RX_RATE_MAX *
3778 						     sizeof(atomic_t)
3779 						     , GFP_KERNEL);
3780 			if (!(priv->hist_data[i])) {
3781 				PRINTM(MERROR,
3782 				       "kmalloc priv->hist_data[%d] failed\n",
3783 				       i);
3784 				goto error;
3785 			}
3786 		}
3787 		if (priv->hist_data)
3788 			woal_hist_data_reset(priv);
3789 	}
3790 #ifdef CONFIG_PROC_FS
3791 	woal_create_proc_entry(priv);
3792 #ifdef PROC_DEBUG
3793 	woal_debug_entry(priv);
3794 #endif /* PROC_DEBUG */
3795 #endif /* CONFIG_PROC_FS */
3796 
3797 	LEAVE();
3798 	return priv;
3799 error:
3800 	handle->priv_num = bss_index;
3801 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
3802 	/* Unregister wiphy device and free */
3803 	if (priv) {
3804 		if (priv->wdev && IS_STA_OR_UAP_CFG80211(cfg80211_wext))
3805 			priv->wdev = NULL;
3806 #ifdef UAP_CFG80211
3807 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
3808 		if (priv->csa_workqueue) {
3809 			destroy_workqueue(priv->csa_workqueue);
3810 			priv->csa_workqueue = NULL;
3811 		}
3812 #endif
3813 #endif
3814 	}
3815 #endif
3816 	if (dev && dev->reg_state == NETREG_REGISTERED)
3817 		unregister_netdev(dev);
3818 	if (dev)
3819 		free_netdev(dev);
3820 	LEAVE();
3821 	return NULL;
3822 }
3823 
3824 /**
3825  *  @brief This function removes an interface.
3826  *
3827  *  @param handle       A pointer to the moal_handle structure
3828  *  @param bss_index    BSS index number
3829  *
3830  *  @return             N/A
3831  */
3832 void
3833 woal_remove_interface(moal_handle *handle, t_u8 bss_index)
3834 {
3835 	struct net_device *dev = NULL;
3836 	moal_private *priv = handle->priv[bss_index];
3837 #if defined(STA_WEXT) || defined(UAP_WEXT)
3838 	union iwreq_data wrqu;
3839 #endif
3840 	int i = 0;
3841 
3842 	ENTER();
3843 	if (!priv || !priv->netdev)
3844 		goto error;
3845 	dev = priv->netdev;
3846 
3847 	if (priv->media_connected == MTRUE) {
3848 		priv->media_connected = MFALSE;
3849 #if defined(STA_WEXT) || defined(UAP_WEXT)
3850 		if (IS_STA_OR_UAP_WEXT(cfg80211_wext) &&
3851 		    GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
3852 			memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
3853 			wrqu.ap_addr.sa_family = ARPHRD_ETHER;
3854 			wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu,
3855 					    NULL);
3856 		}
3857 #endif
3858 	}
3859 	woal_flush_tcp_sess_queue(priv);
3860 
3861 	woal_flush_tx_stat_queue(priv);
3862 
3863 	if (priv->bss_type == MLAN_BSS_TYPE_STA)
3864 		woal_flush_tdls_list(priv);
3865 #ifdef STA_CFG80211
3866 	if (priv->bss_type == MLAN_BSS_TYPE_STA &&
3867 	    IS_STA_CFG80211(cfg80211_wext)) {
3868 		woal_flush_pmksa_list(priv);
3869 		if (priv->okc_roaming_ie) {
3870 			kfree(priv->okc_roaming_ie);
3871 			priv->okc_roaming_ie = NULL;
3872 			priv->okc_ie_len = 0;
3873 		}
3874 	}
3875 #endif
3876 
3877 	if (priv->bss_type == MLAN_BSS_TYPE_STA ||
3878 	    priv->bss_type == MLAN_BSS_TYPE_UAP) {
3879 		for (i = 0; i < handle->histogram_table_num; i++) {
3880 			kfree(priv->hist_data[i]);
3881 			priv->hist_data[i] = NULL;
3882 		}
3883 	}
3884 #ifdef CONFIG_PROC_FS
3885 #ifdef PROC_DEBUG
3886 	/* Remove proc debug */
3887 	woal_debug_remove(priv);
3888 #endif /* PROC_DEBUG */
3889 	woal_proc_remove(priv);
3890 #endif /* CONFIG_PROC_FS */
3891 	/* Last reference is our one */
3892 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
3893 	PRINTM(MINFO, "refcnt = %d\n", atomic_read(&dev->refcnt));
3894 #else
3895 	PRINTM(MINFO, "refcnt = %d\n", netdev_refcnt_read(dev));
3896 #endif
3897 
3898 	PRINTM(MINFO, "netdev_finish_unregister: %s\n", dev->name);
3899 
3900 	if (dev->reg_state == NETREG_REGISTERED)
3901 		unregister_netdev(dev);
3902 
3903 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
3904 	/* Unregister wiphy device and free */
3905 	if (priv->wdev && IS_STA_OR_UAP_CFG80211(cfg80211_wext))
3906 		priv->wdev = NULL;
3907 #ifdef UAP_CFG80211
3908 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
3909 	if (priv->csa_workqueue) {
3910 		flush_workqueue(priv->csa_workqueue);
3911 		destroy_workqueue(priv->csa_workqueue);
3912 		priv->csa_workqueue = NULL;
3913 	}
3914 #endif
3915 #endif
3916 #endif
3917 
3918 	/* Clear the priv in handle */
3919 	priv->phandle->priv[priv->bss_index] = NULL;
3920 	priv->phandle = NULL;
3921 	priv->netdev = NULL;
3922 	free_netdev(dev);
3923 error:
3924 	LEAVE();
3925 	return;
3926 }
3927 
3928 /**
3929  *  @brief Configure pmic in firmware
3930  *
3931  *  @param handle    A pointer to moal_handle
3932  *  @param wait_option  Wait option
3933  *
3934  *  @return             MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
3935  *                          otherwise fail
3936  */
3937 mlan_status
3938 woal_pmic_configure(moal_handle *handle, t_u8 wait_option)
3939 {
3940 	moal_private *priv = NULL;
3941 	mlan_ioctl_req *req = NULL;
3942 	mlan_ds_misc_cfg *misc = NULL;
3943 	mlan_status status;
3944 
3945 	ENTER();
3946 
3947 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
3948 	if (!priv) {
3949 		LEAVE();
3950 		return MLAN_STATUS_FAILURE;
3951 	}
3952 
3953 	/* Allocate an IOCTL request buffer */
3954 	req = (mlan_ioctl_req *)
3955 		woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3956 	if (req == NULL) {
3957 		status = MLAN_STATUS_FAILURE;
3958 		goto done;
3959 	}
3960 
3961 	/* Fill request buffer */
3962 	misc = (mlan_ds_misc_cfg *)req->pbuf;
3963 	misc->sub_command = MLAN_OID_MISC_PMIC_CFG;
3964 	req->req_id = MLAN_IOCTL_MISC_CFG;
3965 	req->action = MLAN_ACT_SET;
3966 
3967 	/* Send IOCTL request to MLAN */
3968 	status = woal_request_ioctl(priv, req, wait_option);
3969 done:
3970 	kfree(req);
3971 	LEAVE();
3972 	return status;
3973 }
3974 
3975 /**
3976  *  @brief Send FW shutdown command to MLAN
3977  *
3978  *  @param priv         A pointer to moal_private structure
3979  *  @param wait_option  Wait option
3980  *
3981  *  @return             MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
3982  *                          otherwise fail
3983  */
3984 static mlan_status
3985 woal_shutdown_fw(moal_private *priv, t_u8 wait_option)
3986 {
3987 	mlan_ioctl_req *req = NULL;
3988 	mlan_ds_misc_cfg *misc = NULL;
3989 	mlan_status status;
3990 
3991 	ENTER();
3992 
3993 	/* Allocate an IOCTL request buffer */
3994 	req = (mlan_ioctl_req *)
3995 		woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3996 	if (req == NULL) {
3997 		status = MLAN_STATUS_FAILURE;
3998 		goto done;
3999 	}
4000 
4001 	/* Fill request buffer */
4002 	misc = (mlan_ds_misc_cfg *)req->pbuf;
4003 	misc->sub_command = MLAN_OID_MISC_INIT_SHUTDOWN;
4004 	misc->param.func_init_shutdown = MLAN_FUNC_SHUTDOWN;
4005 	req->req_id = MLAN_IOCTL_MISC_CFG;
4006 	req->action = MLAN_ACT_SET;
4007 
4008 	/* Send IOCTL request to MLAN */
4009 	status = woal_request_ioctl(priv, req, wait_option);
4010 	/* add 100 ms delay to avoid back to back init/shutdown */
4011 	mdelay(100);
4012 done:
4013 	if (status != MLAN_STATUS_PENDING)
4014 		kfree(req);
4015 	LEAVE();
4016 	return status;
4017 }
4018 
4019 /**
4020  *  @brief Return hex value of a give character
4021  *
4022  *  @param chr      Character to be converted
4023  *
4024  *  @return         The converted character if chr is a valid hex, else 0
4025  */
4026 int
4027 woal_hexval(char chr)
4028 {
4029 	if (chr >= '0' && chr <= '9')
4030 		return chr - '0';
4031 	if (chr >= 'A' && chr <= 'F')
4032 		return chr - 'A' + 10;
4033 	if (chr >= 'a' && chr <= 'f')
4034 		return chr - 'a' + 10;
4035 
4036 	return 0;
4037 }
4038 
4039 #ifdef STA_SUPPORT
4040 #endif
4041 
4042 /**
4043  *  @brief This function cancel all works in the queue
4044  *  and destroy the main workqueue.
4045  *
4046  *  @param handle    A pointer to moal_handle
4047  *
4048  *  @return        N/A
4049  */
4050 static void
4051 woal_terminate_workqueue(moal_handle *handle)
4052 {
4053 	ENTER();
4054 
4055 	/* Terminate main workqueue */
4056 	if (handle->workqueue) {
4057 		flush_workqueue(handle->workqueue);
4058 		destroy_workqueue(handle->workqueue);
4059 		handle->workqueue = NULL;
4060 	}
4061 	if (handle->rx_workqueue) {
4062 		flush_workqueue(handle->rx_workqueue);
4063 		destroy_workqueue(handle->rx_workqueue);
4064 		handle->rx_workqueue = NULL;
4065 	}
4066 	LEAVE();
4067 }
4068 
4069 /********************************************************
4070 		Global Functions
4071 ********************************************************/
4072 
4073 /**
4074  *  @brief This function opens the network device
4075  *
4076  *  @param dev     A pointer to net_device structure
4077  *
4078  *  @return        0 --success, otherwise fail
4079  */
4080 int
4081 woal_open(struct net_device *dev)
4082 {
4083 	moal_private *priv = (moal_private *)netdev_priv(dev);
4084 	t_u8 carrier_on = MFALSE;
4085 
4086 	ENTER();
4087 
4088 	if (priv->phandle->surprise_removed == MTRUE) {
4089 		PRINTM(MERROR,
4090 		       "open is not allowed in surprise remove state.\n");
4091 		LEAVE();
4092 		return -EFAULT;
4093 	}
4094 #if defined(SYSKT)
4095 	/* On some systems the device open handler will be called before HW ready.
4096 	   Use the following flag check and wait function to work around the issue. */
4097 	{
4098 		int i = 0;
4099 
4100 		while ((priv->phandle->hardware_status != HardwareStatusReady)
4101 		       && (i < MAX_WAIT_DEVICE_READY_COUNT)) {
4102 			i++;
4103 			woal_sched_timeout(100);
4104 		}
4105 		if (i >= MAX_WAIT_DEVICE_READY_COUNT) {
4106 			PRINTM(MFATAL,
4107 			       "HW not ready, wlan_open() return failure\n");
4108 			LEAVE();
4109 			return -EFAULT;
4110 		}
4111 	}
4112 #endif /* USB || SYSKT || SYSKT_MULTI */
4113 	if (!MODULE_GET) {
4114 		LEAVE();
4115 		return -EFAULT;
4116 	}
4117 #ifdef UAP_SUPPORT
4118 	if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
4119 	    (priv->media_connected))
4120 		carrier_on = MTRUE;
4121 #endif
4122 #ifdef STA_SUPPORT
4123 	if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
4124 	    (priv->media_connected || priv->is_adhoc_link_sensed))
4125 		carrier_on = MTRUE;
4126 #endif
4127 #if defined(WIFI_DIRECT_SUPPORT)
4128 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
4129 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
4130 	if (!p2p_enh) {
4131 		if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
4132 		    IS_STA_CFG80211(cfg80211_wext)) {
4133 			priv->phandle->wiphy->interface_modes |=
4134 				MBIT(NL80211_IFTYPE_P2P_GO) |
4135 				MBIT(NL80211_IFTYPE_P2P_CLIENT);
4136 		}
4137 	}
4138 #endif
4139 #endif
4140 #endif
4141 	if (carrier_on == MTRUE) {
4142 		if (!netif_carrier_ok(priv->netdev))
4143 			netif_carrier_on(priv->netdev);
4144 		woal_wake_queue(priv->netdev);
4145 	} else {
4146 		if (netif_carrier_ok(priv->netdev))
4147 			netif_carrier_off(priv->netdev);
4148 	}
4149 
4150 	LEAVE();
4151 	return 0;
4152 }
4153 
4154 /**
4155  *  @brief This function closes the network device
4156  *
4157  *  @param dev     A pointer to net_device structure
4158  *
4159  *  @return        0
4160  */
4161 int
4162 woal_close(struct net_device *dev)
4163 {
4164 	moal_private *priv = (moal_private *)netdev_priv(dev);
4165 
4166 	ENTER();
4167 	woal_flush_tx_stat_queue(priv);
4168 
4169 #ifdef STA_SUPPORT
4170 #ifdef STA_CFG80211
4171 	if (IS_STA_CFG80211(cfg80211_wext) &&
4172 	    (priv->bss_type == MLAN_BSS_TYPE_STA))
4173 		woal_clear_conn_params(priv);
4174 	woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
4175 
4176 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
4177 	if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev->current_bss)
4178 		cfg80211_disconnected(priv->netdev, 0, NULL, 0,
4179 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
4180 				      true,
4181 #endif
4182 				      GFP_KERNEL);
4183 #endif
4184 
4185 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
4186 	if (IS_STA_CFG80211(cfg80211_wext) && priv->sched_scanning) {
4187 		woal_stop_bg_scan(priv, MOAL_IOCTL_WAIT);
4188 		priv->bg_scan_start = MFALSE;
4189 		priv->bg_scan_reported = MFALSE;
4190 		cfg80211_sched_scan_stopped(priv->wdev->wiphy
4191 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
4192 					    , 0
4193 #endif
4194 			);
4195 		priv->sched_scanning = MFALSE;
4196 	}
4197 #endif
4198 #endif
4199 #endif
4200 	if (!priv->bss_virtual)
4201 		woal_stop_queue(priv->netdev);
4202 #if defined(WIFI_DIRECT_SUPPORT)
4203 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
4204 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
4205 	if (!p2p_enh) {
4206 		if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
4207 		    !priv->bss_virtual &&
4208 		    IS_STA_CFG80211(cfg80211_wext) &&
4209 		    IS_UAP_CFG80211(cfg80211_wext)) {
4210 			priv->phandle->wiphy->interface_modes &=
4211 				~(MBIT(NL80211_IFTYPE_P2P_GO) |
4212 				  MBIT(NL80211_IFTYPE_P2P_CLIENT));
4213 		}
4214 	}
4215 #endif
4216 #endif
4217 #endif
4218 	MODULE_PUT;
4219 
4220 	LEAVE();
4221 	return 0;
4222 }
4223 
4224 /**
4225  *  @brief This function sets the MAC address to firmware.
4226  *
4227  *  @param dev     A pointer to mlan_private structure
4228  *  @param addr    MAC address to set
4229  *
4230  *  @return        0 --success, otherwise fail
4231  */
4232 int
4233 woal_set_mac_address(struct net_device *dev, void *addr)
4234 {
4235 	int ret = 0;
4236 	moal_private *priv = (moal_private *)netdev_priv(dev);
4237 	struct sockaddr *phw_addr = (struct sockaddr *)addr;
4238 	t_u8 prev_addr[ETH_ALEN];
4239 
4240 	ENTER();
4241 
4242 	if (priv->phandle->surprise_removed == MTRUE) {
4243 		PRINTM(MERROR,
4244 		       "Set mac address is not allowed in surprise remove state.\n");
4245 		LEAVE();
4246 		return -EFAULT;
4247 	}
4248 
4249 	memcpy(prev_addr, priv->current_addr, ETH_ALEN);
4250 	memset(priv->current_addr, 0, ETH_ALEN);
4251 	/* dev->dev_addr is 6 bytes */
4252 	HEXDUMP("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
4253 
4254 	HEXDUMP("addr:", (t_u8 *)phw_addr->sa_data, ETH_ALEN);
4255 	memcpy(priv->current_addr, phw_addr->sa_data, ETH_ALEN);
4256 #if defined(WIFI_DIRECT_SUPPORT)
4257 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
4258 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
4259 	if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
4260 		priv->current_addr[0] |= 0x02;
4261 		PRINTM(MCMND, "Set WFD device addr: " MACSTR "\n",
4262 		       MAC2STR(priv->current_addr));
4263 	}
4264 #endif
4265 #endif
4266 #endif
4267 	if (MLAN_STATUS_SUCCESS != woal_request_set_mac_address(priv)) {
4268 		PRINTM(MERROR, "Set MAC address failed\n");
4269 		/* For failure restore the MAC address */
4270 		memcpy(priv->current_addr, prev_addr, ETH_ALEN);
4271 		ret = -EFAULT;
4272 		goto done;
4273 	}
4274 	HEXDUMP("priv->MacAddr:", priv->current_addr, ETH_ALEN);
4275 	memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN);
4276 done:
4277 	LEAVE();
4278 	return ret;
4279 }
4280 
4281 /**
4282  *  @brief Check driver status
4283  *
4284  *  @param handle   A pointer to moal_handle
4285  *
4286  *  @return         MTRUE/MFALSE
4287  */
4288 t_u8
4289 woal_check_driver_status(moal_handle *handle)
4290 {
4291 	moal_private *priv = NULL;
4292 	struct timeval t;
4293 	int i = 0;
4294 	ENTER();
4295 
4296 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
4297 	if (!priv || woal_get_debug_info(priv, MOAL_IOCTL_WAIT, &info)) {
4298 		PRINTM(MERROR,
4299 		       "Could not retrieve debug information from MLAN\n");
4300 		LEAVE();
4301 		return MTRUE;
4302 	}
4303 #define MOAL_CMD_TIMEOUT_MAX			9
4304 #define MOAL_CMD_TIMEOUT                20
4305 	do_gettimeofday(&t);
4306 	if (info.pending_cmd &&
4307 	    (t.tv_sec > (info.dnld_cmd_in_secs + MOAL_CMD_TIMEOUT_MAX))) {
4308 		if (t.tv_sec > (info.dnld_cmd_in_secs + MOAL_CMD_TIMEOUT) &&
4309 		    !info.num_cmd_timeout) {
4310 			PRINTM(MERROR, "Ignore invalid time, wait=%d\n",
4311 			       (int)(t.tv_sec - info.dnld_cmd_in_secs));
4312 		} else {
4313 			PRINTM(MERROR, "Timeout cmd id = 0x%x wait=%d\n",
4314 			       info.pending_cmd,
4315 			       (int)(t.tv_sec - info.dnld_cmd_in_secs));
4316 			LEAVE();
4317 			return MTRUE;
4318 		}
4319 	}
4320 	if (info.num_cmd_timeout) {
4321 		PRINTM(MERROR, "num_cmd_timeout = %d\n", info.num_cmd_timeout);
4322 		PRINTM(MERROR, "Timeout cmd id = 0x%x, act = 0x%x\n",
4323 		       info.timeout_cmd_id, info.timeout_cmd_act);
4324 		LEAVE();
4325 		return MTRUE;
4326 	}
4327 	if (info.num_cmd_host_to_card_failure) {
4328 		PRINTM(MERROR, "num_cmd_host_to_card_failure = %d\n",
4329 		       info.num_cmd_host_to_card_failure);
4330 		LEAVE();
4331 		return MTRUE;
4332 	}
4333 	if (info.num_no_cmd_node) {
4334 		PRINTM(MERROR, "num_no_cmd_node = %d\n", info.num_no_cmd_node);
4335 		LEAVE();
4336 		return MTRUE;
4337 	}
4338 	for (i = 0; i < handle->priv_num; i++) {
4339 		priv = handle->priv[i];
4340 		if (priv) {
4341 			if (priv->num_tx_timeout >= NUM_TX_TIMEOUT_THRESHOLD) {
4342 				PRINTM(MERROR, "num_tx_timeout = %d\n",
4343 				       priv->num_tx_timeout);
4344 				LEAVE();
4345 				return MTRUE;
4346 			}
4347 		}
4348 	}
4349 	if (info.pm_wakeup_card_req && info.pm_wakeup_fw_try) {
4350 #define MAX_WAIT_TIME     3
4351 		if (t.tv_sec > (info.pm_wakeup_in_secs + MAX_WAIT_TIME)) {
4352 			PRINTM(MERROR,
4353 			       "wakeup_dev_req=%d wakeup_tries=%d wait=%d\n",
4354 			       info.pm_wakeup_card_req, info.pm_wakeup_fw_try,
4355 			       (int)(t.tv_sec - info.pm_wakeup_in_secs));
4356 			LEAVE();
4357 			return MTRUE;
4358 		}
4359 	}
4360 	LEAVE();
4361 	return MFALSE;
4362 }
4363 
4364 /**
4365  *  @brief Display MLAN debug information
4366  *
4367  *  @param priv     A pointer to moal_private
4368  *
4369  *  @return         N/A
4370  */
4371 void
4372 woal_mlan_debug_info(moal_private *priv)
4373 {
4374 	int i;
4375 #ifdef SDIO_MULTI_PORT_TX_AGGR
4376 	int j;
4377 	t_u8 mp_aggr_pkt_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
4378 #endif
4379 	char str[512] = { 0 };
4380 	char *s;
4381 
4382 	ENTER();
4383 
4384 	if (!priv || woal_get_debug_info(priv, MOAL_IOCTL_WAIT, &info)) {
4385 		PRINTM(MERROR,
4386 		       "Could not retrieve debug information from MLAN\n");
4387 		LEAVE();
4388 		return;
4389 	}
4390 	PRINTM(MERROR, "------------mlan_debug_info-------------\n");
4391 	PRINTM(MERROR, "mlan_processing =%d\n", info.mlan_processing);
4392 	PRINTM(MERROR, "main_lock_flag =%d\n", info.main_lock_flag);
4393 	PRINTM(MERROR, "main_process_cnt =%d\n", info.main_process_cnt);
4394 	PRINTM(MERROR, "delay_task_flag =%d\n", info.delay_task_flag);
4395 	PRINTM(MERROR, "mlan_rx_processing =%d\n", info.mlan_rx_processing);
4396 	PRINTM(MERROR, "rx_pkts_queued=%d\n", info.rx_pkts_queued);
4397 	PRINTM(MERROR, "tx_pkts_queued=%d\n", info.tx_pkts_queued);
4398 	PRINTM(MERROR, "num_cmd_timeout = %d\n", info.num_cmd_timeout);
4399 	PRINTM(MERROR, "dbg.num_cmd_timeout = %d\n", info.dbg_num_cmd_timeout);
4400 	PRINTM(MERROR, "Timeout cmd id = 0x%x, act = 0x%x\n",
4401 	       info.timeout_cmd_id, info.timeout_cmd_act);
4402 
4403 	PRINTM(MERROR, "last_cmd_index = %d\n", info.last_cmd_index);
4404 	for (s = str, i = 0; i < DBG_CMD_NUM; i++)
4405 		s += sprintf(s, "0x%x ", info.last_cmd_id[i]);
4406 	PRINTM(MERROR, "last_cmd_id = %s\n", str);
4407 	for (s = str, i = 0; i < DBG_CMD_NUM; i++)
4408 		s += sprintf(s, "0x%x ", info.last_cmd_act[i]);
4409 	PRINTM(MERROR, "last_cmd_act = %s\n", str);
4410 	PRINTM(MERROR, "last_cmd_resp_index = %d\n", info.last_cmd_resp_index);
4411 	for (s = str, i = 0; i < DBG_CMD_NUM; i++)
4412 		s += sprintf(s, "0x%x ", info.last_cmd_resp_id[i]);
4413 	PRINTM(MERROR, "last_cmd_resp_id = %s\n", str);
4414 	PRINTM(MERROR, "last_event_index = %d\n", info.last_event_index);
4415 	for (s = str, i = 0; i < DBG_CMD_NUM; i++)
4416 		s += sprintf(s, "0x%x ", info.last_event[i]);
4417 	PRINTM(MERROR, "last_event = %s", str);
4418 
4419 	PRINTM(MERROR, "num_data_h2c_failure = %d\n",
4420 	       info.num_tx_host_to_card_failure);
4421 	PRINTM(MERROR, "num_cmd_h2c_failure = %d\n",
4422 	       info.num_cmd_host_to_card_failure);
4423 	PRINTM(MERROR, "num_alloc_buffer_failure = %d\n",
4424 	       info.num_alloc_buffer_failure);
4425 	PRINTM(MERROR, "num_pkt_dropped = %d\n", info.num_pkt_dropped);
4426 
4427 	PRINTM(MERROR, "num_data_c2h_failure = %d\n",
4428 	       info.num_rx_card_to_host_failure);
4429 	PRINTM(MERROR, "num_cmdevt_c2h_failure = %d\n",
4430 	       info.num_cmdevt_card_to_host_failure);
4431 	PRINTM(MERROR, "num_int_read_failure = %d\n",
4432 	       info.num_int_read_failure);
4433 	PRINTM(MERROR, "last_int_status = %d\n", info.last_int_status);
4434 
4435 	PRINTM(MERROR, "num_event_deauth = %d\n", info.num_event_deauth);
4436 	PRINTM(MERROR, "num_event_disassoc = %d\n", info.num_event_disassoc);
4437 	PRINTM(MERROR, "num_event_link_lost = %d\n", info.num_event_link_lost);
4438 	PRINTM(MERROR, "num_cmd_deauth = %d\n", info.num_cmd_deauth);
4439 	PRINTM(MERROR, "num_cmd_assoc_success = %d\n",
4440 	       info.num_cmd_assoc_success);
4441 	PRINTM(MERROR, "num_cmd_assoc_failure = %d\n",
4442 	       info.num_cmd_assoc_failure);
4443 	PRINTM(MERROR, "cmd_resp_received = %d\n", info.cmd_resp_received);
4444 	PRINTM(MERROR, "event_received = %d\n", info.event_received);
4445 
4446 	PRINTM(MERROR, "max_tx_buf_size = %d\n", info.max_tx_buf_size);
4447 	PRINTM(MERROR, "tx_buf_size = %d\n", info.tx_buf_size);
4448 	PRINTM(MERROR, "curr_tx_buf_size = %d\n", info.curr_tx_buf_size);
4449 
4450 	PRINTM(MERROR, "data_sent=%d cmd_sent=%d\n", info.data_sent,
4451 	       info.cmd_sent);
4452 
4453 	PRINTM(MERROR, "ps_mode=%d ps_state=%d\n", info.ps_mode, info.ps_state);
4454 	PRINTM(MERROR, "wakeup_dev_req=%d wakeup_tries=%d\n",
4455 	       info.pm_wakeup_card_req, info.pm_wakeup_fw_try);
4456 	PRINTM(MERROR, "hs_configured=%d hs_activated=%d\n",
4457 	       info.is_hs_configured, info.hs_activated);
4458 	PRINTM(MERROR, "pps_uapsd_mode=%d sleep_pd=%d\n",
4459 	       info.pps_uapsd_mode, info.sleep_pd);
4460 	PRINTM(MERROR, "tx_lock_flag = %d\n", info.tx_lock_flag);
4461 	PRINTM(MERROR, "port_open = %d\n", info.port_open);
4462 	PRINTM(MERROR, "scan_processing = %d\n", info.scan_processing);
4463 
4464 	PRINTM(MERROR, "mp_rd_bitmap=0x%x curr_rd_port=0x%x\n",
4465 	       (unsigned int)info.mp_rd_bitmap, info.curr_rd_port);
4466 	PRINTM(MERROR, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n",
4467 	       (unsigned int)info.mp_wr_bitmap, info.curr_wr_port);
4468 	PRINTM(MERROR, "mp_invalid_update=%d\n", info.mp_invalid_update);
4469 #ifdef SDIO_MULTI_PORT_TX_AGGR
4470 	PRINTM(MERROR, "last_recv_wr_bitmap=0x%x last_mp_index = %d\n",
4471 	       info.last_recv_wr_bitmap, info.last_mp_index);
4472 	for (i = 0; i < SDIO_MP_DBG_NUM; i++) {
4473 		for (s = str, j = 0; j < mp_aggr_pkt_limit; j++)
4474 			s += sprintf(s, "0x%02x ",
4475 				     info.last_mp_wr_info[i *
4476 							  mp_aggr_pkt_limit +
4477 							  j]);
4478 
4479 		PRINTM(MERROR,
4480 		       "mp_wr_bitmap: 0x%x mp_wr_ports=0x%x len=%d curr_wr_port=0x%x\n%s\n",
4481 		       info.last_mp_wr_bitmap[i], info.last_mp_wr_ports[i],
4482 		       info.last_mp_wr_len[i], info.last_curr_wr_port[i], str);
4483 	}
4484 #endif
4485 	for (i = 0; i < info.ralist_num; i++) {
4486 		PRINTM(MERROR,
4487 		       "ralist ra: %02x:%02x:%02x:%02x:%02x:%02x tid=%d pkts=%d pause=%d\n",
4488 		       info.ralist[i].ra[0], info.ralist[i].ra[1],
4489 		       info.ralist[i].ra[2], info.ralist[i].ra[3],
4490 		       info.ralist[i].ra[4], info.ralist[i].ra[5],
4491 		       info.ralist[i].tid, info.ralist[i].total_pkts,
4492 		       info.ralist[i].tx_pause);
4493 	}
4494 
4495 	PRINTM(MERROR, "------------mlan_debug_info End-------------\n");
4496 	LEAVE();
4497 }
4498 
4499 /**
4500  *  @brief This function handle the shutdown timeout issue
4501  *
4502  *  @param handle   Pointer to structure moal_handle
4503  *
4504  *  @return         N/A
4505  */
4506 void
4507 woal_ioctl_timeout(moal_handle *handle)
4508 {
4509 	moal_private *priv = NULL;
4510 
4511 	ENTER();
4512 
4513 	PRINTM(MMSG, "woal_ioctl_timout.\n");
4514 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
4515 	if (priv) {
4516 		woal_mlan_debug_info(priv);
4517 		woal_moal_debug_info(priv, NULL, MFALSE);
4518 	}
4519 	LEAVE();
4520 	return;
4521 }
4522 
4523 /**
4524  *  @brief This function handles the timeout of packet
4525  *          transmission
4526  *
4527  *  @param dev     A pointer to net_device structure
4528  *
4529  *  @return        N/A
4530  */
4531 void
4532 woal_tx_timeout(struct net_device *dev)
4533 {
4534 	moal_private *priv = (moal_private *)netdev_priv(dev);
4535 
4536 	ENTER();
4537 
4538 	priv->num_tx_timeout++;
4539 	PRINTM(MERROR, "%lu : %s (bss=%d): Tx timeout (%d)\n",
4540 	       jiffies, dev->name, priv->bss_index, priv->num_tx_timeout);
4541 	woal_set_trans_start(dev);
4542 
4543 	if (priv->num_tx_timeout == NUM_TX_TIMEOUT_THRESHOLD) {
4544 		woal_mlan_debug_info(priv);
4545 		woal_moal_debug_info(priv, NULL, MFALSE);
4546 		woal_broadcast_event(priv, CUS_EVT_DRIVER_HANG,
4547 				     strlen(CUS_EVT_DRIVER_HANG));
4548 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
4549 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
4550 		if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
4551 			woal_cfg80211_vendor_event(priv, event_hang,
4552 						   CUS_EVT_DRIVER_HANG,
4553 						   strlen(CUS_EVT_DRIVER_HANG));
4554 #endif
4555 #endif
4556 		priv->phandle->driver_state = MTRUE;
4557 		woal_process_hang(priv->phandle);
4558 	}
4559 
4560 	LEAVE();
4561 }
4562 
4563 /**
4564  *  @brief This function returns the network statistics
4565  *
4566  *  @param dev     A pointer to net_device structure
4567  *
4568  *  @return        A pointer to net_device_stats structure
4569  */
4570 struct net_device_stats *
4571 woal_get_stats(struct net_device *dev)
4572 {
4573 	moal_private *priv = (moal_private *)netdev_priv(dev);
4574 	return &priv->stats;
4575 }
4576 
4577 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
4578 /**
4579  *  @brief This function handles wmm queue select
4580  *
4581  *  @param dev     A pointer to net_device structure
4582  *  @param skb     A pointer to sk_buff structure
4583  *
4584  *  @return        tx_queue index (0-3)
4585  */
4586 u16
4587 woal_select_queue(struct net_device *dev, struct sk_buff *skb
4588 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
4589 		  , void *accel_priv
4590 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
4591 		  , select_queue_fallback_t fallback
4592 #endif
4593 #endif
4594 	)
4595 {
4596 	moal_private *priv = (moal_private *)netdev_priv(dev);
4597 	struct ethhdr *eth = NULL;
4598 	t_u8 tid = 0;
4599 	t_u8 index = 0;
4600 
4601 	ENTER();
4602 
4603 	/*
4604 	 * skb->priority values from 256->263 are magic values to
4605 	 * directly indicate a specific 802.1d priority.  This is used
4606 	 * to allow 802.1d priority to be passed directly in from VLAN
4607 	 * tags, etc.
4608 	 */
4609 	if (IS_SKB_MAGIC_VLAN(skb)) {
4610 		tid = GET_VLAN_PRIO(skb);
4611 	} else {
4612 		eth = (struct ethhdr *)skb->data;
4613 		switch (eth->h_proto) {
4614 		case __constant_htons(ETH_P_IP):
4615 			tid = priv->dscp_map[SKB_TOS(skb) >> DSCP_OFFSET];
4616 			if (tid == 0xFF)
4617 				tid = (IPTOS_PREC(SKB_TOS(skb)) >>
4618 				       IPTOS_OFFSET);
4619 			break;
4620 		case __constant_htons(ETH_P_IPV6):
4621 			tid = SKB_TIDV6(skb);
4622 			break;
4623 		case __constant_htons(ETH_P_ARP):
4624 		default:
4625 			break;
4626 		}
4627 	}
4628 
4629 	index = mlan_select_wmm_queue(priv->phandle->pmlan_adapter,
4630 				      priv->bss_index, tid);
4631 	PRINTM(MDATA, "select queue: tid=%d, index=%d\n", tid, index);
4632 	LEAVE();
4633 	return index;
4634 }
4635 #endif
4636 
4637 /**
4638  *  @brief This function flush tx status queue
4639  *
4640  *  @param priv      A pointer to moal_private structure
4641  *
4642  *  @return          N/A
4643  */
4644 void
4645 woal_flush_tx_stat_queue(moal_private *priv)
4646 {
4647 	struct tx_status_info *tx_info = NULL, *tmp_node;
4648 	unsigned long flags;
4649 	struct sk_buff *skb = NULL;
4650 	spin_lock_irqsave(&priv->tx_stat_lock, flags);
4651 	list_for_each_entry_safe(tx_info, tmp_node, &priv->tx_stat_queue, link) {
4652 		list_del(&tx_info->link);
4653 		spin_unlock_irqrestore(&priv->tx_stat_lock, flags);
4654 		skb = (struct sk_buff *)tx_info->tx_skb;
4655 		if (tx_info->tx_cookie) {
4656 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
4657 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
4658 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
4659 			cfg80211_mgmt_tx_status(priv->netdev,
4660 						tx_info->tx_cookie, skb->data,
4661 						skb->len, true, GFP_ATOMIC);
4662 #else
4663 			cfg80211_mgmt_tx_status(priv->wdev, tx_info->tx_cookie,
4664 						skb->data, skb->len, true,
4665 						GFP_ATOMIC);
4666 #endif
4667 #endif
4668 #endif
4669 		}
4670 		dev_kfree_skb_any(skb);
4671 		kfree(tx_info);
4672 		spin_lock_irqsave(&priv->tx_stat_lock, flags);
4673 	}
4674 	INIT_LIST_HEAD(&priv->tx_stat_queue);
4675 	spin_unlock_irqrestore(&priv->tx_stat_lock, flags);
4676 }
4677 
4678 /**
4679  *  @brief This function gets tx info from tx_stat_queue
4680  *
4681  *  @param priv      	A pointer to moal_private structure
4682  *  @param tx_seq_num   tx seq number
4683  *
4684  *  @return          A pointer to the tcp tx_status_info structure, if found.
4685  *                   Otherwise, null
4686  */
4687 struct tx_status_info *
4688 woal_get_tx_info(moal_private *priv, t_u8 tx_seq_num)
4689 {
4690 	struct tx_status_info *tx_info = NULL;
4691 	ENTER();
4692 
4693 	list_for_each_entry(tx_info, &priv->tx_stat_queue, link) {
4694 		if (tx_info->tx_seq_num == tx_seq_num) {
4695 			LEAVE();
4696 			return tx_info;
4697 		}
4698 	}
4699 	LEAVE();
4700 	return NULL;
4701 }
4702 
4703 /**
4704  *  @brief This function remove tx info from queue
4705  *
4706  *  @param priv      		A pointer to moal_private structure
4707  *  @param tx_seq_num           tx seq number
4708  *
4709  *  @return	         N/A
4710  */
4711 void
4712 woal_remove_tx_info(moal_private *priv, t_u8 tx_seq_num)
4713 {
4714 	struct tx_status_info *tx_info, *tmp = NULL;
4715 	unsigned long flags;
4716 	ENTER();
4717 
4718 	spin_lock_irqsave(&priv->tx_stat_lock, flags);
4719 	list_for_each_entry_safe(tx_info, tmp, &priv->tx_stat_queue, link) {
4720 		if (tx_info->tx_seq_num == tx_seq_num) {
4721 			list_del(&tx_info->link);
4722 			dev_kfree_skb_any((struct sk_buff *)tx_info->tx_skb);
4723 			kfree(tx_info);
4724 			break;
4725 		}
4726 	}
4727 	spin_unlock_irqrestore(&priv->tx_stat_lock, flags);
4728 
4729 	LEAVE();
4730 }
4731 
4732 /**
4733  *  @brief This function flush tcp session queue
4734  *
4735  *  @param priv      A pointer to moal_private structure
4736  *
4737  *  @return          N/A
4738  */
4739 void
4740 woal_flush_tdls_list(moal_private *priv)
4741 {
4742 	struct tdls_peer *peer = NULL, *tmp_node;
4743 	unsigned long flags;
4744 	spin_lock_irqsave(&priv->tdls_lock, flags);
4745 	list_for_each_entry_safe(peer, tmp_node, &priv->tdls_list, link) {
4746 		list_del(&peer->link);
4747 		kfree(peer);
4748 	}
4749 	INIT_LIST_HEAD(&priv->tdls_list);
4750 	spin_unlock_irqrestore(&priv->tdls_lock, flags);
4751 	priv->tdls_check_tx = MFALSE;
4752 }
4753 
4754 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
4755 /**
4756  *  @brief  check the tx packet for tdls auto set up
4757  *
4758  *  @param priv      A pointer to moal_private structure
4759  *  @param skb       A pointer to skb buffer.
4760  *
4761  *  @return          N/A
4762  */
4763 void
4764 woal_tdls_check_tx(moal_private *priv, struct sk_buff *skb)
4765 {
4766 	struct tdls_peer *peer = NULL;
4767 	unsigned long flags;
4768 	t_u8 ra[MLAN_MAC_ADDR_LENGTH];
4769 	ENTER();
4770 	memcpy(ra, skb->data, MLAN_MAC_ADDR_LENGTH);
4771 	spin_lock_irqsave(&priv->tdls_lock, flags);
4772 	list_for_each_entry(peer, &priv->tdls_list, link) {
4773 		if (!memcmp(peer->peer_addr, ra, ETH_ALEN)) {
4774 			if (peer->rssi &&
4775 			    (peer->rssi <= TDLS_RSSI_HIGH_THRESHOLD)) {
4776 				if ((peer->link_status == TDLS_NOT_SETUP) &&
4777 				    (peer->num_failure <
4778 				     TDLS_MAX_FAILURE_COUNT)) {
4779 					peer->link_status =
4780 						TDLS_SETUP_INPROGRESS;
4781 					PRINTM(MMSG,
4782 					       "Wlan: Set up TDLS link,peer="
4783 					       MACSTR " rssi=%d\n",
4784 					       MAC2STR(peer->peer_addr),
4785 					       -peer->rssi);
4786 					cfg80211_tdls_oper_request(priv->netdev,
4787 								   peer->
4788 								   peer_addr,
4789 								   NL80211_TDLS_SETUP,
4790 								   0,
4791 								   GFP_ATOMIC);
4792 					priv->tdls_check_tx = MFALSE;
4793 				}
4794 
4795 			}
4796 			break;
4797 		}
4798 	}
4799 	spin_unlock_irqrestore(&priv->tdls_lock, flags);
4800 	LEAVE();
4801 }
4802 #endif
4803 
4804 /**
4805  *  @brief This function flush tcp session queue
4806  *
4807  *  @param priv      A pointer to moal_private structure
4808  *
4809  *  @return          N/A
4810  */
4811 void
4812 woal_flush_tcp_sess_queue(moal_private *priv)
4813 {
4814 	struct tcp_sess *tcp_sess = NULL, *tmp_node;
4815 	unsigned long flags;
4816 	struct sk_buff *skb;
4817 	spin_lock_irqsave(&priv->tcp_sess_lock, flags);
4818 	list_for_each_entry_safe(tcp_sess, tmp_node, &priv->tcp_sess_queue,
4819 				 link) {
4820 		list_del(&tcp_sess->link);
4821 		if (tcp_sess->is_timer_set)
4822 			woal_cancel_timer(&tcp_sess->ack_timer);
4823 		skb = (struct sk_buff *)tcp_sess->ack_skb;
4824 		if (skb)
4825 			dev_kfree_skb_any(skb);
4826 		kfree(tcp_sess);
4827 	}
4828 	INIT_LIST_HEAD(&priv->tcp_sess_queue);
4829 	priv->tcp_ack_drop_cnt = 0;
4830 	priv->tcp_ack_cnt = 0;
4831 	spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
4832 }
4833 
4834 /**
4835  *  @brief This function gets tcp session from the tcp session queue
4836  *
4837  *  @param priv      A pointer to moal_private structure
4838  *  @param src_ip    IP address of the device
4839  *  @param src_port  TCP port of the device
4840  *  @param dst_ip    IP address of the client
4841  *  @param dst_port  TCP port of the client
4842  *
4843  *  @return          A pointer to the tcp session data structure, if found.
4844  *                   Otherwise, null
4845  */
4846 static inline struct tcp_sess *
4847 woal_get_tcp_sess(moal_private *priv,
4848 		  t_u32 src_ip, t_u16 src_port, t_u32 dst_ip, t_u16 dst_port)
4849 {
4850 	struct tcp_sess *tcp_sess = NULL;
4851 	ENTER();
4852 
4853 	list_for_each_entry(tcp_sess, &priv->tcp_sess_queue, link) {
4854 		if ((tcp_sess->src_ip_addr == src_ip) &&
4855 		    (tcp_sess->src_tcp_port == src_port) &&
4856 		    (tcp_sess->dst_ip_addr == dst_ip) &&
4857 		    (tcp_sess->dst_tcp_port == dst_port)) {
4858 			LEAVE();
4859 			return tcp_sess;
4860 		}
4861 	}
4862 	LEAVE();
4863 	return NULL;
4864 }
4865 
4866 /**
4867  *  @brief This function send the holding tcp ack packet
4868  *  re-assoc thread.
4869  *
4870  *  @param context  A pointer to context
4871  *  @return         N/A
4872  */
4873 void
4874 woal_tcp_ack_timer_func(void *context)
4875 {
4876 	struct tcp_sess *tcp_session = (struct tcp_sess *)context;
4877 	moal_private *priv = (moal_private *)tcp_session->priv;
4878 	unsigned long flags;
4879 	mlan_buffer *pmbuf;
4880 	struct sk_buff *skb;
4881 	mlan_status status;
4882 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
4883 	t_u32 index = 0;
4884 #endif
4885 	ENTER();
4886 	spin_lock_irqsave(&priv->tcp_sess_lock, flags);
4887 	tcp_session->is_timer_set = MFALSE;
4888 	skb = (struct sk_buff *)tcp_session->ack_skb;
4889 	pmbuf = (mlan_buffer *)tcp_session->pmbuf;
4890 	tcp_session->ack_skb = NULL;
4891 	tcp_session->pmbuf = NULL;
4892 	spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
4893 	if (skb && pmbuf) {
4894 		status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
4895 		switch (status) {
4896 		case MLAN_STATUS_PENDING:
4897 			atomic_inc(&priv->phandle->tx_pending);
4898 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
4899 			index = skb_get_queue_mapping(skb);
4900 			atomic_inc(&priv->wmm_tx_pending[index]);
4901 			if (atomic_read(&priv->wmm_tx_pending[index]) >=
4902 			    MAX_TX_PENDING) {
4903 				struct netdev_queue *txq =
4904 					netdev_get_tx_queue(priv->netdev,
4905 							    index);
4906 				netif_tx_stop_queue(txq);
4907 				PRINTM(MINFO, "Stop Kernel Queue : %d\n",
4908 				       index);
4909 			}
4910 #else
4911 			if (atomic_read(&priv->phandle->tx_pending) >=
4912 			    MAX_TX_PENDING)
4913 				woal_stop_queue(priv->netdev);
4914 #endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29) */
4915 			queue_work(priv->phandle->workqueue,
4916 				   &priv->phandle->main_work);
4917 			break;
4918 		case MLAN_STATUS_SUCCESS:
4919 			priv->stats.tx_packets++;
4920 			priv->stats.tx_bytes += skb->len;
4921 			dev_kfree_skb_any(skb);
4922 			break;
4923 		case MLAN_STATUS_FAILURE:
4924 		default:
4925 			priv->stats.tx_dropped++;
4926 			dev_kfree_skb_any(skb);
4927 			break;
4928 		}
4929 	}
4930 	LEAVE();
4931 	return;
4932 }
4933 
4934 /**
4935  *  @brief This function send the tcp ack
4936  *
4937  *
4938  *  @param priv         A pointer to moal_private structure
4939  *  @param tcp_session  A pointer to tcp_session
4940  *  @return         N/A
4941  */
4942 void
4943 woal_send_tcp_ack(moal_private *priv, struct tcp_sess *tcp_session)
4944 {
4945 	mlan_status status;
4946 	struct sk_buff *skb = (struct sk_buff *)tcp_session->ack_skb;
4947 	mlan_buffer *pmbuf = (mlan_buffer *)tcp_session->pmbuf;
4948 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
4949 	t_u32 index = 0;
4950 #endif
4951 	ENTER();
4952 	if (tcp_session->is_timer_set) {
4953 		woal_cancel_timer(&tcp_session->ack_timer);
4954 		tcp_session->is_timer_set = MFALSE;
4955 	}
4956 	tcp_session->ack_skb = NULL;
4957 	tcp_session->pmbuf = NULL;
4958 	status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
4959 	switch (status) {
4960 	case MLAN_STATUS_PENDING:
4961 		atomic_inc(&priv->phandle->tx_pending);
4962 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
4963 		index = skb_get_queue_mapping(skb);
4964 		atomic_inc(&priv->wmm_tx_pending[index]);
4965 		if (atomic_read(&priv->wmm_tx_pending[index]) >= MAX_TX_PENDING) {
4966 			struct netdev_queue *txq =
4967 				netdev_get_tx_queue(priv->netdev, index);
4968 			netif_tx_stop_queue(txq);
4969 			PRINTM(MINFO, "Stop Kernel Queue : %d\n", index);
4970 		}
4971 #else
4972 		if (atomic_read(&priv->phandle->tx_pending) >= MAX_TX_PENDING)
4973 			woal_stop_queue(priv->netdev);
4974 #endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29) */
4975 		queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
4976 		break;
4977 	case MLAN_STATUS_SUCCESS:
4978 		priv->stats.tx_packets++;
4979 		priv->stats.tx_bytes += skb->len;
4980 		dev_kfree_skb_any(skb);
4981 		break;
4982 	case MLAN_STATUS_FAILURE:
4983 	default:
4984 		priv->stats.tx_dropped++;
4985 		dev_kfree_skb_any(skb);
4986 		break;
4987 	}
4988 	LEAVE();
4989 }
4990 
4991 /**
4992  *  @brief This function get the tcp ack session node
4993  *
4994  *  @param priv      A pointer to moal_private structure
4995  *  @param pmbuf     A pointer to mlan_buffer associated with a skb
4996  *
4997  *  @return          1, if it's dropped; 0, if not dropped
4998  */
4999 int
5000 woal_process_tcp_ack(moal_private *priv, mlan_buffer *pmbuf)
5001 {
5002 	int ret = 0;
5003 	unsigned long flags;
5004 	struct tcp_sess *tcp_session;
5005 	struct ethhdr *ethh = NULL;
5006 	struct iphdr *iph = NULL;
5007 	struct tcphdr *tcph = NULL;
5008 	t_u32 ack_seq;
5009 	struct sk_buff *skb;
5010 
5011 	ENTER();
5012 
5013 	/** check the tcp packet */
5014 	ethh = (struct ethhdr *)(pmbuf->pbuf + pmbuf->data_offset);
5015 	if (ntohs(ethh->h_proto) != ETH_P_IP) {
5016 		LEAVE();
5017 		return 0;
5018 	}
5019 	iph = (struct iphdr *)((t_u8 *)ethh + sizeof(struct ethhdr));
5020 	if (iph->protocol != IPPROTO_TCP) {
5021 		LEAVE();
5022 		return 0;
5023 	}
5024 	tcph = (struct tcphdr *)((t_u8 *)iph + iph->ihl * 4);
5025 
5026 	if (*((t_u8 *)tcph + 13) == 0x10) {
5027 		/* Only replace ACK */
5028 		if (ntohs(iph->tot_len) > (iph->ihl + tcph->doff) * 4) {
5029 			/* Don't drop ACK with payload */
5030 			/* TODO: should we delete previous TCP session */
5031 			LEAVE();
5032 			return ret;
5033 		}
5034 		priv->tcp_ack_cnt++;
5035 		spin_lock_irqsave(&priv->tcp_sess_lock, flags);
5036 		tcp_session = woal_get_tcp_sess(priv, iph->saddr,
5037 						tcph->source, iph->daddr,
5038 						tcph->dest);
5039 		if (!tcp_session) {
5040 			tcp_session =
5041 				kmalloc(sizeof(struct tcp_sess), GFP_ATOMIC);
5042 			if (!tcp_session) {
5043 				PRINTM(MERROR, "Fail to allocate tcp_sess.\n");
5044 				spin_unlock_irqrestore(&priv->tcp_sess_lock,
5045 						       flags);
5046 				goto done;
5047 			}
5048 			tcp_session->ack_skb = pmbuf->pdesc;
5049 			tcp_session->pmbuf = pmbuf;
5050 			pmbuf->flags |= MLAN_BUF_FLAG_TCP_ACK;
5051 			tcp_session->src_ip_addr = iph->saddr;
5052 			tcp_session->dst_ip_addr = iph->daddr;
5053 			tcp_session->src_tcp_port = tcph->source;
5054 			tcp_session->dst_tcp_port = tcph->dest;
5055 			tcp_session->ack_seq = ntohl(tcph->ack_seq);
5056 			tcp_session->priv = (void *)priv;
5057 			skb = (struct sk_buff *)pmbuf->pdesc;
5058 			skb->cb[0] = 0;
5059 			/* Initialize the timer for tcp ack */
5060 			woal_initialize_timer(&tcp_session->ack_timer,
5061 					      woal_tcp_ack_timer_func,
5062 					      tcp_session);
5063 			tcp_session->is_timer_set = MTRUE;
5064 			woal_mod_timer(&tcp_session->ack_timer, MOAL_TIMER_1MS);
5065 			list_add_tail(&tcp_session->link,
5066 				      &priv->tcp_sess_queue);
5067 			spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
5068 			ret = HOLD_TCP_ACK;
5069 			LEAVE();
5070 			return ret;
5071 		} else if (!tcp_session->ack_skb) {
5072 			tcp_session->ack_skb = pmbuf->pdesc;
5073 			tcp_session->pmbuf = pmbuf;
5074 			pmbuf->flags |= MLAN_BUF_FLAG_TCP_ACK;
5075 			tcp_session->ack_seq = ntohl(tcph->ack_seq);
5076 			tcp_session->priv = (void *)priv;
5077 			skb = (struct sk_buff *)pmbuf->pdesc;
5078 			skb->cb[0] = 0;
5079 			tcp_session->is_timer_set = MTRUE;
5080 			woal_mod_timer(&tcp_session->ack_timer, MOAL_TIMER_1MS);
5081 			spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
5082 			ret = HOLD_TCP_ACK;
5083 			LEAVE();
5084 			return ret;
5085 		}
5086 		ack_seq = ntohl(tcph->ack_seq);
5087 		skb = (struct sk_buff *)tcp_session->ack_skb;
5088 		if (likely(ack_seq > tcp_session->ack_seq) &&
5089 		    (skb->len == pmbuf->data_len)) {
5090 			memcpy(skb->data, pmbuf->pbuf + pmbuf->data_offset,
5091 			       pmbuf->data_len);
5092 			tcp_session->ack_seq = ack_seq;
5093 			ret = DROP_TCP_ACK;
5094 			skb->cb[0]++;
5095 //We will drop 90% tcp ack
5096 #define TCP_ACK_MAX_HOLD    9
5097 			if (skb->cb[0] >= TCP_ACK_MAX_HOLD)
5098 				woal_send_tcp_ack(priv, tcp_session);
5099 			spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
5100 			skb = (struct sk_buff *)pmbuf->pdesc;
5101 			dev_kfree_skb_any(skb);
5102 			priv->tcp_ack_drop_cnt++;
5103 		} else {
5104 			pmbuf->flags |= MLAN_BUF_FLAG_TCP_ACK;
5105 			spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
5106 			LEAVE();
5107 			return ret;
5108 		}
5109 	}
5110 done:
5111 	LEAVE();
5112 	return ret;
5113 }
5114 
5115 /**
5116  *  @brief This function handles packet transmission
5117  *
5118  *  @param skb     A pointer to sk_buff structure
5119  *  @param dev     A pointer to net_device structure
5120  *
5121  *  @return        0 --success
5122  */
5123 int
5124 woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
5125 {
5126 	moal_private *priv = (moal_private *)netdev_priv(dev);
5127 	mlan_buffer *pmbuf = NULL;
5128 	mlan_status status;
5129 	struct sk_buff *new_skb = NULL;
5130 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
5131 	t_u32 index = 0;
5132 #endif
5133 	int ret = 0;
5134 	ENTER();
5135 	PRINTM(MDATA, "%lu : %s (bss=%d): Data <= kernel\n",
5136 	       jiffies, dev->name, priv->bss_index);
5137 
5138 	if (priv->phandle->surprise_removed == MTRUE) {
5139 		dev_kfree_skb_any(skb);
5140 		priv->stats.tx_dropped++;
5141 		goto done;
5142 	}
5143 	priv->num_tx_timeout = 0;
5144 	if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
5145 		PRINTM(MERROR, "Tx Error: Bad skb length %d : %d\n",
5146 		       skb->len, ETH_FRAME_LEN);
5147 		dev_kfree_skb_any(skb);
5148 		priv->stats.tx_dropped++;
5149 		goto done;
5150 	}
5151 	if (skb_headroom(skb) < (MLAN_MIN_DATA_HEADER_LEN +
5152 				 sizeof(mlan_buffer) +
5153 				 priv->extra_tx_head_len)) {
5154 		PRINTM(MWARN, "Tx: Insufficient skb headroom %d\n",
5155 		       skb_headroom(skb));
5156 		/* Insufficient skb headroom - allocate a new skb */
5157 		new_skb = skb_realloc_headroom(skb, MLAN_MIN_DATA_HEADER_LEN +
5158 					       sizeof(mlan_buffer) +
5159 					       priv->extra_tx_head_len);
5160 		if (unlikely(!new_skb)) {
5161 			PRINTM(MERROR, "Tx: Cannot allocate skb\n");
5162 			dev_kfree_skb_any(skb);
5163 			priv->stats.tx_dropped++;
5164 			goto done;
5165 		}
5166 		if (new_skb != skb)
5167 			dev_kfree_skb_any(skb);
5168 		skb = new_skb;
5169 		PRINTM(MINFO, "new skb headroom %d\n", skb_headroom(skb));
5170 	}
5171 	pmbuf = (mlan_buffer *)skb->head;
5172 	memset((t_u8 *)pmbuf, 0, sizeof(mlan_buffer));
5173 	pmbuf->bss_index = priv->bss_index;
5174 	woal_fill_mlan_buffer(priv, pmbuf, skb);
5175 	if (priv->enable_tcp_ack_enh == MTRUE) {
5176 		ret = woal_process_tcp_ack(priv, pmbuf);
5177 		if (ret)
5178 			goto done;
5179 	}
5180 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
5181 	if (priv->enable_auto_tdls && priv->tdls_check_tx)
5182 		woal_tdls_check_tx(priv, skb);
5183 #endif
5184 
5185 	status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
5186 	switch (status) {
5187 	case MLAN_STATUS_PENDING:
5188 		atomic_inc(&priv->phandle->tx_pending);
5189 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
5190 		index = skb_get_queue_mapping(skb);
5191 		atomic_inc(&priv->wmm_tx_pending[index]);
5192 		if (atomic_read(&priv->wmm_tx_pending[index]) >= MAX_TX_PENDING) {
5193 			struct netdev_queue *txq =
5194 				netdev_get_tx_queue(priv->netdev, index);
5195 			netif_tx_stop_queue(txq);
5196 			PRINTM(MINFO, "Stop Kernel Queue : %d\n", index);
5197 		}
5198 #else
5199 		if (atomic_read(&priv->phandle->tx_pending) >= MAX_TX_PENDING)
5200 			woal_stop_queue(priv->netdev);
5201 #endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29) */
5202 		if (!mlan_is_main_process_running(priv->phandle->pmlan_adapter))
5203 			 queue_work(priv->phandle->workqueue,
5204 				    &priv->phandle->main_work);
5205 		break;
5206 	case MLAN_STATUS_SUCCESS:
5207 		priv->stats.tx_packets++;
5208 		priv->stats.tx_bytes += skb->len;
5209 		dev_kfree_skb_any(skb);
5210 		break;
5211 	case MLAN_STATUS_FAILURE:
5212 	default:
5213 		priv->stats.tx_dropped++;
5214 		dev_kfree_skb_any(skb);
5215 		break;
5216 	}
5217 done:
5218 	LEAVE();
5219 	return 0;
5220 }
5221 
5222 /**
5223  *  @brief Convert ascii string to Hex integer
5224  *
5225  *  @param d        A pointer to integer buf
5226  *  @param s        A pointer to ascii string
5227  *  @param dlen     The byte number of ascii string in hex
5228  *
5229  *  @return         Number of integer
5230  */
5231 int
5232 woal_ascii2hex(t_u8 *d, char *s, t_u32 dlen)
5233 {
5234 	unsigned int i;
5235 	t_u8 n;
5236 
5237 	ENTER();
5238 
5239 	memset(d, 0x00, dlen);
5240 
5241 	for (i = 0; i < dlen * 2; i++) {
5242 		if ((s[i] >= 48) && (s[i] <= 57))
5243 			n = s[i] - 48;
5244 		else if ((s[i] >= 65) && (s[i] <= 70))
5245 			n = s[i] - 55;
5246 		else if ((s[i] >= 97) && (s[i] <= 102))
5247 			n = s[i] - 87;
5248 		else
5249 			break;
5250 		if (!(i % 2))
5251 			n = n * 16;
5252 		d[i / 2] += n;
5253 	}
5254 
5255 	LEAVE();
5256 	return i;
5257 }
5258 
5259 /**
5260  *  @brief Return integer value of a given ascii string
5261  *
5262  *  @param data    Converted data to be returned
5263  *  @param a       String to be converted
5264  *
5265  *  @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
5266  */
5267 mlan_status
5268 woal_atoi(int *data, char *a)
5269 {
5270 	int i, val = 0, len;
5271 	int mul = 1;
5272 
5273 	ENTER();
5274 
5275 	len = strlen(a);
5276 	if (len > 2) {
5277 		if (!strncmp(a, "0x", 2)) {
5278 			a = a + 2;
5279 			len -= 2;
5280 			*data = woal_atox(a);
5281 			LEAVE();
5282 			return MLAN_STATUS_SUCCESS;
5283 		}
5284 	}
5285 	for (i = 0; i < len; i++) {
5286 		if (isdigit(a[i])) {
5287 			val = val * 10 + (a[i] - '0');
5288 		} else {
5289 			if ((i == 0) && (a[i] == '-')) {
5290 				mul = -1;
5291 			} else {
5292 				PRINTM(MERROR, "Invalid char %c in string %s\n",
5293 				       a[i], a);
5294 				LEAVE();
5295 				return MLAN_STATUS_FAILURE;
5296 			}
5297 		}
5298 	}
5299 	*data = (mul * val);
5300 
5301 	LEAVE();
5302 	return MLAN_STATUS_SUCCESS;
5303 }
5304 
5305 /**
5306  *  @brief Return hex value of a given ascii string
5307  *
5308  *  @param a        String to be converted to ascii
5309  *
5310  *  @return         The converted character if a is a valid hex, else 0
5311  */
5312 int
5313 woal_atox(char *a)
5314 {
5315 	int i = 0;
5316 
5317 	ENTER();
5318 
5319 	while (isxdigit(*a))
5320 		i = i * 16 + woal_hexval(*a++);
5321 
5322 	LEAVE();
5323 	return i;
5324 }
5325 
5326 /**
5327  *  @brief Extension of strsep lib command. This function will also take care
5328  *      escape character
5329  *
5330  *  @param s         A pointer to array of chars to process
5331  *  @param delim     The delimiter character to end the string
5332  *  @param esc       The escape character to ignore for delimiter
5333  *
5334  *  @return          Pointer to the separated string if delim found, else NULL
5335  */
5336 char *
5337 woal_strsep(char **s, char delim, char esc)
5338 {
5339 	char *se = *s, *sb;
5340 
5341 	ENTER();
5342 
5343 	if (!(*s) || (*se == '\0')) {
5344 		LEAVE();
5345 		return NULL;
5346 	}
5347 
5348 	for (sb = *s; *sb != '\0'; ++sb) {
5349 		if (*sb == esc && *(sb + 1) == esc) {
5350 			/*
5351 			 * We get a esc + esc seq then keep the one esc
5352 			 * and chop off the other esc character
5353 			 */
5354 			memmove(sb, sb + 1, strlen(sb));
5355 			continue;
5356 		}
5357 		if (*sb == esc && *(sb + 1) == delim) {
5358 			/*
5359 			 * We get a delim + esc seq then keep the delim
5360 			 * and chop off the esc character
5361 			 */
5362 			memmove(sb, sb + 1, strlen(sb));
5363 			continue;
5364 		}
5365 		if (*sb == delim)
5366 			break;
5367 	}
5368 
5369 	if (*sb == '\0')
5370 		sb = NULL;
5371 	else
5372 		*sb++ = '\0';
5373 
5374 	*s = sb;
5375 
5376 	LEAVE();
5377 	return se;
5378 }
5379 
5380 /**
5381  *  @brief Convert mac address from string to t_u8 buffer.
5382  *
5383  *  @param mac_addr The buffer to store the mac address in.
5384  *  @param buf      The source of mac address which is a string.
5385  *
5386  *  @return         N/A
5387  */
5388 void
5389 woal_mac2u8(t_u8 *mac_addr, char *buf)
5390 {
5391 	char *begin, *end, *mac_buff;
5392 	int i;
5393 
5394 	ENTER();
5395 
5396 	if (!buf) {
5397 		LEAVE();
5398 		return;
5399 	}
5400 
5401 	mac_buff = kzalloc(strlen(buf) + 1, GFP_KERNEL);
5402 	if (!mac_buff) {
5403 		LEAVE();
5404 		return;
5405 	}
5406 	memcpy(mac_buff, buf, strlen(buf));
5407 
5408 	begin = mac_buff;
5409 	for (i = 0; i < ETH_ALEN; ++i) {
5410 		end = woal_strsep(&begin, ':', '/');
5411 		if (end)
5412 			mac_addr[i] = woal_atox(end);
5413 	}
5414 
5415 	kfree(mac_buff);
5416 	LEAVE();
5417 }
5418 
5419 #ifdef STA_SUPPORT
5420 /**
5421  *  @brief This function sets multicast addresses to firmware
5422  *
5423  *  @param dev     A pointer to net_device structure
5424  *
5425  *  @return        N/A
5426  */
5427 void
5428 woal_set_multicast_list(struct net_device *dev)
5429 {
5430 	moal_private *priv = (moal_private *)netdev_priv(dev);
5431 	ENTER();
5432 	woal_request_set_multicast_list(priv, dev);
5433 	LEAVE();
5434 }
5435 #endif
5436 
5437 /**
5438  *  @brief This function initializes the private structure
5439  *          and set default value to the member of moal_private.
5440  *
5441  *  @param priv             A pointer to moal_private structure
5442  *  @param wait_option      Wait option
5443  *
5444  *  @return                 N/A
5445  */
5446 void
5447 woal_init_priv(moal_private *priv, t_u8 wait_option)
5448 {
5449 	ENTER();
5450 #ifdef STA_SUPPORT
5451 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
5452 		priv->current_key_index = 0;
5453 		priv->rate_index = AUTO_RATE;
5454 		priv->is_adhoc_link_sensed = MFALSE;
5455 		priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
5456 		priv->bg_scan_start = MFALSE;
5457 		priv->bg_scan_reported = MFALSE;
5458 		memset(&priv->nick_name, 0, sizeof(priv->nick_name));
5459 		priv->num_tx_timeout = 0;
5460 		priv->rx_filter = 0;
5461 
5462 #ifdef REASSOCIATION
5463 		priv->reassoc_on = MFALSE;
5464 		priv->set_asynced_essid_flag = MFALSE;
5465 #endif
5466 #ifdef STA_CFG80211
5467 		memset(&priv->sme_current, 0,
5468 		       sizeof(struct cfg80211_connect_params));
5469 #endif
5470 	}
5471 #endif /* STA_SUPPORT */
5472 #ifdef UAP_SUPPORT
5473 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
5474 		priv->bss_started = MFALSE;
5475 #ifdef UAP_CFG80211
5476 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
5477 		memset(&priv->chan, 0, sizeof(struct cfg80211_chan_def));
5478 		memset(&priv->csa_chan, 0, sizeof(struct cfg80211_chan_def));
5479 		priv->uap_tx_blocked = MFALSE;
5480 		memset(&priv->beacon_after, 0,
5481 		       sizeof(struct cfg80211_beacon_data));
5482 #endif
5483 #endif
5484 	}
5485 #endif
5486 
5487 	memset(&priv->tx_protocols, 0, sizeof(dot11_protocol));
5488 	memset(&priv->rx_protocols, 0, sizeof(dot11_protocol));
5489 	priv->media_connected = MFALSE;
5490 
5491 	memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map));
5492 
5493 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
5494 	priv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
5495 	priv->beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
5496 	priv->proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
5497 	priv->assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
5498 	priv->beacon_wps_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
5499 	priv->proberesp_p2p_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
5500 	priv->assocresp_qos_map_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
5501 	priv->proberesp_vendor_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
5502 #endif
5503 
5504 #ifdef STA_SUPPORT
5505 	priv->pmk_saved = MFALSE;
5506 	memset(&priv->pmk, 0, sizeof(mlan_pmk_t));
5507 #endif
5508 
5509 	priv->enable_tcp_ack_enh = MTRUE;
5510 
5511 	priv->enable_auto_tdls = MFALSE;
5512 	priv->tdls_check_tx = MFALSE;
5513 
5514 	priv->gtk_data_ready = MFALSE;
5515 	memset(&priv->gtk_rekey_data, 0, sizeof(mlan_ds_misc_gtk_rekey_data));
5516 
5517 	woal_request_get_fw_info(priv, wait_option, NULL);
5518 
5519 #if defined(WIFI_DIRECT_SUPPORT)
5520 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
5521 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
5522 #ifdef MFG_CMD_SUPPORT
5523 	if (mfg_mode != MLAN_INIT_PARA_ENABLED)
5524 #endif
5525 		if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
5526 			if (priv->bss_virtual) {
5527 				if (priv->pa_netdev) {
5528 					memcpy(priv->current_addr,
5529 					       priv->pa_netdev->dev_addr,
5530 					       ETH_ALEN);
5531 					priv->current_addr[4] ^= 0x80;
5532 					woal_request_set_mac_address(priv);
5533 					memcpy(priv->netdev->dev_addr,
5534 					       priv->current_addr, ETH_ALEN);
5535 					PRINTM(MCMND,
5536 					       "Set WFD interface addr: " MACSTR
5537 					       "\n",
5538 					       MAC2STR(priv->current_addr));
5539 				}
5540 			} else {
5541 				priv->current_addr[0] |= 0x02;
5542 				woal_request_set_mac_address(priv);
5543 				memcpy(priv->netdev->dev_addr,
5544 				       priv->current_addr, ETH_ALEN);
5545 				PRINTM(MCMND,
5546 				       "Set WFD device addr: " MACSTR "\n",
5547 				       MAC2STR(priv->current_addr));
5548 			}
5549 		}
5550 #endif
5551 #endif
5552 #endif
5553 #ifdef UAP_SUPPORT
5554 #if defined(DFS_TESTING_SUPPORT)
5555 	priv->user_cac_period_msec = 0;
5556 #endif
5557 #endif
5558 	LEAVE();
5559 }
5560 
5561 /**
5562  *  @brief Reset all interfaces if all_intf flag is TRUE,
5563  *          otherwise specified interface only
5564  *
5565  *  @param priv          A pointer to moal_private structure
5566  *  @param wait_option   Wait option
5567  *  @param all_intf      TRUE  : all interfaces
5568  *                       FALSE : current interface only
5569  *
5570  *  @return             MLAN_STATUS_SUCCESS --success, otherwise fail
5571  */
5572 int
5573 woal_reset_intf(moal_private *priv, t_u8 wait_option, int all_intf)
5574 {
5575 	int ret = MLAN_STATUS_SUCCESS;
5576 	int intf_num;
5577 	moal_handle *handle = NULL;
5578 	mlan_bss_info bss_info;
5579 
5580 	ENTER();
5581 
5582 	if (!priv) {
5583 		LEAVE();
5584 		return MLAN_STATUS_FAILURE;
5585 	}
5586 	handle = priv->phandle;
5587 
5588 	/* Stop queue and detach device */
5589 	if (!all_intf) {
5590 		woal_stop_queue(priv->netdev);
5591 		netif_device_detach(priv->netdev);
5592 	} else {
5593 		for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
5594 			woal_stop_queue(handle->priv[intf_num]->netdev);
5595 			netif_device_detach(handle->priv[intf_num]->netdev);
5596 		}
5597 	}
5598 
5599 	/* Get BSS info */
5600 	memset(&bss_info, 0, sizeof(bss_info));
5601 	woal_get_bss_info(priv, wait_option, &bss_info);
5602 
5603 #ifdef STA_SUPPORT
5604 	woal_cancel_scan(priv, wait_option);
5605 #endif
5606 
5607 	/* Cancel host sleep */
5608 	if (bss_info.is_hs_configured) {
5609 		if (MLAN_STATUS_SUCCESS != woal_cancel_hs(priv, wait_option)) {
5610 			ret = -EFAULT;
5611 			goto done;
5612 		}
5613 	}
5614 
5615 	/* Disconnect from network */
5616 	if (!all_intf) {
5617 		/* Disconnect specified interface only */
5618 		if ((priv->media_connected == MTRUE)
5619 #ifdef UAP_SUPPORT
5620 		    || (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
5621 #endif
5622 			) {
5623 			woal_disconnect(priv, wait_option, NULL,
5624 					DEF_DEAUTH_REASON_CODE);
5625 			priv->media_connected = MFALSE;
5626 		}
5627 	} else {
5628 		/* Disconnect all interfaces */
5629 		for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
5630 			if (handle->priv[intf_num]->media_connected == MTRUE
5631 #ifdef UAP_SUPPORT
5632 			    || (GET_BSS_ROLE(handle->priv[intf_num]) ==
5633 				MLAN_BSS_ROLE_UAP)
5634 #endif
5635 				) {
5636 				woal_disconnect(handle->priv[intf_num],
5637 						wait_option, NULL,
5638 						DEF_DEAUTH_REASON_CODE);
5639 				handle->priv[intf_num]->media_connected =
5640 					MFALSE;
5641 			}
5642 		}
5643 	}
5644 
5645 #ifdef REASSOCIATION
5646 	/* Reset the reassoc timer and status */
5647 	if (!all_intf) {
5648 		handle->reassoc_on &= ~MBIT(priv->bss_index);
5649 		priv->reassoc_on = MFALSE;
5650 		priv->set_asynced_essid_flag = MFALSE;
5651 	} else {
5652 		handle->reassoc_on = 0;
5653 		for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
5654 			handle->priv[intf_num]->reassoc_on = MFALSE;
5655 			handle->priv[intf_num]->set_asynced_essid_flag = MFALSE;
5656 		}
5657 	}
5658 	if (!handle->reassoc_on && handle->is_reassoc_timer_set) {
5659 		woal_cancel_timer(&handle->reassoc_timer);
5660 		handle->is_reassoc_timer_set = MFALSE;
5661 	}
5662 #endif /* REASSOCIATION */
5663 
5664 #if defined(WIFI_DIRECT_SUPPORT)
5665 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
5666 	if (handle->is_go_timer_set) {
5667 		woal_cancel_timer(&handle->go_timer);
5668 		handle->is_go_timer_set = MFALSE;
5669 	}
5670 #endif
5671 #endif
5672 
5673 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
5674 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
5675 	if (handle->is_remain_timer_set) {
5676 		woal_cancel_timer(&handle->remain_timer);
5677 		woal_remain_timer_func(handle);
5678 	}
5679 #endif
5680 #endif
5681 
5682 done:
5683 	LEAVE();
5684 	return ret;
5685 }
5686 
5687 /**
5688  *  @brief This function return the point to structure moal_private
5689  *
5690  *  @param handle       Pointer to structure moal_handle
5691  *  @param bss_index    BSS index number
5692  *
5693  *  @return             moal_private pointer or NULL
5694  */
5695 moal_private *
5696 woal_bss_index_to_priv(moal_handle *handle, t_u8 bss_index)
5697 {
5698 	int i;
5699 
5700 	ENTER();
5701 	if (!handle) {
5702 		LEAVE();
5703 		return NULL;
5704 	}
5705 	for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
5706 		if (handle->priv[i] &&
5707 		    (handle->priv[i]->bss_index == bss_index)) {
5708 			LEAVE();
5709 			return handle->priv[i];
5710 		}
5711 	}
5712 
5713 	LEAVE();
5714 	return NULL;
5715 }
5716 
5717 /**
5718  *  @brief This function alloc mlan_buffer.
5719  *  @param handle  A pointer to moal_handle structure
5720  *  @param size	   buffer size to allocate
5721  *
5722  *  @return        mlan_buffer pointer or NULL
5723  */
5724 pmlan_buffer
5725 woal_alloc_mlan_buffer(moal_handle *handle, int size)
5726 {
5727 	mlan_buffer *pmbuf = NULL;
5728 	struct sk_buff *skb;
5729 	gfp_t flag;
5730 
5731 	ENTER();
5732 
5733 	flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL;
5734 	if (size <= 0) {
5735 		PRINTM(MERROR, "Buffer size must be positive\n");
5736 		LEAVE();
5737 		return NULL;
5738 	}
5739 
5740 	skb = __dev_alloc_skb(size + sizeof(mlan_buffer), flag);
5741 	if (!skb) {
5742 		PRINTM(MERROR, "%s: No free skb\n", __func__);
5743 		LEAVE();
5744 		return NULL;
5745 	}
5746 	skb_reserve(skb, sizeof(mlan_buffer));
5747 	pmbuf = (mlan_buffer *)skb->head;
5748 	memset((u8 *)pmbuf, 0, sizeof(mlan_buffer));
5749 	pmbuf->pdesc = (t_void *)skb;
5750 	pmbuf->pbuf = (t_u8 *)skb->data;
5751 	atomic_inc(&handle->mbufalloc_count);
5752 	LEAVE();
5753 	return pmbuf;
5754 }
5755 
5756 /**
5757  *  @brief This function alloc mlan_ioctl_req.
5758  *
5759  *  @param size	   buffer size to allocate
5760  *
5761  *  @return        mlan_ioctl_req pointer or NULL
5762  */
5763 pmlan_ioctl_req
5764 woal_alloc_mlan_ioctl_req(int size)
5765 {
5766 	mlan_ioctl_req *req = NULL;
5767 	gfp_t flag;
5768 
5769 	ENTER();
5770 
5771 	flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL;
5772 	req = kzalloc((sizeof(mlan_ioctl_req) + size + sizeof(int) +
5773 		       sizeof(wait_queue)), flag);
5774 	if (!req) {
5775 		PRINTM(MERROR, "%s: Fail to alloc ioctl buffer\n", __func__);
5776 		LEAVE();
5777 		return NULL;
5778 	}
5779 	req->pbuf = (t_u8 *)req + sizeof(mlan_ioctl_req) + sizeof(wait_queue);
5780 	req->buf_len = (t_u32)size;
5781 	req->reserved_1 = (t_ptr)((t_u8 *)req + sizeof(mlan_ioctl_req));
5782 
5783 	LEAVE();
5784 	return req;
5785 }
5786 
5787 /**
5788  *  @brief This function frees mlan_buffer.
5789  *  @param handle  A pointer to moal_handle structure
5790  *  @param pmbuf   Pointer to mlan_buffer
5791  *
5792  *  @return        N/A
5793  */
5794 void
5795 woal_free_mlan_buffer(moal_handle *handle, pmlan_buffer pmbuf)
5796 {
5797 	ENTER();
5798 	if (!pmbuf) {
5799 		LEAVE();
5800 		return;
5801 	}
5802 	if (pmbuf->pdesc)
5803 		dev_kfree_skb_any((struct sk_buff *)pmbuf->pdesc);
5804 	else
5805 		PRINTM(MERROR, "free mlan buffer without pdesc\n");
5806 	atomic_dec(&handle->mbufalloc_count);
5807 	LEAVE();
5808 	return;
5809 }
5810 
5811 #ifdef STA_SUPPORT
5812 #endif /* STA_SUPPORT */
5813 
5814 /**
5815  *  @brief This function handles events generated by firmware
5816  *
5817  *  @param priv     A pointer to moal_private structure
5818  *  @param payload  A pointer to payload buffer
5819  *  @param len      Length of the payload
5820  *  @return         MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
5821  */
5822 mlan_status
5823 woal_broadcast_event(moal_private *priv, t_u8 *payload, t_u32 len)
5824 {
5825 	mlan_status ret = MLAN_STATUS_SUCCESS;
5826 	struct sk_buff *skb = NULL;
5827 	struct nlmsghdr *nlh = NULL;
5828 	moal_handle *handle = priv->phandle;
5829 	struct net_device *netdev = priv->netdev;
5830 	struct sock *sk = handle->nl_sk;
5831 
5832 	ENTER();
5833 
5834 	/* interface name to be prepended to event */
5835 	if ((len + IFNAMSIZ) > NL_MAX_PAYLOAD
5836 #ifdef WIFI_DIRECT_SUPPORT
5837 	    * 2
5838 #endif
5839 		) {
5840 		PRINTM(MERROR, "event size is too big, len=%d\n", (int)len);
5841 		ret = MLAN_STATUS_FAILURE;
5842 		goto done;
5843 	}
5844 	if (sk) {
5845 		/* Allocate skb */
5846 #ifdef WIFI_DIRECT_SUPPORT
5847 		if ((len + IFNAMSIZ) > NL_MAX_PAYLOAD) {
5848 			skb = alloc_skb(NLMSG_SPACE(NL_MAX_PAYLOAD * 2),
5849 					GFP_ATOMIC);
5850 			if (!skb) {
5851 				PRINTM(MERROR,
5852 				       "Could not allocate skb for netlink\n");
5853 				ret = MLAN_STATUS_FAILURE;
5854 				goto done;
5855 			}
5856 		} else {
5857 #endif
5858 			skb = alloc_skb(NLMSG_SPACE(NL_MAX_PAYLOAD),
5859 					GFP_ATOMIC);
5860 			if (!skb) {
5861 				PRINTM(MERROR,
5862 				       "Could not allocate skb for netlink\n");
5863 				ret = MLAN_STATUS_FAILURE;
5864 				goto done;
5865 			}
5866 #ifdef WIFI_DIRECT_SUPPORT
5867 		}
5868 #endif
5869 		nlh = (struct nlmsghdr *)skb->data;
5870 		nlh->nlmsg_len = NLMSG_SPACE(len + IFNAMSIZ);
5871 
5872 		/* From kernel */
5873 		nlh->nlmsg_pid = 0;
5874 		nlh->nlmsg_flags = 0;
5875 
5876 		/* Data */
5877 		skb_put(skb, nlh->nlmsg_len);
5878 		memcpy(NLMSG_DATA(nlh), netdev->name, IFNAMSIZ);
5879 		memcpy(((t_u8 *)(NLMSG_DATA(nlh))) + IFNAMSIZ, payload, len);
5880 
5881 		/* From Kernel */
5882 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
5883 		NETLINK_CB(skb).pid = 0;
5884 #else
5885 		NETLINK_CB(skb).portid = 0;
5886 #endif
5887 
5888 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
5889 		/* Multicast message */
5890 		NETLINK_CB(skb).dst_pid = 0;
5891 #endif
5892 
5893 		/* Multicast group number */
5894 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
5895 		NETLINK_CB(skb).dst_groups = NL_MULTICAST_GROUP;
5896 #else
5897 		NETLINK_CB(skb).dst_group = NL_MULTICAST_GROUP;
5898 #endif
5899 
5900 		/* Send message */
5901 		ret = netlink_broadcast(sk, skb, 0, NL_MULTICAST_GROUP,
5902 					GFP_ATOMIC);
5903 		if (ret) {
5904 			PRINTM(MWARN, "netlink_broadcast failed: ret=%d\n",
5905 			       ret);
5906 			goto done;
5907 		}
5908 
5909 		ret = MLAN_STATUS_SUCCESS;
5910 	} else {
5911 		PRINTM(MERROR,
5912 		       "Could not send event through NETLINK. Link down.\n");
5913 		ret = MLAN_STATUS_FAILURE;
5914 	}
5915 done:
5916 	LEAVE();
5917 	return ret;
5918 }
5919 
5920 #ifdef REASSOCIATION
5921 /**
5922  *  @brief This function handles re-association. it is triggered
5923  *  by re-assoc timer.
5924  *
5925  *  @param data    A pointer to wlan_thread structure
5926  *  @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
5927  */
5928 int
5929 woal_reassociation_thread(void *data)
5930 {
5931 	moal_thread *pmoal_thread = data;
5932 	moal_private *priv = NULL;
5933 	moal_handle *handle = (moal_handle *)pmoal_thread->handle;
5934 #if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 13, 0)
5935 	wait_queue_t wait;
5936 #else
5937 	wait_queue_entry_t wait;
5938 #endif
5939 	int i;
5940 	BOOLEAN reassoc_timer_req;
5941 	mlan_802_11_ssid req_ssid;
5942 	mlan_ssid_bssid ssid_bssid;
5943 	mlan_status status;
5944 	mlan_bss_info bss_info;
5945 	t_u32 timer_val = MOAL_TIMER_10S;
5946 	t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 };
5947 	ENTER();
5948 
5949 	woal_activate_thread(pmoal_thread);
5950 	init_waitqueue_entry(&wait, current);
5951 
5952 	current->flags |= PF_NOFREEZE;
5953 
5954 	for (;;) {
5955 		add_wait_queue(&pmoal_thread->wait_q, &wait);
5956 		set_current_state(TASK_INTERRUPTIBLE);
5957 
5958 		schedule();
5959 
5960 		set_current_state(TASK_RUNNING);
5961 		remove_wait_queue(&pmoal_thread->wait_q, &wait);
5962 
5963 		/* Cancel re-association timer */
5964 		if (handle->is_reassoc_timer_set == MTRUE) {
5965 			woal_cancel_timer(&handle->reassoc_timer);
5966 			handle->is_reassoc_timer_set = MFALSE;
5967 		}
5968 
5969 		if (handle->surprise_removed)
5970 			break;
5971 		if (kthread_should_stop())
5972 			break;
5973 
5974 		if (handle->hardware_status != HardwareStatusReady) {
5975 			PRINTM(MINFO,
5976 			       "Reassoc: Hardware status is not correct\n");
5977 			continue;
5978 		}
5979 
5980 		PRINTM(MEVENT, "Reassoc: Thread waking up...\n");
5981 		reassoc_timer_req = MFALSE;
5982 #ifdef STA_CFG80211
5983 		for (i = 0;
5984 		     i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM) &&
5985 		     (priv = handle->priv[i]); i++) {
5986 			if (priv->roaming_required) {
5987 				priv->roaming_required = MFALSE;
5988 				PRINTM(MEVENT, "Try to roaming......\n");
5989 				woal_start_roaming(priv);
5990 				break;
5991 			}
5992 		}
5993 #endif
5994 
5995 		for (i = 0;
5996 		     i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM) &&
5997 		     (priv = handle->priv[i]); i++) {
5998 
5999 			if (priv->reassoc_required == MFALSE) {
6000 				priv->set_asynced_essid_flag = MFALSE;
6001 				continue;
6002 			}
6003 
6004 			memset(&bss_info, 0x00, sizeof(bss_info));
6005 
6006 			if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
6007 								     MOAL_IOCTL_WAIT,
6008 								     &bss_info))
6009 			{
6010 				PRINTM(MINFO, "Ressoc: Fail to get bss info\n");
6011 				priv->reassoc_required = MFALSE;
6012 				priv->set_asynced_essid_flag = MFALSE;
6013 				continue;
6014 			}
6015 
6016 			if (bss_info.bss_mode != MLAN_BSS_MODE_INFRA ||
6017 			    priv->media_connected != MFALSE) {
6018 				PRINTM(MINFO,
6019 				       "Reassoc: ad-hoc mode or media connected\n");
6020 				priv->reassoc_required = MFALSE;
6021 				priv->set_asynced_essid_flag = MFALSE;
6022 				continue;
6023 			}
6024 	    /** avoid on going scan from other thread */
6025 			if (handle->scan_pending_on_block) {
6026 				reassoc_timer_req = MTRUE;
6027 				break;
6028 			}
6029 
6030 			/* The semaphore is used to avoid reassociation thread and
6031 			   wlan_set_scan/wlan_set_essid interrupting each other.
6032 			   Reassociation should be disabled completely by application if
6033 			   wlan_set_user_scan_ioctl/wlan_set_wap is used.
6034 			 */
6035 			if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
6036 				PRINTM(MERROR,
6037 				       "Acquire semaphore error, reassociation thread\n");
6038 				reassoc_timer_req = MTRUE;
6039 				break;
6040 			}
6041 
6042 			PRINTM(MINFO, "Reassoc: Required ESSID: %s\n",
6043 			       priv->prev_ssid_bssid.ssid.ssid);
6044 			PRINTM(MINFO, "Reassoc: Performing Active Scan\n");
6045 
6046 			memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid));
6047 			memcpy(&req_ssid,
6048 			       &priv->prev_ssid_bssid.ssid,
6049 			       sizeof(mlan_802_11_ssid));
6050 
6051 			/* Do specific SSID scanning */
6052 			if (MLAN_STATUS_SUCCESS !=
6053 			    woal_request_scan(priv, MOAL_IOCTL_WAIT,
6054 					      &req_ssid)) {
6055 				PRINTM(MERROR,
6056 				       "Reassoc: Fail to do specific scan\n");
6057 				reassoc_timer_req = MTRUE;
6058 				MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
6059 				break;
6060 			}
6061 
6062 			if (handle->surprise_removed) {
6063 				MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
6064 				break;
6065 			}
6066 
6067 			memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
6068 
6069 			if (priv->set_asynced_essid_flag == MTRUE) {
6070 				if (priv->assoc_with_mac &&
6071 				    memcmp(priv->prev_ssid_bssid.bssid,
6072 					   zero_mac, MLAN_MAC_ADDR_LENGTH)) {
6073 					/* Search AP by BSSID & SSID */
6074 					PRINTM(MINFO,
6075 					       "Reassoc: Search AP by BSSID & SSID\n");
6076 					memcpy(&ssid_bssid.bssid,
6077 					       &priv->prev_ssid_bssid.bssid,
6078 					       MLAN_MAC_ADDR_LENGTH);
6079 				} else {
6080 					/* Search AP by ESSID for asynced essid setting */
6081 					PRINTM(MINFO,
6082 					       "Set asynced essid: Search AP by ESSID\n");
6083 				}
6084 
6085 				memcpy(&ssid_bssid.ssid,
6086 				       &priv->prev_ssid_bssid.ssid,
6087 				       sizeof(mlan_802_11_ssid));
6088 			} else {
6089 				/* Search AP by BSSID first */
6090 				PRINTM(MINFO,
6091 				       "Reassoc: Search AP by BSSID first\n");
6092 				memcpy(&ssid_bssid.bssid,
6093 				       &priv->prev_ssid_bssid.bssid,
6094 				       MLAN_MAC_ADDR_LENGTH);
6095 			}
6096 
6097 			status = woal_find_best_network(priv, MOAL_IOCTL_WAIT,
6098 							&ssid_bssid);
6099 #ifdef STA_WEXT
6100 			if (status == MLAN_STATUS_SUCCESS) {
6101 				if (MLAN_STATUS_SUCCESS !=
6102 				    woal_11d_check_ap_channel(priv,
6103 							      MOAL_IOCTL_WAIT,
6104 							      &ssid_bssid)) {
6105 					PRINTM(MERROR,
6106 					       "Reassoc: The AP's channel is invalid for current region\n");
6107 					status = MLAN_STATUS_FAILURE;
6108 				}
6109 			}
6110 #endif
6111 	    /** The find AP without ssid, we need re-search */
6112 			if (status == MLAN_STATUS_SUCCESS &&
6113 			    !ssid_bssid.ssid.ssid_len) {
6114 				PRINTM(MINFO,
6115 				       "Reassoc: Skip AP without ssid\n");
6116 				status = MLAN_STATUS_FAILURE;
6117 			}
6118 
6119 			if (priv->set_asynced_essid_flag != MTRUE &&
6120 			    MLAN_STATUS_SUCCESS != status) {
6121 				PRINTM(MINFO,
6122 				       "Reassoc: AP not found in scan list\n");
6123 				PRINTM(MINFO, "Reassoc: Search AP by SSID\n");
6124 				/* Search AP by SSID */
6125 				memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
6126 				memcpy(&ssid_bssid.ssid,
6127 				       &priv->prev_ssid_bssid.ssid,
6128 				       sizeof(mlan_802_11_ssid));
6129 				status = woal_find_best_network(priv,
6130 								MOAL_IOCTL_WAIT,
6131 								&ssid_bssid);
6132 #ifdef STA_WEXT
6133 				if (status == MLAN_STATUS_SUCCESS) {
6134 					if (MLAN_STATUS_SUCCESS !=
6135 					    woal_11d_check_ap_channel(priv,
6136 								      MOAL_IOCTL_WAIT,
6137 								      &ssid_bssid))
6138 					{
6139 						PRINTM(MERROR,
6140 						       "Reassoc: The AP's channel is invalid for current region\n");
6141 						status = MLAN_STATUS_FAILURE;
6142 					}
6143 				}
6144 #endif
6145 			}
6146 
6147 			if (status == MLAN_STATUS_SUCCESS) {
6148 				/* set the wep key */
6149 				if (bss_info.wep_status)
6150 					woal_enable_wep_key(priv,
6151 							    MOAL_IOCTL_WAIT);
6152 				/* Zero SSID implies use BSSID to connect */
6153 				memset(&ssid_bssid.ssid, 0,
6154 				       sizeof(mlan_802_11_ssid));
6155 				status = woal_bss_start(priv, MOAL_IOCTL_WAIT,
6156 							&ssid_bssid);
6157 			}
6158 
6159 			if (priv->media_connected == MFALSE)
6160 				reassoc_timer_req = MTRUE;
6161 			else {
6162 				mlan_ds_rate *rate = NULL;
6163 				mlan_ioctl_req *req = NULL;
6164 
6165 				reassoc_timer_req = MFALSE;
6166 				if (priv->set_asynced_essid_flag == MTRUE) {
6167 					memset(&bss_info, 0, sizeof(bss_info));
6168 					if (MLAN_STATUS_SUCCESS !=
6169 					    woal_get_bss_info(priv,
6170 							      MOAL_IOCTL_WAIT,
6171 							      &bss_info)) {
6172 						PRINTM(MINFO,
6173 						       "Set asynced essid: Fail to get bss info after assoc\n");
6174 					} else {
6175 						memcpy(&priv->prev_ssid_bssid.
6176 						       ssid, &bss_info.ssid,
6177 						       sizeof
6178 						       (mlan_802_11_ssid));
6179 						memcpy(&priv->prev_ssid_bssid.
6180 						       bssid, &bss_info.bssid,
6181 						       MLAN_MAC_ADDR_LENGTH);
6182 					}
6183 					priv->set_asynced_essid_flag = MFALSE;
6184 				}
6185 				if (priv->rate_index != AUTO_RATE) {
6186 					req = woal_alloc_mlan_ioctl_req(sizeof
6187 									(mlan_ds_rate));
6188 
6189 					if (req == NULL) {
6190 						LEAVE();
6191 						return MLAN_STATUS_FAILURE;
6192 					}
6193 
6194 					rate = (mlan_ds_rate *)req->pbuf;
6195 					rate->param.rate_cfg.rate_type =
6196 						MLAN_RATE_INDEX;
6197 					rate->sub_command = MLAN_OID_RATE_CFG;
6198 					req->req_id = MLAN_IOCTL_RATE;
6199 
6200 					req->action = MLAN_ACT_SET;
6201 
6202 					rate->param.rate_cfg.rate =
6203 						priv->rate_index;
6204 
6205 					status = woal_request_ioctl(priv, req,
6206 								    MOAL_IOCTL_WAIT);
6207 					if (status != MLAN_STATUS_SUCCESS) {
6208 						if (status !=
6209 						    MLAN_STATUS_PENDING)
6210 							kfree(req);
6211 						LEAVE();
6212 						return MLAN_STATUS_FAILURE;
6213 					}
6214 					kfree(req);
6215 				}
6216 			}
6217 
6218 			MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
6219 		}
6220 
6221 		if (handle->surprise_removed)
6222 			break;
6223 
6224 		if (reassoc_timer_req == MTRUE) {
6225 			handle->is_reassoc_timer_set = MTRUE;
6226 			if (priv && (priv->set_asynced_essid_flag == MTRUE)) {
6227 				PRINTM(MERROR,
6228 				       "Set Async ESSID: No AP found or assoc failed.\n");
6229 				priv->set_asynced_essid_flag = MFALSE;
6230 			} else {
6231 				PRINTM(MEVENT,
6232 				       "Reassoc: No AP found or assoc failed. "
6233 				       "Restarting re-assoc Timer: %d\n",
6234 				       (int)timer_val);
6235 				woal_mod_timer(&handle->reassoc_timer,
6236 					       timer_val);
6237 			}
6238 		} else {
6239 			if (priv) {
6240 				priv->set_asynced_essid_flag = MFALSE;
6241 			}
6242 		}
6243 	}
6244 	woal_deactivate_thread(pmoal_thread);
6245 
6246 	LEAVE();
6247 	return MLAN_STATUS_SUCCESS;
6248 }
6249 
6250 /**
6251  *  @brief This function triggers re-association by waking up
6252  *  re-assoc thread.
6253  *
6254  *  @param context  A pointer to context
6255  *  @return         N/A
6256  */
6257 void
6258 woal_reassoc_timer_func(void *context)
6259 {
6260 	moal_handle *handle = (moal_handle *)context;
6261 
6262 	ENTER();
6263 
6264 	PRINTM(MINFO, "reassoc_timer fired.\n");
6265 	handle->is_reassoc_timer_set = MFALSE;
6266 
6267 	PRINTM(MINFO, "Waking Up the Reassoc Thread\n");
6268 	wake_up_interruptible(&handle->reassoc_thread.wait_q);
6269 
6270 	LEAVE();
6271 	return;
6272 }
6273 #endif /* REASSOCIATION */
6274 
6275 #ifdef STA_SUPPORT
6276 /**
6277  *  @brief update dscp mapping from assoc_resp/reassoc_resp
6278  *
6279  *  @param priv      Pointer to the moal_private driver data struct
6280  *
6281  *  @return          N/A
6282  */
6283 void
6284 woal_update_dscp_mapping(moal_private *priv)
6285 {
6286 	mlan_ds_misc_assoc_rsp assoc_rsp;
6287 	IEEEtypes_AssocRsp_t *passoc_rsp = NULL;
6288 	IEEEtypes_Header_t *qos_mapping_ie = NULL;
6289 	DSCP_Range_t *pdscp_range = NULL;
6290 	t_u8 dscp_except_num = 0;
6291 	DSCP_Exception_t dscp_except[MAX_DSCP_EXCEPTION_NUM];
6292 	int i, j;
6293 	ENTER();
6294 
6295 	memset(&assoc_rsp, 0, sizeof(mlan_ds_misc_assoc_rsp));
6296 	woal_get_assoc_rsp(priv, &assoc_rsp, MOAL_NO_WAIT);
6297 	passoc_rsp = (IEEEtypes_AssocRsp_t *)assoc_rsp.assoc_resp_buf;
6298 	memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map));
6299 	qos_mapping_ie =
6300 		(IEEEtypes_Header_t *)woal_parse_ie_tlv(passoc_rsp->ie_buffer,
6301 							assoc_rsp.
6302 							assoc_resp_len -
6303 							ASSOC_RESP_FIXED_SIZE,
6304 							QOS_MAPPING);
6305 	if (qos_mapping_ie &&
6306 	    (qos_mapping_ie->len >= (sizeof(DSCP_Range_t) * MAX_NUM_TID))) {
6307 		dscp_except_num =
6308 			(qos_mapping_ie->len -
6309 			 sizeof(DSCP_Range_t) * MAX_NUM_TID) /
6310 			sizeof(DSCP_Exception_t);
6311 		if (dscp_except_num > MAX_DSCP_EXCEPTION_NUM) {
6312 			PRINTM(MERROR, "dscp_except_num exceeds MAX limit\n");
6313 			LEAVE();
6314 			return;
6315 		}
6316 		memcpy(dscp_except,
6317 		       (t_u8 *)qos_mapping_ie + sizeof(IEEEtypes_Header_t),
6318 		       dscp_except_num * sizeof(DSCP_Exception_t));
6319 		pdscp_range =
6320 			(DSCP_Range_t *)((t_u8 *)qos_mapping_ie +
6321 					 sizeof(IEEEtypes_Header_t) +
6322 					 dscp_except_num *
6323 					 sizeof(DSCP_Exception_t));
6324 		for (i = 0; i < MAX_NUM_TID; i++) {
6325 			PRINTM(MEVENT, "TID %d: dscp_low=%d, dscp_high=%d\n", i,
6326 			       pdscp_range->dscp_low_value,
6327 			       pdscp_range->dscp_high_value);
6328 			if (pdscp_range->dscp_low_value != 0xff &&
6329 			    pdscp_range->dscp_high_value != 0xff &&
6330 			    pdscp_range->dscp_high_value <= 63) {
6331 				for (j = pdscp_range->dscp_low_value;
6332 				     j <= pdscp_range->dscp_high_value; j++)
6333 					priv->dscp_map[j] = i;
6334 			}
6335 			pdscp_range++;
6336 		}
6337 		for (i = 0; i < dscp_except_num; i++) {
6338 			if ((dscp_except[i].dscp_value <= 63) &&
6339 			    (dscp_except[i].user_priority <= 7)) {
6340 				PRINTM(MEVENT,
6341 				       "dscp excpt: value=%d priority=%d\n",
6342 				       dscp_except[i].dscp_value,
6343 				       dscp_except[i].user_priority);
6344 				priv->dscp_map[dscp_except[i].dscp_value] =
6345 					dscp_except[i].user_priority;
6346 			}
6347 		}
6348 	}
6349 	LEAVE();
6350 }
6351 
6352 /**
6353  *  @brief Sends disconnect event
6354  *
6355  *  @param priv A pointer to moal_private struct
6356  *  @return     N/A
6357  */
6358 t_void
6359 woal_send_disconnect_to_system(moal_private *priv)
6360 {
6361 	int custom_len = 0;
6362 	t_u8 event_buf[32];
6363 #ifdef STA_WEXT
6364 	union iwreq_data wrqu;
6365 #endif
6366 #ifdef STA_CFG80211
6367 	unsigned long flags;
6368 #endif
6369 	mlan_ds_misc_gtk_rekey_data zero_gtk;
6370 
6371 	ENTER();
6372 	priv->media_connected = MFALSE;
6373 	woal_stop_queue(priv->netdev);
6374 	if (netif_carrier_ok(priv->netdev))
6375 		netif_carrier_off(priv->netdev);
6376 	woal_flush_tcp_sess_queue(priv);
6377 
6378 	priv->gtk_data_ready = MFALSE;
6379 	memset(&zero_gtk, 0x00, sizeof(zero_gtk));
6380 	if (gtk_rekey_offload == GTK_REKEY_OFFLOAD_ENABLE &&
6381 	    memcmp(&priv->gtk_rekey_data, &zero_gtk,
6382 		   sizeof(priv->gtk_rekey_data)) != 0) {
6383 		PRINTM(MCMND, "clear GTK in woal_send_disconnect_to_system\n");
6384 		woal_set_rekey_data(priv, NULL, MLAN_ACT_CLEAR);
6385 	}
6386 	memset(&priv->gtk_rekey_data, 0, sizeof(mlan_ds_misc_gtk_rekey_data));
6387 
6388 	if (priv->bss_type == MLAN_BSS_TYPE_STA)
6389 		woal_flush_tdls_list(priv);
6390 #ifdef STA_CFG80211
6391 	if (priv->bss_type == MLAN_BSS_TYPE_STA &&
6392 	    IS_STA_CFG80211(cfg80211_wext)) {
6393 		woal_flush_pmksa_list(priv);
6394 		if (priv->okc_roaming_ie) {
6395 			kfree(priv->okc_roaming_ie);
6396 			priv->okc_roaming_ie = NULL;
6397 			priv->okc_ie_len = 0;
6398 		}
6399 	}
6400 #endif
6401 	if (priv->bss_type == MLAN_BSS_TYPE_STA && priv->hist_data)
6402 		woal_hist_data_reset(priv);
6403 
6404 #ifdef STA_WEXT
6405 	if (IS_STA_WEXT(cfg80211_wext)) {
6406 		memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
6407 		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
6408 		wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
6409 	}
6410 #endif
6411 #ifdef STA_CFG80211
6412 	if (IS_STA_CFG80211(cfg80211_wext)) {
6413 		spin_lock_irqsave(&priv->connect_lock, flags);
6414 		if (!priv->cfg_disconnect && !priv->cfg_connect &&
6415 		    priv->wdev &&
6416 		    priv->wdev->iftype != NL80211_IFTYPE_ADHOC
6417 		    && ((priv->bss_type != MLAN_BSS_TYPE_STA) ||
6418 			(priv->bss_type == MLAN_BSS_TYPE_STA &&
6419 			 priv->sme_current.ssid))
6420 			) {
6421 			PRINTM(MMSG,
6422 			       "wlan: Disconnected from " MACSTR
6423 			       ": Reason code %d\n", MAC2STR(priv->cfg_bssid),
6424 			       WLAN_REASON_DEAUTH_LEAVING);
6425 			spin_unlock_irqrestore(&priv->connect_lock, flags);
6426 			/* This function must be called only when disconnect issued by
6427 			   the FW, i.e. disconnected by AP. For IBSS mode this call is
6428 			   not valid */
6429 			cfg80211_disconnected(priv->netdev,
6430 					      WLAN_REASON_DEAUTH_LEAVING, NULL,
6431 					      0,
6432 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
6433 					      false,
6434 #endif
6435 					      GFP_KERNEL);
6436 		} else {
6437 			spin_unlock_irqrestore(&priv->connect_lock, flags);
6438 		}
6439 		if (!woal_is_any_interface_active(priv->phandle))
6440 			woal_set_scan_time(priv, ACTIVE_SCAN_CHAN_TIME,
6441 					   PASSIVE_SCAN_CHAN_TIME,
6442 					   SPECIFIC_SCAN_CHAN_TIME);
6443 		priv->ft_ie_len = 0;
6444 		priv->ft_pre_connect = MFALSE;
6445 		memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map));
6446 	}
6447 #endif /* STA_CFG80211 */
6448 
6449 	memset(event_buf, 0, sizeof(event_buf));
6450 	custom_len = strlen(CUS_EVT_AP_CONNECTED);
6451 	strncpy(event_buf, CUS_EVT_AP_CONNECTED,
6452 		MIN((sizeof(event_buf) - 1), custom_len));
6453 	woal_broadcast_event(priv, event_buf, custom_len + ETH_ALEN);
6454 	LEAVE();
6455 }
6456 #endif /* STA_SUPPORT */
6457 
6458 #define OFFSET_SEQNUM 4
6459 /**
6460  *  @brief  This function stores the FW dumps received from events in a file
6461  *
6462  *  @param phandle     A pointer to moal_handle
6463  *  @param pmevent  A pointer to mlan_event structure
6464  *
6465  *  @return         N/A
6466  */
6467 
6468 t_void
6469 woal_store_firmware_dump(moal_handle *phandle, mlan_event *pmevent)
6470 {
6471 	struct file *pfile_fwdump = NULL;
6472 	loff_t pos = 0;
6473 	t_u16 seqnum;
6474 	t_u8 path_name[64];
6475 
6476 	ENTER();
6477 	if (phandle->fwdump_fname)
6478 		pfile_fwdump =
6479 			filp_open(phandle->fwdump_fname,
6480 				  O_CREAT | O_WRONLY | O_APPEND, 0644);
6481 	else {
6482 		seqnum = woal_le16_to_cpu(*(t_u16 *)
6483 					  (pmevent->event_buf + OFFSET_SEQNUM));
6484 		if (seqnum == 1) {
6485 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
6486 	    /** Create dump directort*/
6487 			woal_create_dump_dir(phandle, path_name,
6488 					     sizeof(path_name));
6489 #else
6490 			memset(path_name, 0, sizeof(path_name));
6491 			strcpy(path_name, "/data");
6492 #endif
6493 			PRINTM(MMSG, "Firmware Dump directory name is %s\n",
6494 			       path_name);
6495 			woal_dump_drv_info(phandle, path_name);
6496 			if (fwdump_fname) {
6497 				memset(fwdump_fname, 0, 64);
6498 			} else {
6499 				gfp_t flag;
6500 				flag = (in_atomic() ||
6501 					irqs_disabled())? GFP_ATOMIC :
6502 					GFP_KERNEL;
6503 				fwdump_fname = kzalloc(64, flag);
6504 			}
6505 			sprintf(fwdump_fname, "%s/file_fwdump", path_name);
6506 			pfile_fwdump =
6507 				filp_open(fwdump_fname,
6508 					  O_CREAT | O_WRONLY | O_APPEND, 0644);
6509 			if (IS_ERR(pfile_fwdump)) {
6510 				memset(fwdump_fname, 0, 64);
6511 				sprintf(fwdump_fname, "%s/%s", "/var",
6512 					"file_fwdump");
6513 				pfile_fwdump =
6514 					filp_open(fwdump_fname,
6515 						  O_CREAT | O_WRONLY | O_APPEND,
6516 						  0644);
6517 			}
6518 		} else
6519 			pfile_fwdump =
6520 				filp_open(fwdump_fname,
6521 					  O_CREAT | O_WRONLY | O_APPEND, 0644);
6522 	}
6523 	if (IS_ERR(pfile_fwdump)) {
6524 		PRINTM(MERROR, "Cannot create firmware dump file\n");
6525 		LEAVE();
6526 		return;
6527 	}
6528 	vfs_write(pfile_fwdump, pmevent->event_buf, pmevent->event_len, &pos);
6529 	filp_close(pfile_fwdump, NULL);
6530 	LEAVE();
6531 	return;
6532 }
6533 
6534 #define DRV_INFO_SIZE 0x40000
6535 #define ROW_SIZE_16      16
6536 #define ROW_SIZE_32      32
6537 /**
6538  *  @brief This function save moal_priv's debug log
6539  *
6540  *  @param phandle   A pointer to moal_handle
6541  *  @param buf       A pointer buffer saving log
6542  *
6543  *  @return          The length of this log
6544  */
6545 static int
6546 woal_dump_priv_drv_info(moal_handle *handle, t_u8 *buf)
6547 {
6548 	char *ptr = (char *)buf;
6549 	int index;
6550 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
6551 	int i = 0;
6552 #endif
6553 	moal_private *priv;
6554 
6555 	ENTER();
6556 	if (!handle || !buf) {
6557 		PRINTM(MMSG, "%s: can't retreive info\n", __func__);
6558 		LEAVE();
6559 		return 0;
6560 	}
6561 	for (index = 0; index < MIN(handle->priv_num, MLAN_MAX_BSS_NUM);
6562 	     index++) {
6563 		priv = handle->priv[index];
6564 		if (priv) {
6565 			ptr += sprintf(ptr, "[Interface : %s]\n",
6566 				       priv->proc_entry_name);
6567 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
6568 			ptr += sprintf(ptr, "wmm_tx_pending[0] = %d\n",
6569 				       atomic_read(&priv->wmm_tx_pending[0]));
6570 			ptr += sprintf(ptr, "wmm_tx_pending[1] = %d\n",
6571 				       atomic_read(&priv->wmm_tx_pending[1]));
6572 			ptr += sprintf(ptr, "wmm_tx_pending[2] = %d\n",
6573 				       atomic_read(&priv->wmm_tx_pending[2]));
6574 			ptr += sprintf(ptr, "wmm_tx_pending[3] = %d\n",
6575 				       atomic_read(&priv->wmm_tx_pending[3]));
6576 #endif
6577 			ptr += sprintf(ptr, "Media state = \"%s\"\n",
6578 				       ((priv->media_connected ==
6579 					 MFALSE) ? "Disconnected" :
6580 					"Connected"));
6581 			ptr += sprintf(ptr, "carrier %s\n",
6582 				       ((netif_carrier_ok(priv->netdev)) ? "on"
6583 					: "off"));
6584 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
6585 			for (i = 0; i < (priv->netdev->num_tx_queues); i++) {
6586 				ptr += sprintf(ptr, "tx queue %d: %s\n", i,
6587 					       ((netif_tx_queue_stopped
6588 						 (netdev_get_tx_queue
6589 						  (priv->netdev,
6590 						   i))) ? "stopped" :
6591 						"started"));
6592 			}
6593 #else
6594 			ptr += sprintf(ptr, "tx queue %s\n",
6595 				       ((netif_queue_stopped(priv->netdev)) ?
6596 					"stopped" : "started"));
6597 #endif
6598 			ptr += sprintf(ptr, "%s: num_tx_timeout = %d\n",
6599 				       priv->netdev->name,
6600 				       priv->num_tx_timeout);
6601 		}
6602 	}
6603 
6604 	LEAVE();
6605 	return ptr - (char *)buf;
6606 }
6607 
6608 #define SDIO_SCRATCH_REG 0xE8
6609 /**
6610  *  @brief This function save sdio reg info
6611  *
6612  *  @param phandle   A pointer to moal_handle
6613  *  @param buf       A pointer buffer saving log
6614  *
6615  *  @return          The length of this log
6616  */
6617 static int
6618 woal_dump_sdio_reg_info(moal_handle *phandle, t_u8 *drv_buf)
6619 {
6620 	char *drv_ptr = (char *)drv_buf;
6621 	int ret = 0;
6622 	t_u8 loop, index = 0, func, data;
6623 	unsigned int reg, reg_start, reg_end;
6624 	unsigned int scratch_reg = SDIO_SCRATCH_REG;
6625 	unsigned int reg_table[] = { 0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62,
6626 		0x64, 0x65, 0x66, 0x68, 0x69, 0x6a
6627 	};
6628 	char buf[256], *ptr;
6629 
6630 	ENTER();
6631 
6632 	if (!phandle || !drv_buf) {
6633 		PRINTM(MMSG, "%s: can't retreive info\n", __func__);
6634 		LEAVE();
6635 		return 0;
6636 	}
6637 	mlan_pm_wakeup_card(phandle->pmlan_adapter);
6638 
6639 	drv_ptr += sprintf(drv_ptr, "--------sdio_reg_debug_info---------\n");
6640 	sdio_claim_host(((struct sdio_mmc_card *)phandle->card)->func);
6641 	for (loop = 0; loop < 5; loop++) {
6642 		memset(buf, 0, sizeof(buf));
6643 		ptr = buf;
6644 		if (loop == 0) {
6645 			/* Read the registers of SDIO function0 */
6646 			func = loop;
6647 			reg_start = 0;
6648 			reg_end = 9;
6649 
6650 		} else if (loop == 1) {
6651 			/* Read the registers of SDIO function1 */
6652 			func = loop;
6653 			reg_start = 0x10;
6654 			reg_end = 0x17;
6655 		} else if (loop == 2) {
6656 			/* Read specific registers of SDIO function1 */
6657 			index = 0;
6658 			func = 1;
6659 			reg_start = reg_table[index++];
6660 			reg_end =
6661 				reg_table[sizeof(reg_table) / sizeof(int) - 1];
6662 		} else {
6663 			/* Read the scratch registers of SDIO function1 */
6664 			if (loop == 4)
6665 				mdelay(100);
6666 			func = 1;
6667 			reg_start = scratch_reg;
6668 			reg_end = scratch_reg + 10;
6669 		}
6670 		if (loop != 2)
6671 			ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", func,
6672 				       reg_start, reg_end);
6673 		else
6674 			ptr += sprintf(ptr, "SDIO Func%d: ", func);
6675 		for (reg = reg_start; reg <= reg_end;) {
6676 			if (func == 0)
6677 				data = sdio_f0_readb(((struct sdio_mmc_card *)
6678 						      phandle->card)->func, reg,
6679 						     &ret);
6680 			else
6681 				data = sdio_readb(((struct sdio_mmc_card *)
6682 						   phandle->card)->func, reg,
6683 						  &ret);
6684 			if (loop == 2)
6685 				ptr += sprintf(ptr, "(%#x) ", reg);
6686 			if (!ret)
6687 				ptr += sprintf(ptr, "%02x ", data);
6688 			else {
6689 				ptr += sprintf(ptr, "ERR");
6690 				break;
6691 			}
6692 			if (loop == 2 && reg < reg_end)
6693 				reg = reg_table[index++];
6694 			else
6695 				reg++;
6696 		}
6697 		drv_ptr += sprintf(drv_ptr, "%s\n", buf);
6698 	}
6699 	sdio_release_host(((struct sdio_mmc_card *)phandle->card)->func);
6700 
6701 	drv_ptr +=
6702 		sprintf(drv_ptr, "--------sdio_reg_debug_info End---------\n");
6703 
6704 	LEAVE();
6705 	return drv_ptr - (char *)drv_buf;
6706 }
6707 
6708 /**
6709  *  @brief This function save moal_handle's info
6710  *
6711  *  @param phandle   A pointer to moal_handle
6712  *  @param buf       A pointer buffer saving log
6713  *
6714  *  @return          The length of this log
6715  */
6716 static int
6717 woal_dump_moal_drv_info(moal_handle *phandle, t_u8 *buf)
6718 {
6719 	char *ptr;
6720 	char str_buf[MLAN_MAX_VER_STR_LEN];
6721 
6722 	ENTER();
6723 	if (!phandle || !buf) {
6724 		PRINTM(MMSG, "%s: can't retreive info\n", __func__);
6725 		LEAVE();
6726 		return 0;
6727 	}
6728 	ptr = (char *)buf;
6729 	ptr += sprintf(ptr, "------------moal_debug_info-------------\n");
6730 	woal_get_version(phandle, str_buf, sizeof(str_buf) - 1);
6731 	ptr += sprintf(ptr, "Driver version = %s\n", str_buf);
6732 	ptr += sprintf(ptr, "main_state = %d\n", phandle->main_state);
6733 	ptr += sprintf(ptr, "ioctl_pending = %d\n",
6734 		       atomic_read(&phandle->ioctl_pending));
6735 	ptr += sprintf(ptr, "tx_pending = %d\n",
6736 		       atomic_read(&phandle->tx_pending));
6737 	ptr += sprintf(ptr, "rx_pending = %d\n",
6738 		       atomic_read(&phandle->rx_pending));
6739 	ptr += sprintf(ptr, "lock_count = %d\n",
6740 		       atomic_read(&phandle->lock_count));
6741 	ptr += sprintf(ptr, "malloc_count = %d\n",
6742 		       atomic_read(&phandle->malloc_count));
6743 	ptr += sprintf(ptr, "mbufalloc_count = %d\n",
6744 		       atomic_read(&phandle->mbufalloc_count));
6745 #if defined(SDIO_SUSPEND_RESUME)
6746 	ptr += sprintf(ptr, "hs_skip_count = %u\n", phandle->hs_skip_count);
6747 	ptr += sprintf(ptr, "hs_force_count = %u\n", phandle->hs_force_count);
6748 #endif
6749 
6750 	ptr += woal_dump_priv_drv_info(phandle, ptr);
6751 	ptr += sprintf(ptr, "------------moal_debug_info End-------------\n");
6752 
6753 	ptr += woal_dump_sdio_reg_info(phandle, ptr);
6754 
6755 	LEAVE();
6756 	return ptr - (char *)buf;
6757 }
6758 
6759 /**
6760  *  @brief This function save mlan's info
6761  *
6762  *  @param phandle   A pointer to moal_handle
6763  *  @param buf       A pointer buffer saving log
6764  *
6765  *  @return          The length of this log
6766  */
6767 static int
6768 woal_dump_mlan_drv_info(moal_private *priv, t_u8 *buf)
6769 {
6770 	char *ptr = (char *)buf;
6771 	int i;
6772 #ifdef SDIO_MULTI_PORT_TX_AGGR
6773 	int j;
6774 	t_u8 mp_aggr_pkt_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
6775 #endif
6776 	char str[11 * DBG_CMD_NUM + 1] = { 0 };
6777 	char *s;
6778 
6779 	ENTER();
6780 	if (!priv || woal_get_debug_info(priv, MOAL_IOCTL_WAIT, &info)) {
6781 		PRINTM(MERROR,
6782 		       "Could not retrieve debug information from MLAN\n");
6783 		LEAVE();
6784 		return 0;
6785 	}
6786 	ptr += sprintf(ptr, "------------mlan_debug_info-------------\n");
6787 	ptr += sprintf(ptr, "mlan_processing =%d\n", info.mlan_processing);
6788 	ptr += sprintf(ptr, "main_lock_flag =%d\n", info.main_lock_flag);
6789 	ptr += sprintf(ptr, "main_process_cnt =%d\n", info.main_process_cnt);
6790 	ptr += sprintf(ptr, "delay_task_flag =%d\n", info.delay_task_flag);
6791 	ptr += sprintf(ptr, "mlan_rx_processing =%d\n",
6792 		       info.mlan_rx_processing);
6793 	ptr += sprintf(ptr, "rx_pkts_queued =%d\n", info.rx_pkts_queued);
6794 	ptr += sprintf(ptr, "tx_pkts_queued =%d\n", info.tx_pkts_queued);
6795 
6796 	ptr += sprintf(ptr, "num_cmd_timeout = %d\n", info.num_cmd_timeout);
6797 	ptr += sprintf(ptr, "dbg.num_cmd_timeout = %d\n",
6798 		       info.dbg_num_cmd_timeout);
6799 	ptr += sprintf(ptr, "Timeout cmd id = 0x%x, act = 0x%x\n",
6800 		       info.timeout_cmd_id, info.timeout_cmd_act);
6801 	ptr += sprintf(ptr, "last_cmd_index = %d\n", info.last_cmd_index);
6802 	for (s = str, i = 0; i < DBG_CMD_NUM; i++)
6803 		s += sprintf(s, "0x%x ", info.last_cmd_id[i]);
6804 	ptr += sprintf(ptr, "last_cmd_id = %s\n", str);
6805 
6806 	for (s = str, i = 0; i < DBG_CMD_NUM; i++)
6807 		s += sprintf(s, "0x%x ", info.last_cmd_act[i]);
6808 
6809 	ptr += sprintf(ptr, "last_cmd_act = %s\n", str);
6810 	ptr += sprintf(ptr, "last_cmd_resp_index = %d\n",
6811 		       info.last_cmd_resp_index);
6812 	for (s = str, i = 0; i < DBG_CMD_NUM; i++)
6813 		s += sprintf(s, "0x%x ", info.last_cmd_resp_id[i]);
6814 
6815 	ptr += sprintf(ptr, "last_cmd_resp_id = %s\n", str);
6816 	ptr += sprintf(ptr, "last_event_index = %d\n", info.last_event_index);
6817 	for (s = str, i = 0; i < DBG_CMD_NUM; i++)
6818 		s += sprintf(s, "0x%x ", info.last_event[i]);
6819 
6820 	ptr += sprintf(ptr, "last_event = %s\n", str);
6821 	ptr += sprintf(ptr, "num_data_h2c_failure = %d\n",
6822 		       info.num_tx_host_to_card_failure);
6823 	ptr += sprintf(ptr, "num_cmd_h2c_failure = %d\n",
6824 		       info.num_cmd_host_to_card_failure);
6825 	ptr += sprintf(ptr, "num_alloc_buffer_failure = %d\n",
6826 		       info.num_alloc_buffer_failure);
6827 	ptr += sprintf(ptr, "num_pkt_dropped = %d\n", info.num_pkt_dropped);
6828 	ptr += sprintf(ptr, "num_data_c2h_failure = %d\n",
6829 		       info.num_rx_card_to_host_failure);
6830 	ptr += sprintf(ptr, "num_cmdevt_c2h_failure = %d\n",
6831 		       info.num_cmdevt_card_to_host_failure);
6832 	ptr += sprintf(ptr, "num_int_read_failure = %d\n",
6833 		       info.num_int_read_failure);
6834 	ptr += sprintf(ptr, "last_int_status = %d\n", info.last_int_status);
6835 	ptr += sprintf(ptr, "num_event_deauth = %d\n", info.num_event_deauth);
6836 	ptr += sprintf(ptr, "num_event_disassoc = %d\n",
6837 		       info.num_event_disassoc);
6838 	ptr += sprintf(ptr, "num_event_link_lost = %d\n",
6839 		       info.num_event_link_lost);
6840 	ptr += sprintf(ptr, "num_cmd_deauth = %d\n", info.num_cmd_deauth);
6841 	ptr += sprintf(ptr, "num_cmd_assoc_success = %d\n",
6842 		       info.num_cmd_assoc_success);
6843 	ptr += sprintf(ptr, "num_cmd_assoc_failure = %d\n",
6844 		       info.num_cmd_assoc_failure);
6845 	ptr += sprintf(ptr, "cmd_resp_received = %d\n", info.cmd_resp_received);
6846 	ptr += sprintf(ptr, "event_received = %d\n", info.event_received);
6847 	ptr += sprintf(ptr, "max_tx_buf_size = %d\n", info.max_tx_buf_size);
6848 	ptr += sprintf(ptr, "tx_buf_size = %d\n", info.tx_buf_size);
6849 	ptr += sprintf(ptr, "curr_tx_buf_size = %d\n", info.curr_tx_buf_size);
6850 
6851 	ptr += sprintf(ptr, "data_sent=%d cmd_sent=%d\n", info.data_sent,
6852 		       info.cmd_sent);
6853 	ptr += sprintf(ptr, "ps_mode=%d ps_state=%d\n", info.ps_mode,
6854 		       info.ps_state);
6855 	ptr += sprintf(ptr, "wakeup_dev_req=%d wakeup_tries=%d\n",
6856 		       info.pm_wakeup_card_req, info.pm_wakeup_fw_try);
6857 	ptr += sprintf(ptr, "hs_configured=%d hs_activated=%d\n",
6858 		       info.is_hs_configured, info.hs_activated);
6859 	ptr += sprintf(ptr, "pps_uapsd_mode=%d sleep_pd=%d\n",
6860 		       info.pps_uapsd_mode, info.sleep_pd);
6861 	ptr += sprintf(ptr, "tx_lock_flag = %d\n", info.tx_lock_flag);
6862 	ptr += sprintf(ptr, "port_open = %d\n", info.port_open);
6863 	ptr += sprintf(ptr, "scan_processing = %d\n", info.scan_processing);
6864 
6865 	ptr += sprintf(ptr, "mp_rd_bitmap=0x%x curr_rd_port=0x%x\n",
6866 		       (unsigned int)info.mp_rd_bitmap, info.curr_rd_port);
6867 	ptr += sprintf(ptr, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n",
6868 		       (unsigned int)info.mp_wr_bitmap, info.curr_wr_port);
6869 	ptr += sprintf(ptr, "mp_invalid_update=%d\n", info.mp_invalid_update);
6870 #ifdef SDIO_MULTI_PORT_TX_AGGR
6871 	ptr += sprintf(ptr, "last_recv_wr_bitmap=0x%x last_mp_index = %d\n",
6872 		       info.last_recv_wr_bitmap, info.last_mp_index);
6873 	for (i = 0; i < SDIO_MP_DBG_NUM; i++) {
6874 		for (s = str, j = 0; j < mp_aggr_pkt_limit; j++)
6875 			s += sprintf(s, "0x%02x ",
6876 				     info.last_mp_wr_info[i *
6877 							  mp_aggr_pkt_limit +
6878 							  j]);
6879 
6880 		ptr += sprintf(ptr,
6881 			       "mp_wr_bitmap: 0x%x mp_wr_ports=0x%x len=%d curr_wr_port=0x%x\n%s\n",
6882 			       info.last_mp_wr_bitmap[i],
6883 			       info.last_mp_wr_ports[i], info.last_mp_wr_len[i],
6884 			       info.last_curr_wr_port[i], str);
6885 	}
6886 #endif
6887 	ptr += sprintf(ptr, "------------mlan_debug_info End-------------\n");
6888 
6889 	LEAVE();
6890 	return ptr - (char *)buf;
6891 }
6892 
6893 /**
6894  *  @brief This function dump hex to file
6895  *
6896  *  @param phandle   A pointer to moal_handle
6897  *  @param buf       A pointer to buffer to dump
6898  *  @param len       lengh of buf
6899  *  @param ascii     Whether add ascii at the end
6900  *  @param save_buf  Buffer which is saved to
6901  *
6902  *  @return          The length of this log
6903  */
6904 static int
6905 woal_save_hex_dump(int rowsize, const void *buf, size_t len,
6906 		   bool ascii, t_u8 *save_buf)
6907 {
6908 	const u8 *ptr = buf;
6909 	int i, linelen, remaining = len;
6910 	unsigned char linebuf[ROW_SIZE_32 * 3 + 2 + ROW_SIZE_32 + 1];
6911 	char *pos = (char *)save_buf;
6912 
6913 	if (rowsize != ROW_SIZE_16 && rowsize != ROW_SIZE_32)
6914 		rowsize = ROW_SIZE_16;
6915 
6916 	for (i = 0; i < len; i += rowsize) {
6917 		linelen = min(remaining, rowsize);
6918 		remaining -= rowsize;
6919 
6920 		hex_dump_to_buffer(ptr + i, linelen, rowsize, 1, linebuf,
6921 				   sizeof(linebuf), ascii);
6922 
6923 		pos += sprintf(pos, "%p: %s\n", ptr + i, linebuf);
6924 	}
6925 
6926 	return pos - (char *)save_buf;
6927 }
6928 
6929 /**
6930  *  @brief This function dump moal hex to file
6931  *
6932  *  @param phandle   A pointer to moal_handle
6933  *  @param buf       A pointer to buffer
6934  *
6935  *  @return          The length of this log
6936  */
6937 static int
6938 woal_dump_moal_hex(moal_handle *phandle, t_u8 *buf)
6939 {
6940 	char *ptr = (char *)buf;
6941 	int i;
6942 	ENTER();
6943 
6944 	if (!phandle || !buf) {
6945 		PRINTM(MMSG, "%s: can't retreive info\n", __func__);
6946 		LEAVE();
6947 		return 0;
6948 	}
6949 
6950 	ptr += sprintf(ptr, "<--moal_handle-->\n");
6951 	ptr += sprintf(ptr, "moal_handle=%p, size=%ld(0x%lx)\n", phandle,
6952 		       (long int)sizeof(*phandle),
6953 		       (long unsigned int)sizeof(*phandle));
6954 	ptr += woal_save_hex_dump(ROW_SIZE_16, phandle, sizeof(*phandle), MTRUE,
6955 				  ptr);
6956 	ptr += sprintf(ptr, "<--moal_handle End-->\n");
6957 
6958 	for (i = 0; i < phandle->priv_num; i++) {
6959 		ptr += sprintf(ptr, "<--moal_private(%d)-->\n", i);
6960 		ptr += sprintf(ptr, "moal_private=%p, size=%ld(0x%lx)\n",
6961 			       phandle->priv[i],
6962 			       (long int)sizeof(*(phandle->priv[i])),
6963 			       (long unsigned int)sizeof(*(phandle->priv[i])));
6964 		ptr += woal_save_hex_dump(ROW_SIZE_16, phandle->priv[i],
6965 					  sizeof(*(phandle->priv[i])), MTRUE,
6966 					  ptr);
6967 		ptr += sprintf(ptr, "<--moal_private(%d) End-->\n", i);
6968 	}
6969 	LEAVE();
6970 	return ptr - (char *)buf;
6971 }
6972 
6973 /**
6974  *  @brief This function dump mlan hex to file
6975  *
6976  *  @param priv   A pointer to moal_private structure
6977  *  @param buf       A pointer to buffer
6978  *  @param pfile  A pointer to file structure
6979  *
6980  *  @return          The length of this log
6981  */
6982 static int
6983 woal_dump_mlan_hex(moal_private *priv, t_u8 *buf, struct file *pfile)
6984 {
6985 	char *ptr = (char *)buf;
6986 	int i;
6987 	int len = 0;
6988 
6989 	ENTER();
6990 
6991 	if (!buf || !priv || !pfile ||
6992 	    woal_get_debug_info(priv, MOAL_IOCTL_WAIT, &info)) {
6993 		PRINTM(MMSG, "%s: can't retreive info\n", __func__);
6994 		LEAVE();
6995 		return 0;
6996 	}
6997 
6998 	ptr += sprintf(ptr, "<--mlan_adapter-->\n");
6999 	ptr += sprintf(ptr, "mlan_adapter=%p, size=%d(0x%x)\n",
7000 		       info.mlan_adapter, info.mlan_adapter_size,
7001 		       info.mlan_adapter_size);
7002 	ptr += woal_save_hex_dump(ROW_SIZE_16, info.mlan_adapter,
7003 				  info.mlan_adapter_size, MTRUE, ptr);
7004 	ptr += sprintf(ptr, "<--mlan_adapter End-->\n");
7005 	vfs_write(pfile, buf, ptr - (char *)buf, &pfile->f_pos);
7006 	len += ptr - (char *)buf;
7007 #ifdef SDIO_MULTI_PORT_TX_AGGR
7008 	if (info.mpa_buf && info.mpa_buf_size) {
7009 		ptr = (char *)buf;
7010 		ptr += sprintf(ptr, "<--mlan_mpa_buf-->\n");
7011 		ptr += sprintf(ptr, "mlan_mpa_buf=%p, size=%d(0x%x)\n",
7012 			       info.mpa_buf, info.mpa_buf_size,
7013 			       info.mpa_buf_size);
7014 		ptr += woal_save_hex_dump(ROW_SIZE_16, info.mpa_buf,
7015 					  info.mpa_buf_size, MTRUE, ptr);
7016 		ptr += sprintf(ptr, "<--mlan_mpa_buf End-->\n");
7017 		vfs_write(pfile, buf, ptr - (char *)buf, &pfile->f_pos);
7018 		len += ptr - (char *)buf;
7019 	}
7020 #endif
7021 	for (i = 0; i < info.mlan_priv_num; i++) {
7022 		ptr = (char *)buf;
7023 		ptr += sprintf(ptr, "<--mlan_private(%d)-->\n", i);
7024 		ptr += sprintf(ptr, "mlan_private=%p, size=%d(0x%x)\n",
7025 			       info.mlan_priv[i], info.mlan_priv_size[i],
7026 			       info.mlan_priv_size[i]);
7027 		ptr += woal_save_hex_dump(ROW_SIZE_16, info.mlan_priv[i],
7028 					  info.mlan_priv_size[i], MTRUE, ptr);
7029 		ptr += sprintf(ptr, "<--mlan_private(%d) End-->\n", i);
7030 		vfs_write(pfile, buf, ptr - (char *)buf, &pfile->f_pos);
7031 		len += ptr - (char *)buf;
7032 	}
7033 
7034 	LEAVE();
7035 	return len;
7036 }
7037 
7038 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
7039 /**
7040  *  @brief This function create dump directory
7041  *
7042  *  @param phandle   A pointer to moal_handle
7043  *  @param dir_buf   A pointer to dir_buf buffer
7044  *  @param buf_size  Size of dir_buf buffer
7045  *
7046  *  @return         N/A
7047  */
7048 void
7049 woal_create_dump_dir(moal_handle *phandle, char *dir_buf, int buf_size)
7050 {
7051 	struct dentry *dentry;
7052 	struct path path;
7053 	t_u32 sec, usec;
7054 	int ret;
7055 
7056 	ENTER();
7057 
7058 	if (!phandle || !dir_buf) {
7059 		PRINTM(MERROR, "Can't create directory\n");
7060 		ret = MLAN_STATUS_FAILURE;
7061 		goto done;
7062 	}
7063 
7064 	moal_get_system_time(phandle, &sec, &usec);
7065 	memset(dir_buf, 0, buf_size);
7066 	sprintf(dir_buf, "%s%u", "/data/dump_", sec);
7067 
7068 	dentry = kern_path_create(AT_FDCWD, dir_buf, &path, 1);
7069 	if (IS_ERR(dentry)) {
7070 		PRINTM(MMSG,
7071 		       "Create directory %s error, try create dir in /var",
7072 		       dir_buf);
7073 		memset(dir_buf, 0, buf_size);
7074 		sprintf(dir_buf, "%s%u", "/var/dump_", sec);
7075 		dentry = kern_path_create(AT_FDCWD, dir_buf, &path, 1);
7076 	}
7077 	if (IS_ERR(dentry)) {
7078 		PRINTM(MMSG, "Create directory %s error, use default folder",
7079 		       dir_buf);
7080 		goto default_dir;
7081 	}
7082 	ret = vfs_mkdir(path.dentry->d_inode, dentry, 0777);
7083 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
7084 	mutex_unlock(&path.dentry->d_inode->i_mutex);
7085 #else
7086 	inode_unlock(path.dentry->d_inode);
7087 #endif
7088 
7089 	if (ret < 0) {
7090 		PRINTM(MMSG, "Create directory failure, use default folder\n");
7091 		goto default_dir;
7092 	} else {
7093 		PRINTM(MMSG, "Create directory %s successfully\n", dir_buf);
7094 		goto done;
7095 	}
7096 
7097 default_dir:
7098 	memset(dir_buf, 0, buf_size);
7099 	sprintf(dir_buf, "%s", "/data");
7100 done:
7101 	LEAVE();
7102 }
7103 #endif
7104 
7105 /**
7106  *  @brief This function save dump buf to file
7107  *
7108  *  @param dir_name  A pointer to directory name
7109  *  @param file_name A pointer to file name
7110  *  @param buf       A pointer to dump data
7111  *  @param buf_len   The length of dump buf
7112  *
7113  *  @return         SUCCESS OR FAILURE
7114  */
7115 mlan_status
7116 woal_save_dump_info_to_file(char *dir_name, char *file_name, t_u8 *buf,
7117 			    t_u32 buf_len)
7118 {
7119 	mlan_status ret = MLAN_STATUS_SUCCESS;
7120 	struct file *pfile = NULL;
7121 	t_u8 name[64];
7122 	mm_segment_t fs;
7123 	loff_t pos;
7124 
7125 	ENTER();
7126 
7127 	if (!dir_name || !file_name || !buf) {
7128 		PRINTM(MERROR, "Can't save dump info to file\n");
7129 		ret = MLAN_STATUS_FAILURE;
7130 		goto done;
7131 	}
7132 
7133 	memset(name, 0, sizeof(name));
7134 	sprintf(name, "%s/%s", dir_name, file_name);
7135 	pfile = filp_open(name, O_CREAT | O_RDWR, 0644);
7136 	if (IS_ERR(pfile)) {
7137 		PRINTM(MMSG,
7138 		       "Create file %s error, try to save dump file in /var\n",
7139 		       name);
7140 		memset(name, 0, sizeof(name));
7141 		sprintf(name, "%s/%s", "/var", file_name);
7142 		pfile = filp_open(name, O_CREAT | O_RDWR, 0644);
7143 	}
7144 	if (IS_ERR(pfile)) {
7145 		PRINTM(MERROR, "Create Dump file for %s error\n", name);
7146 		ret = MLAN_STATUS_FAILURE;
7147 		goto done;
7148 	}
7149 
7150 	PRINTM(MMSG, "Dump data %s saved in %s\n", file_name, name);
7151 
7152 	fs = get_fs();
7153 	set_fs(KERNEL_DS);
7154 	pos = 0;
7155 	vfs_write(pfile, buf, buf_len, &pos);
7156 	filp_close(pfile, NULL);
7157 	set_fs(fs);
7158 
7159 	PRINTM(MMSG, "Dump data %s saved in %s successfully\n", file_name,
7160 	       name);
7161 
7162 done:
7163 	LEAVE();
7164 	return ret;
7165 }
7166 
7167 /**
7168  *  @brief This function dump drv info to file
7169  *
7170  *  @param phandle   A pointer to moal_handle
7171  *  @param dir_name   A pointer to directory name
7172  *
7173  *  @return         N/A
7174  */
7175 void
7176 woal_dump_drv_info(moal_handle *phandle, t_u8 *dir_name)
7177 {
7178 	int ret = 0;
7179 	struct file *pfile = NULL;
7180 	mm_segment_t fs;
7181 	t_u8 *drv_buf;
7182 	t_u8 file_name[64];
7183 	t_u32 len = 0;
7184 	t_u32 total_len = 0;
7185 
7186 	ENTER();
7187 
7188 	PRINTM(MMSG, "=== START DRIVER INFO DUMP===");
7189 	ret = moal_vmalloc(phandle, DRV_INFO_SIZE + 1, &drv_buf);
7190 	if ((ret != MLAN_STATUS_SUCCESS) || !drv_buf) {
7191 		PRINTM(MERROR, "Error: vmalloc drv buffer failed!\n");
7192 		goto done;
7193 	}
7194 	memset(file_name, 0, sizeof(file_name));
7195 	sprintf(file_name, "%s/%s", dir_name, "file_drv_info");
7196 	pfile = filp_open(file_name, O_CREAT | O_RDWR, 0644);
7197 	if (IS_ERR(pfile)) {
7198 		PRINTM(MMSG,
7199 		       "Create file %s error, try create /var/file_drv_info",
7200 		       file_name);
7201 		pfile = filp_open("/var/file_drv_info", O_CREAT | O_RDWR, 0644);
7202 	} else {
7203 		PRINTM(MMSG, "DRV dump data in %s\n", file_name);
7204 	}
7205 	if (IS_ERR(pfile)) {
7206 		PRINTM(MMSG, "Create file_drv_info file failed\n");
7207 		goto done;
7208 	}
7209 	fs = get_fs();
7210 	set_fs(KERNEL_DS);
7211 
7212 	len = woal_dump_moal_drv_info(phandle, drv_buf);
7213 	total_len += len;
7214 	vfs_write(pfile, drv_buf, len, &pfile->f_pos);
7215 
7216 	len = woal_dump_mlan_drv_info(woal_get_priv(phandle, MLAN_BSS_ROLE_ANY),
7217 				      drv_buf);
7218 	total_len += len;
7219 	vfs_write(pfile, drv_buf, len, &pfile->f_pos);
7220 
7221 	len = woal_dump_moal_hex(phandle, drv_buf);
7222 	total_len += len;
7223 	vfs_write(pfile, drv_buf, len, &pfile->f_pos);
7224 
7225 	len = woal_dump_mlan_hex(woal_get_priv(phandle, MLAN_BSS_ROLE_ANY),
7226 				 drv_buf, pfile);
7227 	total_len += len;
7228 
7229 	PRINTM(MMSG, "Drv info total bytes = %ld (0x%lx)\n",
7230 	       (long int)total_len, (long unsigned int)total_len);
7231 
7232 	filp_close(pfile, NULL);
7233 	set_fs(fs);
7234 
7235 	PRINTM(MMSG, "=== DRIVER INFO DUMP END===");
7236 done:
7237 	if (drv_buf)
7238 		moal_vfree(phandle, drv_buf);
7239 	LEAVE();
7240 }
7241 
7242 #define DEBUG_HOST_READY		0xCC
7243 #define DEBUG_FW_DONE			0xFF
7244 #define DEBUG_MEMDUMP_FINISH            0xFE
7245 #define MAX_POLL_TRIES			100
7246 
7247 #define DEBUG_DUMP_CTRL_REG               0xF9
7248 #define DEBUG_DUMP_START_REG              0xF1
7249 #define DEBUG_DUMP_END_REG                0xF8
7250 
7251 typedef enum {
7252 	DUMP_TYPE_ITCM = 0,
7253 	DUMP_TYPE_DTCM = 1,
7254 	DUMP_TYPE_SQRAM = 2,
7255 	DUMP_TYPE_APU_REGS = 3,
7256 	DUMP_TYPE_CIU_REGS = 4,
7257 	DUMP_TYPE_ICU_REGS = 5,
7258 	DUMP_TYPE_MAC_REGS = 6,
7259 	DUMP_TYPE_EXTEND_7 = 7,
7260 	DUMP_TYPE_EXTEND_8 = 8,
7261 	DUMP_TYPE_EXTEND_9 = 9,
7262 	DUMP_TYPE_EXTEND_10 = 10,
7263 	DUMP_TYPE_EXTEND_11 = 11,
7264 	DUMP_TYPE_EXTEND_12 = 12,
7265 	DUMP_TYPE_EXTEND_13 = 13,
7266 	DUMP_TYPE_EXTEND_LAST = 14
7267 } dumped_mem_type;
7268 
7269 #define MAX_NAME_LEN               8
7270 #define MAX_FULL_NAME_LEN               32
7271 t_u8 *name_prefix = "/data/file_";
7272 
7273 typedef struct {
7274 	t_u8 mem_name[MAX_NAME_LEN];
7275 	t_u8 *mem_Ptr;
7276 	struct file *pfile_mem;
7277 	t_u8 done_flag;
7278 } memory_type_mapping;
7279 
7280 memory_type_mapping mem_type_mapping_tbl = { "DUMP", NULL, NULL, 0xDD };
7281 
7282 typedef enum {
7283 	RDWR_STATUS_SUCCESS = 0,
7284 	RDWR_STATUS_FAILURE = 1,
7285 	RDWR_STATUS_DONE = 2
7286 } rdwr_status;
7287 
7288 /**
7289  *  @brief This function read/write firmware via cmd52
7290  *
7291  *  @param phandle   A pointer to moal_handle
7292  *  @param doneflag  A flag
7293  *
7294  *  @return         MLAN_STATUS_SUCCESS
7295  */
7296 rdwr_status
7297 woal_cmd52_rdwr_firmware(moal_handle *phandle, t_u8 doneflag)
7298 {
7299 	int ret = 0;
7300 	int tries = 0;
7301 	t_u8 ctrl_data = 0;
7302 	t_u8 dbg_dump_ctrl_reg = 0;
7303 	t_u8 debug_host_ready = 0;
7304 
7305 	dbg_dump_ctrl_reg = DEBUG_DUMP_CTRL_REG;
7306 	debug_host_ready = DEBUG_HOST_READY;
7307 	sdio_writeb(((struct sdio_mmc_card *)phandle->card)->func,
7308 		    debug_host_ready, dbg_dump_ctrl_reg, &ret);
7309 	if (ret) {
7310 		PRINTM(MERROR, "SDIO Write ERR\n");
7311 		return RDWR_STATUS_FAILURE;
7312 	}
7313 	for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
7314 		ctrl_data =
7315 			sdio_readb(((struct sdio_mmc_card *)phandle->card)->
7316 				   func, dbg_dump_ctrl_reg, &ret);
7317 		if (ret) {
7318 			PRINTM(MERROR, "SDIO READ ERR\n");
7319 			return RDWR_STATUS_FAILURE;
7320 		}
7321 		if (ctrl_data == DEBUG_FW_DONE)
7322 			break;
7323 		if (doneflag && ctrl_data == doneflag)
7324 			return RDWR_STATUS_DONE;
7325 		if (ctrl_data != debug_host_ready) {
7326 			PRINTM(MMSG,
7327 			       "The ctrl reg was changed, re-try again!\n");
7328 			sdio_writeb(((struct sdio_mmc_card *)phandle->card)->
7329 				    func, debug_host_ready, dbg_dump_ctrl_reg,
7330 				    &ret);
7331 			if (ret) {
7332 				PRINTM(MERROR, "SDIO Write ERR\n");
7333 				return RDWR_STATUS_FAILURE;
7334 			}
7335 		}
7336 		udelay(100);
7337 	}
7338 	if (ctrl_data == debug_host_ready) {
7339 		PRINTM(MERROR, "Fail to pull ctrl_data\n");
7340 		return RDWR_STATUS_FAILURE;
7341 	}
7342 
7343 	return RDWR_STATUS_SUCCESS;
7344 }
7345 
7346 /**
7347  *  @brief This function dump firmware memory to file
7348  *
7349  *  @param phandle   A pointer to moal_handle
7350  *
7351  *  @return         N/A
7352  */
7353 void
7354 woal_dump_firmware_info_v3(moal_handle *phandle)
7355 {
7356 
7357 	int ret = 0;
7358 	int tries = 0;
7359 	unsigned int reg, reg_start, reg_end;
7360 	t_u8 *dbg_ptr = NULL;
7361 	t_u8 *temp_Ptr = NULL;
7362 	t_u32 sec, usec;
7363 	t_u8 start_flag = 0;
7364 	t_u8 doneflag = 0;
7365 	rdwr_status stat;
7366 	t_u32 memory_size = 0;
7367 	t_u8 path_name[64], file_name[32];
7368 	t_u8 *end_ptr = NULL;
7369 	t_u8 dbg_dump_start_reg = 0;
7370 	t_u8 dbg_dump_end_reg = 0;
7371 	t_u8 dbg_dump_ctrl_reg = 0;
7372 	memory_type_mapping *pmem_type_mapping_tbl = &mem_type_mapping_tbl;
7373 
7374 	if (!phandle) {
7375 		PRINTM(MERROR, "Could not dump firmwware info\n");
7376 		return;
7377 	}
7378 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
7379     /** Create dump directort*/
7380 	woal_create_dump_dir(phandle, path_name, sizeof(path_name));
7381 #else
7382 	memset(path_name, 0, sizeof(path_name));
7383 	strcpy(path_name, "/data");
7384 #endif
7385 	PRINTM(MMSG, "Directory name is %s\n", path_name);
7386 
7387 	woal_dump_drv_info(phandle, path_name);
7388 
7389 	dbg_dump_start_reg = DEBUG_DUMP_START_REG;
7390 	dbg_dump_end_reg = DEBUG_DUMP_END_REG;
7391 	dbg_dump_ctrl_reg = DEBUG_DUMP_CTRL_REG;
7392 
7393 	mlan_pm_wakeup_card(phandle->pmlan_adapter);
7394 	phandle->fw_dump = MTRUE;
7395 	sdio_claim_host(((struct sdio_mmc_card *)phandle->card)->func);
7396 	/* start dump fw memory */
7397 	moal_get_system_time(phandle, &sec, &usec);
7398 	PRINTM(MMSG, "==== DEBUG MODE OUTPUT START: %u.%06u ====\n", sec, usec);
7399 	/* read the number of the memories which will dump */
7400 	if (RDWR_STATUS_FAILURE == woal_cmd52_rdwr_firmware(phandle, doneflag))
7401 		goto done;
7402 
7403     /** check the reg which indicate dump starting */
7404 	for (reg = dbg_dump_start_reg; reg <= dbg_dump_end_reg; reg++) {
7405 		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
7406 			start_flag =
7407 				sdio_readb(((struct sdio_mmc_card *)phandle->
7408 					    card)->func, reg, &ret);
7409 			if (ret) {
7410 				PRINTM(MMSG, "SDIO READ ERR\n");
7411 				goto done;
7412 			}
7413 	     /** 0 means dump starting*/
7414 			if (start_flag == 0)
7415 				break;
7416 			if (tries == MAX_POLL_TRIES) {
7417 				PRINTM(MMSG, "FW not ready to dump\n");
7418 				goto done;
7419 			}
7420 			udelay(100);
7421 		}
7422 	}
7423 
7424 	memory_size = 0xF0000;
7425 	PRINTM(MMSG, "%s_SIZE=0x%x\n", pmem_type_mapping_tbl->mem_name,
7426 	       memory_size);
7427 	ret = moal_vmalloc(phandle, memory_size + 1,
7428 			   (t_u8 **)&pmem_type_mapping_tbl->mem_Ptr);
7429 	if ((ret != MLAN_STATUS_SUCCESS) || !pmem_type_mapping_tbl->mem_Ptr) {
7430 		PRINTM(MERROR, "Error: vmalloc %s buffer failed!!!\n",
7431 		       pmem_type_mapping_tbl->mem_name);
7432 		goto done;
7433 	}
7434 	dbg_ptr = pmem_type_mapping_tbl->mem_Ptr;
7435 	end_ptr = dbg_ptr + memory_size;
7436 
7437 	doneflag = pmem_type_mapping_tbl->done_flag;
7438 	moal_get_system_time(phandle, &sec, &usec);
7439 	PRINTM(MMSG, "Start %s output %u.%06u, please wait...\n",
7440 	       pmem_type_mapping_tbl->mem_name, sec, usec);
7441 	do {
7442 		stat = woal_cmd52_rdwr_firmware(phandle, doneflag);
7443 		if (RDWR_STATUS_FAILURE == stat)
7444 			goto done;
7445 
7446 		reg_start = dbg_dump_start_reg;
7447 		reg_end = dbg_dump_end_reg;
7448 		for (reg = reg_start; reg <= reg_end; reg++) {
7449 			*dbg_ptr =
7450 				sdio_readb(((struct sdio_mmc_card *)phandle->
7451 					    card)->func, reg, &ret);
7452 			if (ret) {
7453 				PRINTM(MMSG, "SDIO READ ERR\n");
7454 				goto done;
7455 			}
7456 			dbg_ptr++;
7457 			if (dbg_ptr >= end_ptr) {
7458 				PRINTM(MMSG,
7459 				       "pre-allocced buf is not enough\n");
7460 				ret = moal_vmalloc(phandle,
7461 						   memory_size + 0x4000 + 1,
7462 						   (t_u8 **)&temp_Ptr);
7463 				if ((ret != MLAN_STATUS_SUCCESS) || !temp_Ptr) {
7464 					PRINTM(MERROR,
7465 					       "Error: vmalloc  buffer failed!!!\n");
7466 					goto done;
7467 				}
7468 				moal_memcpy(phandle, temp_Ptr,
7469 					    pmem_type_mapping_tbl->mem_Ptr,
7470 					    memory_size);
7471 				moal_vfree(phandle,
7472 					   pmem_type_mapping_tbl->mem_Ptr);
7473 				pmem_type_mapping_tbl->mem_Ptr = temp_Ptr;
7474 				temp_Ptr = NULL;
7475 				dbg_ptr =
7476 					pmem_type_mapping_tbl->mem_Ptr +
7477 					memory_size;
7478 				memory_size += 0x4000;
7479 				end_ptr =
7480 					pmem_type_mapping_tbl->mem_Ptr +
7481 					memory_size;
7482 			}
7483 
7484 		}
7485 		if (RDWR_STATUS_DONE == stat) {
7486 			PRINTM(MMSG, "%s done:"
7487 #ifdef MLAN_64BIT
7488 			       "size = 0x%lx\n",
7489 #else
7490 			       "size = 0x%x\n",
7491 #endif
7492 			       pmem_type_mapping_tbl->mem_name,
7493 			       dbg_ptr - pmem_type_mapping_tbl->mem_Ptr);
7494 
7495 			memset(file_name, 0, sizeof(file_name));
7496 			sprintf(file_name, "%s%s", "file_sdio_",
7497 				pmem_type_mapping_tbl->mem_name);
7498 			if (MLAN_STATUS_SUCCESS !=
7499 			    woal_save_dump_info_to_file(path_name, file_name,
7500 							pmem_type_mapping_tbl->
7501 							mem_Ptr,
7502 							dbg_ptr -
7503 							pmem_type_mapping_tbl->
7504 							mem_Ptr))
7505 				PRINTM(MMSG, "Can't save dump file %s in %s\n",
7506 				       file_name, path_name);
7507 			moal_vfree(phandle, pmem_type_mapping_tbl->mem_Ptr);
7508 			pmem_type_mapping_tbl->mem_Ptr = NULL;
7509 			break;
7510 		}
7511 	} while (1);
7512 
7513 	moal_get_system_time(phandle, &sec, &usec);
7514 	PRINTM(MMSG, "==== DEBUG MODE OUTPUT END: %u.%06u ====\n", sec, usec);
7515 	/* end dump fw memory */
7516 done:
7517 	phandle->fw_dump = MFALSE;
7518 	sdio_release_host(((struct sdio_mmc_card *)phandle->card)->func);
7519 	if (pmem_type_mapping_tbl->mem_Ptr) {
7520 		moal_vfree(phandle, pmem_type_mapping_tbl->mem_Ptr);
7521 		pmem_type_mapping_tbl->mem_Ptr = NULL;
7522 	}
7523 	PRINTM(MMSG, "==== DEBUG MODE END ====\n");
7524 	return;
7525 }
7526 
7527 /**
7528  *  @brief This function reads and displays SDIO registers for debugging
7529  *
7530  *  @param phandle  A pointer to moal_handle
7531  *
7532  *  @return         N/A
7533  */
7534 void
7535 woal_sdio_reg_dbg(moal_handle *phandle)
7536 {
7537 	int ret = 0;
7538 	t_u8 loop, index = 0, func, data;
7539 	unsigned int reg, reg_start, reg_end;
7540 	unsigned int scratch_reg = SDIO_SCRATCH_REG;
7541 	unsigned int reg_table[] = { 0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62,
7542 		0x64, 0x65, 0x66, 0x68, 0x69, 0x6a
7543 	};
7544 	char buf[256], *ptr;
7545 
7546 	mlan_pm_wakeup_card(phandle->pmlan_adapter);
7547 
7548 	sdio_claim_host(((struct sdio_mmc_card *)phandle->card)->func);
7549 	for (loop = 0; loop < 5; loop++) {
7550 		memset(buf, 0, sizeof(buf));
7551 		ptr = buf;
7552 		if (loop == 0) {
7553 			/* Read the registers of SDIO function0 */
7554 			func = loop;
7555 			reg_start = 0;
7556 			reg_end = 9;
7557 
7558 		} else if (loop == 1) {
7559 			/* Read the registers of SDIO function1 */
7560 			func = loop;
7561 			reg_start = 0x10;
7562 			reg_end = 0x17;
7563 		} else if (loop == 2) {
7564 			/* Read specific registers of SDIO function1 */
7565 			index = 0;
7566 			func = 1;
7567 			reg_start = reg_table[index++];
7568 			reg_end = reg_table[ARRAY_SIZE(reg_table) - 1];
7569 		} else {
7570 			/* Read the scratch registers of SDIO function1 */
7571 			if (loop == 4)
7572 				mdelay(100);
7573 			func = 1;
7574 			reg_start = scratch_reg;
7575 			reg_end = scratch_reg + 10;
7576 		}
7577 		if (loop != 2)
7578 			ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", func,
7579 				       reg_start, reg_end);
7580 		else
7581 			ptr += sprintf(ptr, "SDIO Func%d: ", func);
7582 		for (reg = reg_start; reg <= reg_end;) {
7583 			if (func == 0)
7584 				data = sdio_f0_readb(((struct sdio_mmc_card *)
7585 						      phandle->card)->func, reg,
7586 						     &ret);
7587 			else
7588 				data = sdio_readb(((struct sdio_mmc_card *)
7589 						   phandle->card)->func, reg,
7590 						  &ret);
7591 			if (loop == 2)
7592 				ptr += sprintf(ptr, "(%#x) ", reg);
7593 			if (!ret)
7594 				ptr += sprintf(ptr, "%02x ", data);
7595 			else {
7596 				ptr += sprintf(ptr, "ERR");
7597 				break;
7598 			}
7599 			if (loop == 2 && reg < reg_end)
7600 				reg = reg_table[index++];
7601 			else
7602 				reg++;
7603 		}
7604 		PRINTM(MMSG, "%s\n", buf);
7605 	}
7606 	sdio_release_host(((struct sdio_mmc_card *)phandle->card)->func);
7607 }
7608 
7609 /**
7610  *  @brief This function displays extra MOAL debug information
7611  *
7612  *  @param priv     A pointer to moal_private
7613  *  @param handle   A pointer to moal_handle
7614  *  @param flag     Indicates whether register read can be done directly
7615  *
7616  *  @return         N/A
7617  */
7618 void
7619 woal_moal_debug_info(moal_private *priv, moal_handle *handle, u8 flag)
7620 {
7621 	moal_handle *phandle = NULL;
7622 	char buf[MLAN_MAX_VER_STR_LEN];
7623 	int i = 0;
7624 
7625 	ENTER();
7626 
7627 	if (!priv) {
7628 		if (handle) {
7629 			phandle = handle;
7630 		} else {
7631 			PRINTM(MERROR,
7632 			       "Could not retrieve debug information from MOAL\n");
7633 			LEAVE();
7634 			return;
7635 		}
7636 	} else {
7637 		phandle = priv->phandle;
7638 	}
7639 
7640 	woal_get_version(phandle, buf, sizeof(buf) - 1);
7641 	PRINTM(MERROR, "Driver version = %s\n", buf);
7642 	PRINTM(MERROR, "main_state = %d\n", phandle->main_state);
7643 	PRINTM(MERROR, "ioctl_pending = %d\n",
7644 	       atomic_read(&phandle->ioctl_pending));
7645 	PRINTM(MERROR, "tx_pending = %d\n", atomic_read(&phandle->tx_pending));
7646 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
7647 	if (priv) {
7648 		PRINTM(MERROR, "wmm_tx_pending[0] = %d\n",
7649 		       atomic_read(&priv->wmm_tx_pending[0]));
7650 		PRINTM(MERROR, "wmm_tx_pending[1] = %d\n",
7651 		       atomic_read(&priv->wmm_tx_pending[1]));
7652 		PRINTM(MERROR, "wmm_tx_pending[2] = %d\n",
7653 		       atomic_read(&priv->wmm_tx_pending[2]));
7654 		PRINTM(MERROR, "wmm_tx_pending[3] = %d\n",
7655 		       atomic_read(&priv->wmm_tx_pending[3]));
7656 	}
7657 #endif
7658 	PRINTM(MERROR, "rx_pending = %d\n", atomic_read(&phandle->rx_pending));
7659 	PRINTM(MERROR, "lock_count = %d\n", atomic_read(&phandle->lock_count));
7660 	PRINTM(MERROR, "malloc_count = %d\n",
7661 	       atomic_read(&phandle->malloc_count));
7662 	PRINTM(MERROR, "mbufalloc_count = %d\n",
7663 	       atomic_read(&phandle->mbufalloc_count));
7664 #if defined(SDIO_SUSPEND_RESUME)
7665 	PRINTM(MERROR, "hs_skip_count = %u\n", phandle->hs_skip_count);
7666 	PRINTM(MERROR, "hs_force_count = %u\n", phandle->hs_force_count);
7667 #endif
7668 
7669 	if (priv) {
7670 		PRINTM(MERROR, "Media state = \"%s\"\n",
7671 		       ((priv->media_connected ==
7672 			 MFALSE) ? "Disconnected" : "Connected"));
7673 		PRINTM(MERROR, "carrier %s\n",
7674 		       ((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
7675 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
7676 		for (i = 0; i < (priv->netdev->num_tx_queues); i++) {
7677 			PRINTM(MERROR, "tx queue %d: %s\n", i,
7678 			       ((netif_tx_queue_stopped
7679 				 (netdev_get_tx_queue(priv->netdev, i))) ?
7680 				"stopped" : "started"));
7681 		}
7682 #else
7683 		PRINTM(MERROR, "tx queue %s\n",
7684 		       ((netif_queue_stopped(priv->netdev)) ? "stopped" :
7685 			"started"));
7686 #endif
7687 	}
7688 
7689 	for (i = 0; i < phandle->priv_num; i++) {
7690 		priv = phandle->priv[i];
7691 		if (priv)
7692 			PRINTM(MERROR, "%s: num_tx_timeout = %d\n",
7693 			       priv->netdev->name, priv->num_tx_timeout);
7694 	}
7695 
7696 #if defined(SDIO_SUSPEND_RESUME)
7697 	if (phandle->is_suspended == MTRUE) {
7698 		LEAVE();
7699 		return;
7700 	}
7701 #endif
7702 
7703 	/* Display SDIO registers */
7704 	if (flag &&
7705 	    ((phandle->main_state == MOAL_END_MAIN_PROCESS) ||
7706 	     (phandle->main_state == MOAL_STATE_IDLE))) {
7707 		woal_sdio_reg_dbg(phandle);
7708 	} else {
7709 		phandle->sdio_reg_dbg = MTRUE;
7710 		queue_work(phandle->workqueue, &phandle->main_work);
7711 	}
7712 
7713 	LEAVE();
7714 	return;
7715 }
7716 
7717 /**
7718  *    @brief Download power table to firmware for a specific country
7719  *
7720  *    @param priv         A pointer to moal_private
7721  *    @param country      ISO 3166-1 alpha-2 country code
7722  *
7723  *    @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
7724  */
7725 mlan_status
7726 woal_request_country_power_table(moal_private *priv, char *country)
7727 {
7728 	mlan_status ret = MLAN_STATUS_SUCCESS;
7729 	moal_handle *handle = NULL;
7730 	char country_name[] = "txpower_XX.bin";
7731 	char file_path[256];
7732 	char *last_slash = NULL;
7733 
7734 	ENTER();
7735 
7736 	if (!priv || !priv->phandle) {
7737 		PRINTM(MERROR, "Priv or handle is null\n");
7738 		LEAVE();
7739 		return MLAN_STATUS_FAILURE;
7740 	}
7741 
7742 	if (!country) {
7743 		PRINTM(MERROR, "Country is null\n");
7744 		LEAVE();
7745 		return MLAN_STATUS_FAILURE;
7746 	}
7747 
7748 	handle = priv->phandle;
7749 
7750 	/* Replace XX with ISO 3166-1 alpha-2 country code */
7751 	strncpy(strstr(country_name, "XX"), country, strlen(country));
7752 
7753 	memset(file_path, 0, sizeof(file_path));
7754 	/* file_path should be Null terminated */
7755 	if (fw_name && (strlen(fw_name) < sizeof(file_path))) {
7756 		strncpy(file_path, fw_name,
7757 			MIN((sizeof(file_path) - 1), strlen(fw_name)));
7758 		last_slash = strrchr(file_path, '/');
7759 		if (last_slash)
7760 			memset(last_slash + 1, 0,
7761 			       sizeof(file_path) - 1 - (last_slash -
7762 							file_path));
7763 		else
7764 			memset(file_path, 0, sizeof(file_path));
7765 	} else {
7766 		strncpy(file_path, "mrvl/", sizeof(file_path));
7767 	}
7768 	strncpy(file_path + strlen(file_path), country_name,
7769 		strlen(country_name));
7770 	country_txpwrlimit = file_path;
7771 
7772 	if (MLAN_STATUS_SUCCESS !=
7773 	    woal_set_user_init_data(handle, COUNTRY_POWER_TABLE,
7774 				    MOAL_IOCTL_WAIT)) {
7775 		PRINTM(MFATAL, "Download power table to firmware failed\n");
7776 		ret = MLAN_STATUS_FAILURE;
7777 	}
7778 	LEAVE();
7779 	return ret;
7780 }
7781 
7782 /**
7783  *  @brief napi polling call back function.
7784  *
7785  *  @param napi     A pointer to napi_struct
7786  *  @param budget   the limit of packets driver should poll
7787  *
7788  *  @return       packets received
7789  */
7790 int
7791 woal_netdev_poll_rx(struct napi_struct *napi, int budget)
7792 {
7793 	moal_handle *handle = container_of(napi, moal_handle, napi_rx);
7794 	t_u8 recv = budget;
7795 
7796 	ENTER();
7797 	if (handle->surprise_removed == MTRUE) {
7798 		napi_complete(napi);
7799 		LEAVE();
7800 		return 0;
7801 	}
7802 	mlan_rx_process(handle->pmlan_adapter, &recv);
7803 	if (recv < budget)
7804 		napi_complete(napi);
7805 	LEAVE();
7806 	return recv;
7807 }
7808 
7809 /**
7810  *  @brief This workqueue function handles rx_process
7811  *
7812  *  @param work    A pointer to work_struct
7813  *
7814  *  @return        N/A
7815  */
7816 t_void
7817 woal_rx_work_queue(struct work_struct *work)
7818 {
7819 	moal_handle *handle = container_of(work, moal_handle, rx_work);
7820 	ENTER();
7821 	if (handle->surprise_removed == MTRUE) {
7822 		LEAVE();
7823 		return;
7824 	}
7825 	mlan_rx_process(handle->pmlan_adapter, NULL);
7826 	LEAVE();
7827 }
7828 
7829 /**
7830  *  @brief This workqueue function handles main_process
7831  *
7832  *  @param work    A pointer to work_struct
7833  *
7834  *  @return        N/A
7835  */
7836 t_void
7837 woal_main_work_queue(struct work_struct *work)
7838 {
7839 	moal_handle *handle = container_of(work, moal_handle, main_work);
7840 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
7841 	struct sched_param sp = {.sched_priority = wq_sched_prio };
7842 #endif
7843 
7844 	ENTER();
7845 
7846 	if (handle->surprise_removed == MTRUE) {
7847 		LEAVE();
7848 		return;
7849 	}
7850 
7851 	if (handle->sdio_reg_dbg == MTRUE) {
7852 		handle->sdio_reg_dbg = MFALSE;
7853 		woal_sdio_reg_dbg(handle);
7854 #if defined(DEBUG_LEVEL1)
7855 		if (drvdbg & MFW_D) {
7856 			drvdbg &= ~MFW_D;
7857 			woal_dump_firmware_info_v3(handle);
7858 		}
7859 #endif
7860 		LEAVE();
7861 		return;
7862 	}
7863 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
7864 	/* Change the priority and scheduling policy of main work queue */
7865 	if ((wq_sched_prio != current->rt_priority) ||
7866 	    (wq_sched_policy != current->policy)) {
7867 		PRINTM(MMSG,
7868 		       "Set work queue priority %d and scheduling policy %d\n",
7869 		       wq_sched_prio, wq_sched_policy);
7870 		sched_setscheduler(current, wq_sched_policy, &sp);
7871 	}
7872 #endif
7873 
7874 	handle->main_state = MOAL_ENTER_WORK_QUEUE;
7875 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
7876 	sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
7877 #endif
7878 	handle->main_state = MOAL_START_MAIN_PROCESS;
7879 	/* Call MLAN main process */
7880 	mlan_main_process(handle->pmlan_adapter);
7881 	handle->main_state = MOAL_END_MAIN_PROCESS;
7882 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
7883 	sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
7884 #endif
7885 
7886 	LEAVE();
7887 }
7888 
7889 /**
7890  * @brief Handles interrupt
7891  *
7892  */
7893 /**
7894  * @param handle  A pointer to moal_handle struct
7895  *
7896  * @return        MLAN_STATUS_FAILURE-- when the interrupt is not for us.
7897  */
7898 mlan_status
7899 woal_interrupt(moal_handle *handle)
7900 {
7901 	mlan_status ret = MLAN_STATUS_SUCCESS;
7902 	ENTER();
7903 	handle->main_state = MOAL_RECV_INT;
7904 	PRINTM(MINTR, "*\n");
7905 	if (handle->surprise_removed == MTRUE) {
7906 		LEAVE();
7907 		return MLAN_STATUS_FAILURE;
7908 	}
7909 	/* call mlan_interrupt to read int status */
7910 	mlan_interrupt(handle->pmlan_adapter);
7911 #ifdef SDIO_SUSPEND_RESUME
7912 	if (handle->is_suspended) {
7913 		PRINTM(MINTR, "Receive interrupt in hs_suspended\n");
7914 		LEAVE();
7915 		return ret;
7916 	}
7917 #endif
7918 	handle->main_state = MOAL_START_MAIN_PROCESS;
7919 	/* Call MLAN main process */
7920 	mlan_main_process(handle->pmlan_adapter);
7921 	handle->main_state = MOAL_END_MAIN_PROCESS;
7922 	LEAVE();
7923 	return ret;
7924 }
7925 
7926 /**
7927  * @brief This function adds the card. it will probe the
7928  *      card, allocate the mlan_private and initialize the device.
7929  *
7930  *  @param card    A pointer to card
7931  *
7932  *  @return        A pointer to moal_handle structure
7933  */
7934 moal_handle *
7935 woal_add_card(void *card)
7936 {
7937 	moal_handle *handle = NULL;
7938 	mlan_status status = MLAN_STATUS_SUCCESS;
7939 	int netlink_num = NETLINK_MARVELL;
7940 	int index = 0;
7941 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
7942 	struct netlink_kernel_cfg cfg = {
7943 		.groups = NL_MULTICAST_GROUP,
7944 	};
7945 #endif
7946 
7947 	ENTER();
7948 
7949 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
7950 		goto exit_sem_err;
7951 
7952 	/* Allocate buffer for moal_handle */
7953 	handle = kzalloc(sizeof(moal_handle), GFP_KERNEL);
7954 	if (!handle) {
7955 		PRINTM(MERROR, "Allocate buffer for moal_handle failed!\n");
7956 		goto err_handle;
7957 	}
7958 
7959 	/* Init moal_handle */
7960 	handle->card = card;
7961 	/* Save the handle */
7962 	for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
7963 		if (m_handle[index] == NULL)
7964 			break;
7965 	}
7966 	if (index < MAX_MLAN_ADAPTER) {
7967 		m_handle[index] = handle;
7968 		handle->handle_idx = index;
7969 	} else {
7970 		PRINTM(MERROR, "Exceeded maximum cards supported!\n");
7971 		goto err_kmalloc;
7972 	}
7973 
7974 	if (mac_addr
7975 #ifdef MFG_CMD_SUPPORT
7976 	    && mfg_mode != MLAN_INIT_PARA_ENABLED
7977 #endif
7978 		) {
7979 		t_u8 temp[20];
7980 		t_u8 len = strlen(mac_addr) + 1;
7981 		if (len < sizeof(temp)) {
7982 			memcpy(temp, mac_addr, len);
7983 			handle->set_mac_addr = 1;
7984 			/* note: the following function overwrites the temp buffer */
7985 			woal_mac2u8(handle->mac_addr, temp);
7986 		}
7987 	}
7988 
7989 	handle->histogram_table_num = 1;
7990 
7991 	((struct sdio_mmc_card *)card)->handle = handle;
7992 #ifdef SPI_SUPPORT
7993 	((struct woal_spi_card *)card)->handle = handle;
7994 #endif
7995 
7996 #ifdef STA_SUPPORT
7997 	handle->scan_pending_on_block = MFALSE;
7998 	MOAL_INIT_SEMAPHORE(&handle->async_sem);
7999 #endif
8000 
8001 	/* Init SW */
8002 	if (MLAN_STATUS_SUCCESS != woal_init_sw(handle)) {
8003 		PRINTM(MFATAL, "Software Init Failed\n");
8004 		goto err_kmalloc;
8005 	}
8006 
8007 	do {
8008 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
8009 		handle->nl_sk = netlink_kernel_create(netlink_num, NULL);
8010 #else
8011 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
8012 		handle->nl_sk =
8013 			netlink_kernel_create(netlink_num, NL_MULTICAST_GROUP,
8014 					      NULL, THIS_MODULE);
8015 #else
8016 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
8017 		handle->nl_sk =
8018 			netlink_kernel_create(netlink_num, NL_MULTICAST_GROUP,
8019 					      NULL, NULL, THIS_MODULE);
8020 #else
8021 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
8022 		handle->nl_sk =
8023 			netlink_kernel_create(&init_net, netlink_num,
8024 					      NL_MULTICAST_GROUP, NULL, NULL,
8025 					      THIS_MODULE);
8026 #else
8027 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
8028 		handle->nl_sk =
8029 			netlink_kernel_create(&init_net, netlink_num,
8030 					      THIS_MODULE, &cfg);
8031 #else
8032 		handle->nl_sk =
8033 			netlink_kernel_create(&init_net, netlink_num, &cfg);
8034 #endif
8035 #endif
8036 #endif
8037 #endif
8038 #endif
8039 		if (handle->nl_sk) {
8040 			PRINTM(MINFO, "Netlink number = %d\n", netlink_num);
8041 			handle->netlink_num = netlink_num;
8042 			break;
8043 		}
8044 		netlink_num--;
8045 	} while (netlink_num > 0);
8046 
8047 	if (handle->nl_sk == NULL) {
8048 		PRINTM(MERROR,
8049 		       "Could not initialize netlink event passing mechanism!\n");
8050 		goto err_kmalloc;
8051 	}
8052 
8053 	/* Create workqueue for main process */
8054 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
8055 	/* For kernel less than 2.6.14 name can not be
8056 	 * greater than 10 characters */
8057 	handle->workqueue = create_workqueue("MOAL_WORKQ");
8058 #else
8059 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
8060 	handle->workqueue =
8061 		alloc_workqueue("MOAL_WORK_QUEUE",
8062 				WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
8063 #else
8064 	handle->workqueue = create_workqueue("MOAL_WORK_QUEUE");
8065 #endif
8066 #endif
8067 	if (!handle->workqueue)
8068 		goto err_kmalloc;
8069 
8070 	MLAN_INIT_WORK(&handle->main_work, woal_main_work_queue);
8071 
8072 	if (!napi) {
8073 		/* Create workqueue for rx process */
8074 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
8075 		/* For kernel less than 2.6.14 name can not be
8076 		 * greater than 10 characters */
8077 		handle->rx_workqueue = create_workqueue("MOAL_RX_WORKQ");
8078 #else
8079 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
8080 		handle->rx_workqueue =
8081 			alloc_workqueue("MOAL_RX_WORK_QUEUE",
8082 					WQ_HIGHPRI | WQ_MEM_RECLAIM |
8083 					WQ_UNBOUND, 1);
8084 #else
8085 		handle->rx_workqueue = create_workqueue("MOAL_RX_WORK_QUEUE");
8086 #endif
8087 #endif
8088 		if (!handle->rx_workqueue) {
8089 			woal_terminate_workqueue(handle);
8090 			goto err_kmalloc;
8091 		}
8092 		MLAN_INIT_WORK(&handle->rx_work, woal_rx_work_queue);
8093 	}
8094 #define NAPI_BUDGET     64
8095 	if (napi) {
8096 		init_dummy_netdev(&handle->napi_dev);
8097 		netif_napi_add(&handle->napi_dev, &handle->napi_rx,
8098 			       woal_netdev_poll_rx, NAPI_BUDGET);
8099 		napi_enable(&handle->napi_rx);
8100 	}
8101 
8102 #ifdef REASSOCIATION
8103 	PRINTM(MINFO, "Starting re-association thread...\n");
8104 	handle->reassoc_thread.handle = handle;
8105 	woal_create_thread(woal_reassociation_thread,
8106 			   &handle->reassoc_thread, "woal_reassoc_service");
8107 
8108 	while (!handle->reassoc_thread.pid)
8109 		woal_sched_timeout(2);
8110 #endif /* REASSOCIATION */
8111 
8112 	/* Register the device. Fill up the private data structure with
8113 	 * relevant information from the card and request for the required
8114 	 * IRQ.
8115 	 */
8116 	if (woal_register_dev(handle) != MLAN_STATUS_SUCCESS) {
8117 		PRINTM(MFATAL, "Failed to register wlan device!\n");
8118 		goto err_registerdev;
8119 	}
8120 #ifdef ANDROID_KERNEL
8121 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
8122 	wakeup_source_init(&handle->ws, "mwlan");
8123 #else
8124 	wake_lock_init(&handle->wake_lock, WAKE_LOCK_SUSPEND, "mwlan");
8125 #endif
8126 #endif
8127 
8128 	/* Init FW and HW */
8129 	if (MLAN_STATUS_SUCCESS != woal_init_fw(handle)) {
8130 		PRINTM(MFATAL, "Firmware Init Failed\n");
8131 		goto err_init_fw;
8132 	}
8133 
8134 	LEAVE();
8135 	return handle;
8136 
8137 err_init_fw:
8138 	if ((handle->hardware_status == HardwareStatusFwReady) ||
8139 	    (handle->hardware_status == HardwareStatusReady)) {
8140 		PRINTM(MINFO, "shutdown mlan\n");
8141 		handle->init_wait_q_woken = MFALSE;
8142 		status = mlan_shutdown_fw(handle->pmlan_adapter);
8143 		if (status == MLAN_STATUS_PENDING)
8144 			wait_event_interruptible(handle->init_wait_q,
8145 						 handle->init_wait_q_woken);
8146 	}
8147 #ifdef ANDROID_KERNEL
8148 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
8149 	wakeup_source_trash(&handle->ws);
8150 #else
8151 	wake_lock_destroy(&handle->wake_lock);
8152 #endif
8153 #endif
8154 	/* Unregister device */
8155 	PRINTM(MINFO, "unregister device\n");
8156 	woal_unregister_dev(handle);
8157 err_registerdev:
8158 	handle->surprise_removed = MTRUE;
8159 #ifdef REASSOCIATION
8160 	if (handle->reassoc_thread.pid)
8161 		wake_up_interruptible(&handle->reassoc_thread.wait_q);
8162 	/* waiting for main thread quit */
8163 	while (handle->reassoc_thread.pid)
8164 		woal_sched_timeout(2);
8165 #endif /* REASSOCIATION */
8166 	if (napi)
8167 		netif_napi_del(&handle->napi_rx);
8168 	woal_terminate_workqueue(handle);
8169 err_kmalloc:
8170 	woal_free_moal_handle(handle);
8171 	if (index < MAX_MLAN_ADAPTER)
8172 		m_handle[index] = NULL;
8173 	((struct sdio_mmc_card *)card)->handle = NULL;
8174 err_handle:
8175 	MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
8176 exit_sem_err:
8177 	LEAVE();
8178 	return NULL;
8179 }
8180 
8181 /**
8182  *  @brief This function removes the card.
8183  *
8184  *  @param card    A pointer to card
8185  *
8186  *  @return        MLAN_STATUS_SUCCESS
8187  */
8188 mlan_status
8189 woal_remove_card(void *card)
8190 {
8191 	moal_handle *handle = NULL;
8192 	moal_private *priv = NULL;
8193 	mlan_status status;
8194 	int i;
8195 	int index = 0;
8196 
8197 	ENTER();
8198 
8199 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
8200 		goto exit_sem_err;
8201 	/* Find the correct handle */
8202 	for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
8203 		if (m_handle[index] && (m_handle[index]->card == card)) {
8204 			handle = m_handle[index];
8205 			break;
8206 		}
8207 	}
8208 	if (!handle)
8209 		goto exit_remove;
8210 	handle->surprise_removed = MTRUE;
8211 
8212 	flush_workqueue(handle->workqueue);
8213 	if (handle->rx_workqueue)
8214 		flush_workqueue(handle->rx_workqueue);
8215 
8216 	if (napi) {
8217 		napi_disable(&handle->napi_rx);
8218 		netif_napi_del(&handle->napi_rx);
8219 	}
8220 
8221 	/* Stop data */
8222 	for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
8223 		priv = handle->priv[i];
8224 		if (priv) {
8225 			woal_stop_queue(priv->netdev);
8226 			if (netif_carrier_ok(priv->netdev))
8227 				netif_carrier_off(priv->netdev);
8228 		}
8229 	}
8230 	if ((handle->hardware_status == HardwareStatusFwReady) ||
8231 	    (handle->hardware_status == HardwareStatusReady)) {
8232 		/* Shutdown firmware */
8233 		PRINTM(MIOCTL, "mlan_shutdown_fw.....\n");
8234 		handle->init_wait_q_woken = MFALSE;
8235 
8236 		status = mlan_shutdown_fw(handle->pmlan_adapter);
8237 		if (status == MLAN_STATUS_PENDING)
8238 			wait_event_interruptible(handle->init_wait_q,
8239 						 handle->init_wait_q_woken);
8240 		PRINTM(MIOCTL, "mlan_shutdown_fw done!\n");
8241 	}
8242 	if (atomic_read(&handle->rx_pending) || atomic_read(&handle->tx_pending)
8243 	    || atomic_read(&handle->ioctl_pending)) {
8244 		PRINTM(MERROR,
8245 		       "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n",
8246 		       atomic_read(&handle->rx_pending),
8247 		       atomic_read(&handle->tx_pending),
8248 		       atomic_read(&handle->ioctl_pending));
8249 	}
8250 	unregister_inetaddr_notifier(&handle->woal_notifier);
8251 
8252 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
8253 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
8254 	if (handle->is_remain_timer_set) {
8255 		woal_cancel_timer(&handle->remain_timer);
8256 		woal_remain_timer_func(handle);
8257 	}
8258 #endif
8259 #endif
8260 #if defined(WIFI_DIRECT_SUPPORT)
8261 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
8262 	if (handle->is_go_timer_set) {
8263 		woal_cancel_timer(&handle->go_timer);
8264 		handle->is_go_timer_set = MFALSE;
8265 	}
8266 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
8267 	/* Remove virtual interface */
8268 	woal_remove_virtual_interface(handle);
8269 #endif
8270 #endif
8271 #endif
8272 	/* Remove interface */
8273 	for (i = 0; i < MIN(MLAN_MAX_BSS_NUM, handle->priv_num); i++)
8274 		woal_remove_interface(handle, i);
8275 
8276 	woal_terminate_workqueue(handle);
8277 
8278 #ifdef UAP_CFG80211
8279 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
8280 	if (handle->is_cac_timer_set) {
8281 		woal_cancel_timer(&handle->cac_timer);
8282 		handle->is_cac_timer_set = MFALSE;
8283 	}
8284 #endif
8285 #endif
8286 #ifdef REASSOCIATION
8287 	PRINTM(MINFO, "Free reassoc_timer\n");
8288 	if (handle->is_reassoc_timer_set) {
8289 		woal_cancel_timer(&handle->reassoc_timer);
8290 		handle->is_reassoc_timer_set = MFALSE;
8291 	}
8292 	if (handle->reassoc_thread.pid)
8293 		wake_up_interruptible(&handle->reassoc_thread.wait_q);
8294 
8295 	/* waiting for main thread quit */
8296 	while (handle->reassoc_thread.pid)
8297 		woal_sched_timeout(2);
8298 #endif /* REASSOCIATION */
8299 #ifdef CONFIG_PROC_FS
8300 	woal_proc_exit(handle);
8301 #endif
8302 	/* Unregister device */
8303 	PRINTM(MINFO, "unregister device\n");
8304 	woal_unregister_dev(handle);
8305 #ifdef ANDROID_KERNEL
8306 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
8307 	wakeup_source_trash(&handle->ws);
8308 #else
8309 	wake_lock_destroy(&handle->wake_lock);
8310 #endif
8311 #endif
8312 	/* Free adapter structure */
8313 	PRINTM(MINFO, "Free Adapter\n");
8314 	woal_free_moal_handle(handle);
8315 
8316 	for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
8317 		if (m_handle[index] == handle) {
8318 			m_handle[index] = NULL;
8319 			break;
8320 		}
8321 	}
8322 exit_remove:
8323 	MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
8324 exit_sem_err:
8325 	LEAVE();
8326 	return MLAN_STATUS_SUCCESS;
8327 }
8328 
8329 #ifdef CONFIG_PROC_FS
8330 /**
8331  *  @brief This function switch the drv_mode
8332  *
8333  *  @param handle   A pointer to moal_handle structure
8334  *  @param mode     new drv_mode to switch.
8335  *
8336  *  @return        MLAN_STATUS_SUCCESS /MLAN_STATUS_FAILURE /MLAN_STATUS_PENDING
8337  */
8338 mlan_status
8339 woal_switch_drv_mode(moal_handle *handle, t_u32 mode)
8340 {
8341 	unsigned int i;
8342 	mlan_status status = MLAN_STATUS_SUCCESS;
8343 	moal_private *priv = NULL;
8344 
8345 	ENTER();
8346 
8347 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
8348 		goto exit_sem_err;
8349 
8350 	if (woal_update_drv_tbl(handle, mode) != MLAN_STATUS_SUCCESS) {
8351 		PRINTM(MERROR, "Could not update driver mode table!\n");
8352 		status = MLAN_STATUS_FAILURE;
8353 		goto exit;
8354 	}
8355 
8356 	/* Reset all interfaces */
8357 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
8358 	woal_reset_intf(priv, MOAL_IOCTL_WAIT, MTRUE);
8359 
8360 	status = woal_shutdown_fw(priv, MOAL_IOCTL_WAIT);
8361 	if (status != MLAN_STATUS_SUCCESS) {
8362 		PRINTM(MERROR, "func shutdown failed!\n");
8363 		goto exit;
8364 	}
8365 
8366 	/* Shutdown firmware */
8367 	PRINTM(MIOCTL, "mlan_shutdown_fw.....\n");
8368 	handle->init_wait_q_woken = MFALSE;
8369 	status = mlan_shutdown_fw(handle->pmlan_adapter);
8370 	if (status == MLAN_STATUS_PENDING)
8371 		wait_event_interruptible(handle->init_wait_q,
8372 					 handle->init_wait_q_woken);
8373 	PRINTM(MIOCTL, "mlan_shutdown_fw done!\n");
8374 	if (atomic_read(&handle->rx_pending) || atomic_read(&handle->tx_pending)
8375 	    || atomic_read(&handle->ioctl_pending)) {
8376 		PRINTM(MERROR,
8377 		       "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n",
8378 		       atomic_read(&handle->rx_pending),
8379 		       atomic_read(&handle->tx_pending),
8380 		       atomic_read(&handle->ioctl_pending));
8381 	}
8382 
8383 	unregister_inetaddr_notifier(&handle->woal_notifier);
8384 
8385 	/* Remove interface */
8386 	for (i = 0; i < MIN(MLAN_MAX_BSS_NUM, handle->priv_num); i++)
8387 		woal_remove_interface(handle, i);
8388 
8389 	/* Unregister mlan */
8390 	if (handle->pmlan_adapter) {
8391 		mlan_unregister(handle->pmlan_adapter);
8392 		if (atomic_read(&handle->lock_count) ||
8393 		    atomic_read(&handle->malloc_count) ||
8394 		    atomic_read(&handle->mbufalloc_count)) {
8395 			PRINTM(MERROR,
8396 			       "mlan has memory leak: lock_count=%d, malloc_count=%d, mbufalloc_count=%d\n",
8397 			       atomic_read(&handle->lock_count),
8398 			       atomic_read(&handle->malloc_count),
8399 			       atomic_read(&handle->mbufalloc_count));
8400 		}
8401 		handle->pmlan_adapter = NULL;
8402 	}
8403 
8404 	handle->priv_num = 0;
8405 	drv_mode = mode;
8406 	/* Init SW */
8407 	if (woal_init_sw(handle)) {
8408 		PRINTM(MFATAL, "Software Init Failed\n");
8409 		goto exit;
8410 	}
8411 	/* Init FW and HW */
8412 	if (woal_init_fw(handle)) {
8413 		PRINTM(MFATAL, "Firmware Init Failed\n");
8414 		goto exit;
8415 	}
8416 	LEAVE();
8417 	return status;
8418 exit:
8419 	MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
8420 exit_sem_err:
8421 	LEAVE();
8422 	return status;
8423 }
8424 #endif
8425 
8426 #define FW_POLL_TRIES 100
8427 #define FW_RESET_REG  0x0EE
8428 #define FW_RESET_VAL  0x99
8429 
8430 /**
8431  *  @brief This function reload fw
8432  *
8433  *  @param handle   A pointer to moal_handle structure
8434  *
8435  *  @return        0--success, otherwise failure
8436  */
8437 static int
8438 woal_reset_and_reload_fw(moal_handle *handle)
8439 {
8440 	int ret = 0, tries = 0;
8441 	t_u32 value = 1;
8442 	t_u32 reset_reg = FW_RESET_REG;
8443 	t_u8 reset_val = FW_RESET_VAL;
8444 
8445 	ENTER();
8446 	mlan_pm_wakeup_card(handle->pmlan_adapter);
8447 
8448     /** wait SOC fully wake up */
8449 	for (tries = 0; tries < FW_POLL_TRIES; ++tries) {
8450 		ret = woal_write_reg(handle, reset_reg, 0xba);
8451 		if (ret == MLAN_STATUS_SUCCESS) {
8452 			woal_read_reg(handle, reset_reg, &value);
8453 			if (value == 0xba) {
8454 				PRINTM(MMSG, "FW wake up\n");
8455 				break;
8456 			}
8457 		}
8458 		udelay(1000);
8459 	}
8460 	/* Write register to notify FW */
8461 	if (woal_write_reg(handle, reset_reg, reset_val) != MLAN_STATUS_SUCCESS) {
8462 		PRINTM(MERROR, "Failed to write register.\n");
8463 		ret = -EFAULT;
8464 		goto done;
8465 	}
8466 	/* Poll register around 100 ms */
8467 	for (tries = 0; tries < FW_POLL_TRIES; ++tries) {
8468 		woal_read_reg(handle, reset_reg, &value);
8469 		if (value == 0)
8470 			/* FW is ready */
8471 			break;
8472 		udelay(1000);
8473 	}
8474 
8475 	if (value) {
8476 		PRINTM(MERROR, "Failed to poll FW reset register %X=0x%x\n",
8477 		       reset_reg, value);
8478 		ret = -EFAULT;
8479 		goto done;
8480 	}
8481 	/* Download FW */
8482 	ret = woal_request_fw(handle);
8483 	if (ret) {
8484 		ret = -EFAULT;
8485 		goto done;
8486 	}
8487 	PRINTM(MMSG, "FW Reload successfully.");
8488 done:
8489 	LEAVE();
8490 	return ret;
8491 }
8492 
8493 /**
8494  *  @brief This function reload fw
8495  *
8496  *  @param handle   A pointer to moal_handle structure
8497  *
8498  *  @return        0--success, otherwise failure
8499  */
8500 static int
8501 woal_reload_fw(moal_handle *handle)
8502 {
8503 	int ret = 0;
8504 	ENTER();
8505 	/* Download FW */
8506 	ret = woal_request_fw(handle);
8507 	if (ret) {
8508 		ret = -EFAULT;
8509 		goto done;
8510 	}
8511 	PRINTM(MMSG, "FW Reload successfully.");
8512 done:
8513 	LEAVE();
8514 	return ret;
8515 }
8516 
8517 /**
8518  *  @brief This function reload fw
8519  *
8520  *  @param handle   A pointer to moal_handle structure
8521  *  @param mode     FW reload mode
8522  *
8523  *  @return        0--success, otherwise failure
8524  */
8525 void
8526 woal_request_fw_reload(moal_handle *handle, t_u8 mode)
8527 {
8528 	int intf_num;
8529 	int ret = 0;
8530 	mlan_ioctl_req *req = NULL;
8531 	mlan_ds_misc_cfg *misc = NULL;
8532 #if defined(WIFI_DIRECT_SUPPORT)
8533 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
8534 #if defined(STA_WEXT) || defined(UAP_WEXT)
8535 	t_u8 bss_role = MLAN_BSS_ROLE_STA;
8536 #endif
8537 #endif
8538 #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
8539 
8540 	ENTER();
8541 
8542     /** start block IOCTL */
8543 	handle->driver_state = MTRUE;
8544 	if (mode == FW_RELOAD_WITH_EMULATION) {
8545 		fw_reload = FW_RELOAD_WITH_EMULATION;
8546 		PRINTM(MMSG, "FW reload with re-emulation...\n");
8547 		LEAVE();
8548 		return;
8549 	}
8550 
8551     /** detach network interface */
8552 	for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
8553 		woal_stop_queue(handle->priv[intf_num]->netdev);
8554 		netif_device_detach(handle->priv[intf_num]->netdev);
8555 	}
8556 	handle->fw_reload = MTRUE;
8557 	woal_update_firmware_name(handle);
8558 	if (mode == FW_RELOAD_NO_EMULATION) {
8559 		ret = woal_reload_fw(handle);
8560 	} else if (mode == FW_RELOAD_SDIO_INBAND_RESET)
8561 		ret = woal_reset_and_reload_fw(handle);
8562 	else
8563 		ret = -EFAULT;
8564 	if (ret) {
8565 		PRINTM(MERROR, "FW reload fail\n");
8566 		goto done;
8567 	}
8568     /** un-block IOCTL */
8569 	handle->fw_reload = MFALSE;
8570 	handle->driver_state = MFALSE;
8571 	/* Restart the firmware */
8572 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
8573 	if (req) {
8574 		misc = (mlan_ds_misc_cfg *)req->pbuf;
8575 		misc->sub_command = MLAN_OID_MISC_WARM_RESET;
8576 		misc->param.fw_reload = MTRUE;
8577 		req->req_id = MLAN_IOCTL_MISC_CFG;
8578 		req->action = MLAN_ACT_SET;
8579 		if (MLAN_STATUS_SUCCESS !=
8580 		    woal_request_ioctl(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
8581 				       req, MOAL_IOCTL_WAIT)) {
8582 			ret = -EFAULT;
8583 			kfree(req);
8584 			goto done;
8585 		}
8586 		kfree(req);
8587 	}
8588 	handle->hardware_status = HardwareStatusReady;
8589 	/* Reset all interfaces */
8590 	ret = woal_reset_intf(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
8591 			      MOAL_IOCTL_WAIT, MTRUE);
8592 	/* Initialize private structures */
8593 	for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
8594 		woal_init_priv(handle->priv[intf_num], MOAL_IOCTL_WAIT);
8595 #if defined(WIFI_DIRECT_SUPPORT)
8596 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
8597 #if defined(STA_WEXT) || defined(UAP_WEXT)
8598 		if ((handle->priv[intf_num]->bss_type ==
8599 		     MLAN_BSS_TYPE_WIFIDIRECT) &&
8600 		    (GET_BSS_ROLE(handle->priv[intf_num]) ==
8601 		     MLAN_BSS_ROLE_UAP)) {
8602 			if (MLAN_STATUS_SUCCESS !=
8603 			    woal_bss_role_cfg(handle->priv[intf_num],
8604 					      MLAN_ACT_SET, MOAL_IOCTL_WAIT,
8605 					      &bss_role)) {
8606 				ret = -EFAULT;
8607 				goto done;
8608 			}
8609 		}
8610 #endif /* STA_WEXT || UAP_WEXT */
8611 #endif /* STA_SUPPORT && UAP_SUPPORT */
8612 #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
8613 	}
8614 
8615 	/* Enable interfaces */
8616 	for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
8617 		netif_device_attach(handle->priv[intf_num]->netdev);
8618 		woal_start_queue(handle->priv[intf_num]->netdev);
8619 	}
8620 done:
8621 	LEAVE();
8622 	return;
8623 }
8624 
8625 /**
8626  *  @brief This function initializes module.
8627  *
8628  *  @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
8629  */
8630 static int
8631 woal_init_module(void)
8632 {
8633 	int ret = (int)MLAN_STATUS_SUCCESS;
8634 	int index = 0;
8635 
8636 	ENTER();
8637 
8638 	PRINTM(MMSG, "wlan: Loading MWLAN driver\n");
8639 	/* Init the wlan_private pointer array first */
8640 	for (index = 0; index < MAX_MLAN_ADAPTER; index++)
8641 		m_handle[index] = NULL;
8642 	/* Init mutex */
8643 	MOAL_INIT_SEMAPHORE(&AddRemoveCardSem);
8644 
8645 #ifdef CONFIG_OF
8646 	woal_init_from_dev_tree();
8647 #endif
8648 
8649 	/* Create workqueue for hang process */
8650 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
8651 	/* For kernel less than 2.6.14 name can not be greater than 10
8652 	   characters */
8653 	hang_workqueue = create_workqueue("MOAL_HANG_WORKQ");
8654 #else
8655 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
8656 	hang_workqueue = alloc_workqueue("MOAL_HANG_WORK_QUEUE",
8657 					 WQ_HIGHPRI | WQ_MEM_RECLAIM |
8658 					 WQ_UNBOUND, 1);
8659 #else
8660 	hang_workqueue = create_workqueue("MOAL_HANG_WORK_QUEUE");
8661 #endif
8662 #endif
8663 	MLAN_INIT_WORK(&hang_work, woal_hang_work_queue);
8664 
8665 	/* Register with bus */
8666 	ret = woal_bus_register();
8667 	if (ret == MLAN_STATUS_SUCCESS)
8668 		PRINTM(MMSG, "wlan: Driver loaded successfully\n");
8669 	else
8670 		PRINTM(MMSG, "wlan: Driver loading failed\n");
8671 
8672 	LEAVE();
8673 	return ret;
8674 }
8675 
8676 /**
8677  *  @brief This function cleans module
8678  *
8679  *  @return        N/A
8680  */
8681 static void
8682 woal_cleanup_module(void)
8683 {
8684 	moal_handle *handle = NULL;
8685 	int index = 0;
8686 	int i;
8687 #if defined(STA_SUPPORT) && defined(STA_CFG80211)
8688 	unsigned long flags;
8689 #endif
8690 
8691 	ENTER();
8692 
8693 	PRINTM(MMSG, "wlan: Unloading MWLAN driver\n");
8694 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
8695 		goto exit_sem_err;
8696 	for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
8697 		handle = m_handle[index];
8698 		if (!handle)
8699 			continue;
8700 		if (!handle->priv_num)
8701 			goto exit;
8702 		if (MTRUE == woal_check_driver_status(handle))
8703 			goto exit;
8704 
8705 #ifdef SDIO_SUSPEND_RESUME
8706 #ifdef MMC_PM_KEEP_POWER
8707 		if (handle->is_suspended == MTRUE) {
8708 			woal_sdio_resume(&
8709 					 (((struct sdio_mmc_card *)handle->
8710 					   card)->func)->dev);
8711 		}
8712 #endif /* MMC_PM_KEEP_POWER */
8713 #endif /* SDIO_SUSPEND_RESUME */
8714 
8715 		/* Unregister all connected radiotap net devices */
8716 		if (handle->mon_if) {
8717 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
8718 			woal_set_net_monitor(handle->mon_if->priv,
8719 					     MOAL_IOCTL_WAIT, MFALSE, 0, NULL);
8720 			if (handle->ioctl_timeout) {
8721 				woal_ioctl_timeout(handle);
8722 				goto exit;
8723 			}
8724 #endif
8725 			netif_device_detach(handle->mon_if->mon_ndev);
8726 			if (handle->mon_if->mon_ndev->reg_state ==
8727 			    NETREG_REGISTERED)
8728 				unregister_netdev(handle->mon_if->mon_ndev);
8729 			handle->mon_if = NULL;
8730 		}
8731 
8732 		for (i = 0; i < handle->priv_num; i++) {
8733 #ifdef STA_SUPPORT
8734 			if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) {
8735 				if (handle->priv[i]->media_connected == MTRUE) {
8736 					woal_disconnect(handle->priv[i],
8737 							MOAL_IOCTL_WAIT_TIMEOUT,
8738 							NULL,
8739 							DEF_DEAUTH_REASON_CODE);
8740 					if (handle->ioctl_timeout) {
8741 						woal_ioctl_timeout(handle);
8742 						goto exit;
8743 					}
8744 				}
8745 #ifdef STA_CFG80211
8746 				if (IS_STA_CFG80211(cfg80211_wext) &&
8747 				    (handle->priv[i]->bss_type ==
8748 				     MLAN_BSS_TYPE_STA))
8749 					woal_clear_conn_params(handle->priv[i]);
8750 				spin_lock_irqsave(&handle->scan_req_lock,
8751 						  flags);
8752 				if (IS_STA_CFG80211(cfg80211_wext) &&
8753 				    handle->scan_request) {
8754 					woal_cfg80211_scan_done(handle->
8755 								scan_request,
8756 								MTRUE);
8757 					handle->scan_request = NULL;
8758 					handle->scan_priv = NULL;
8759 				}
8760 				spin_unlock_irqrestore(&handle->scan_req_lock,
8761 						       flags);
8762 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
8763 				if (IS_STA_CFG80211(cfg80211_wext) &&
8764 				    handle->priv[i]->sched_scanning) {
8765 					woal_stop_bg_scan(handle->priv[i],
8766 							  MOAL_IOCTL_WAIT_TIMEOUT);
8767 					if (handle->ioctl_timeout) {
8768 						woal_ioctl_timeout(handle);
8769 						goto exit;
8770 					}
8771 					handle->priv[i]->bg_scan_start = MFALSE;
8772 					handle->priv[i]->bg_scan_reported =
8773 						MFALSE;
8774 					cfg80211_sched_scan_stopped(handle->
8775 								    priv[i]->
8776 								    wdev->wiphy
8777 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
8778 								    , 0
8779 #endif
8780 						);
8781 					handle->priv[i]->sched_scanning =
8782 						MFALSE;
8783 				}
8784 #endif
8785 #endif
8786 			}
8787 #endif
8788 #ifdef UAP_SUPPORT
8789 			if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) {
8790 #ifdef MFG_CMD_SUPPORT
8791 				if (mfg_mode != MLAN_INIT_PARA_ENABLED)
8792 #endif
8793 					woal_disconnect(handle->priv[i],
8794 							MOAL_IOCTL_WAIT_TIMEOUT,
8795 							NULL,
8796 							DEF_DEAUTH_REASON_CODE);
8797 				if (handle->ioctl_timeout) {
8798 					woal_ioctl_timeout(handle);
8799 					goto exit;
8800 				}
8801 			}
8802 #endif
8803 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
8804 			woal_clear_all_mgmt_ies(handle->priv[i],
8805 						MOAL_IOCTL_WAIT_TIMEOUT);
8806 			if (handle->ioctl_timeout) {
8807 				woal_ioctl_timeout(handle);
8808 				goto exit;
8809 			}
8810 			woal_flush_tx_stat_queue(handle->priv[i]);
8811 #endif
8812 
8813 		}
8814 
8815 #ifdef MFG_CMD_SUPPORT
8816 		if (mfg_mode != MLAN_INIT_PARA_ENABLED)
8817 #endif
8818 			woal_set_deep_sleep(woal_get_priv
8819 					    (handle, MLAN_BSS_ROLE_ANY),
8820 					    MOAL_IOCTL_WAIT_TIMEOUT, MFALSE, 0);
8821 
8822 #ifdef MFG_CMD_SUPPORT
8823 		if (mfg_mode != MLAN_INIT_PARA_ENABLED)
8824 #endif
8825 			woal_shutdown_fw(woal_get_priv
8826 					 (handle, MLAN_BSS_ROLE_ANY),
8827 					 MOAL_IOCTL_WAIT_TIMEOUT);
8828 		if (handle->ioctl_timeout) {
8829 			woal_ioctl_timeout(handle);
8830 			goto exit;
8831 		}
8832 	}
8833 
8834 exit:
8835 	MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
8836 exit_sem_err:
8837 	/* Unregister from bus */
8838 	woal_bus_unregister();
8839 	PRINTM(MMSG, "wlan: Driver unloaded\n");
8840 	if (hang_workqueue) {
8841 		flush_workqueue(hang_workqueue);
8842 		destroy_workqueue(hang_workqueue);
8843 		hang_workqueue = NULL;
8844 	}
8845 
8846 	LEAVE();
8847 }
8848 
8849 #ifndef MODULE
8850 #ifdef MFG_CMD_SUPPORT
8851 /**
8852  *  @brief This function handle the mfg_mode from kernel boot command
8853  *
8854  *  @param str     buffer for mfg_mode
8855  *  @return        N/A
8856  */
8857 static int __init
8858 mfg_mode_setup(char *str)
8859 {
8860 	int val = -1;
8861 	get_option(&str, &val);
8862 	if (val > 0)
8863 		mfg_mode = 1;
8864 	PRINTM(MMSG, "mfg_mode=%d\n", mfg_mode);
8865 	return 1;
8866 }
8867 
8868 __setup("mfg_mode=", mfg_mode_setup);
8869 #endif
8870 #endif
8871 
8872 module_init(woal_init_module);
8873 module_exit(woal_cleanup_module);
8874 
8875 module_param(hw_test, int, 0660);
8876 MODULE_PARM_DESC(hw_test, "0: Disable hardware test; 1: Enable hardware test");
8877 #ifdef CONFIG_OF
8878 module_param(dts_enable, int, 0);
8879 MODULE_PARM_DESC(dts_enable, "0: Disable DTS; 1: Enable DTS");
8880 #endif
8881 module_param(fw_name, charp, 0660);
8882 MODULE_PARM_DESC(fw_name, "Firmware name");
8883 module_param(req_fw_nowait, int, 0);
8884 MODULE_PARM_DESC(req_fw_nowait,
8885 		 "0: Use request_firmware API; 1: Use request_firmware_nowait API");
8886 module_param(fw_reload, int, 0);
8887 MODULE_PARM_DESC(fw_reload,
8888 		 "0: disable fw_reload; 1: enable fw reload feature");
8889 module_param(fw_serial, int, 0);
8890 MODULE_PARM_DESC(fw_serial,
8891 		 "0: support parallel download FW; 1: support serial download FW");
8892 module_param(fw_region, int, 0);
8893 MODULE_PARM_DESC(fw_region, "1: create channel regulatory domain from FW");
8894 module_param(mac_addr, charp, 0660);
8895 MODULE_PARM_DESC(mac_addr, "MAC address");
8896 #ifdef MFG_CMD_SUPPORT
8897 module_param(mfg_mode, int, 0660);
8898 MODULE_PARM_DESC(mfg_mode,
8899 		 "0: Download normal firmware; 1: Download MFG firmware");
8900 #endif /* MFG_CMD_SUPPORT */
8901 module_param(drv_mode, int, 0660);
8902 #if defined(WIFI_DIRECT_SUPPORT)
8903 MODULE_PARM_DESC(drv_mode,
8904 		 "Bit 0: STA; Bit 1: uAP; Bit 2: WIFIDIRECT; Bit 4: NAN");
8905 #else
8906 MODULE_PARM_DESC(drv_mode, "Bit 0: STA; Bit 1: uAP; Bit 4: NAN");
8907 #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
8908 #ifdef STA_SUPPORT
8909 module_param(max_sta_bss, int, 0);
8910 MODULE_PARM_DESC(max_sta_bss, "Number of STA interfaces (1)");
8911 module_param(sta_name, charp, 0);
8912 MODULE_PARM_DESC(sta_name, "STA interface name");
8913 #endif /* STA_SUPPORT */
8914 #ifdef UAP_SUPPORT
8915 module_param(max_uap_bss, int, 0);
8916 MODULE_PARM_DESC(max_uap_bss, "Number of uAP interfaces (1)");
8917 module_param(uap_name, charp, 0);
8918 MODULE_PARM_DESC(uap_name, "uAP interface name");
8919 #endif /* UAP_SUPPORT */
8920 #if defined(WIFI_DIRECT_SUPPORT)
8921 module_param(max_wfd_bss, int, 0);
8922 MODULE_PARM_DESC(max_wfd_bss, "Number of WIFIDIRECT interfaces (1)");
8923 module_param(wfd_name, charp, 0);
8924 MODULE_PARM_DESC(wfd_name, "WIFIDIRECT interface name");
8925 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
8926 module_param(max_vir_bss, int, 0);
8927 MODULE_PARM_DESC(max_vir_bss, "Number of Virtual interfaces (0)");
8928 #endif
8929 #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
8930 module_param(nan_name, charp, 0);
8931 MODULE_PARM_DESC(nan_name, "NAN interface name");
8932 module_param(max_nan_bss, int, 0);
8933 MODULE_PARM_DESC(max_nan_bss, "Number of NAN interfaces (1)");
8934 #ifdef DEBUG_LEVEL1
8935 module_param(drvdbg, uint, 0660);
8936 MODULE_PARM_DESC(drvdbg, "Driver debug");
8937 #endif /* DEBUG_LEVEL1 */
8938 module_param(auto_ds, int, 0660);
8939 MODULE_PARM_DESC(auto_ds,
8940 		 "0: MLAN default; 1: Enable auto deep sleep; 2: Disable auto deep sleep");
8941 module_param(ps_mode, int, 0660);
8942 MODULE_PARM_DESC(ps_mode,
8943 		 "0: MLAN default; 1: Enable IEEE PS mode; 2: Disable IEEE PS mode");
8944 module_param(max_tx_buf, int, 0);
8945 MODULE_PARM_DESC(max_tx_buf, "Maximum Tx buffer size (2048/4096/8192)");
8946 
8947 module_param(intmode, int, 0);
8948 MODULE_PARM_DESC(intmode, "0: INT_MODE_SDIO, 1: INT_MODE_GPIO");
8949 module_param(gpiopin, int, 0);
8950 MODULE_PARM_DESC(gpiopin, "255:new GPIO int mode, other vlue: gpio pin number");
8951 
8952 #ifdef SDIO_SUSPEND_RESUME
8953 module_param(pm_keep_power, int, 0);
8954 MODULE_PARM_DESC(pm_keep_power, "1: PM keep power; 0: PM no power");
8955 module_param(shutdown_hs, int, 0);
8956 MODULE_PARM_DESC(shutdown_hs,
8957 		 "1: Enable HS when shutdown; 0: No HS when shutdown");
8958 #endif
8959 #if defined(STA_SUPPORT)
8960 module_param(cfg_11d, int, 0);
8961 MODULE_PARM_DESC(cfg_11d,
8962 		 "0: MLAN default; 1: Enable 802.11d; 2: Disable 802.11d");
8963 #endif
8964 module_param(dpd_data_cfg, charp, 0);
8965 MODULE_PARM_DESC(dpd_data_cfg, "DPD data file name");
8966 module_param(init_cfg, charp, 0);
8967 MODULE_PARM_DESC(init_cfg, "Init config file name");
8968 module_param(cal_data_cfg, charp, 0);
8969 MODULE_PARM_DESC(cal_data_cfg, "Calibration data file name");
8970 module_param(txpwrlimit_cfg, charp, 0);
8971 MODULE_PARM_DESC(txpwrlimit_cfg,
8972 		 "Set configuration data of Tx power limitation");
8973 module_param(cntry_txpwr, int, 0);
8974 MODULE_PARM_DESC(cntry_txpwr,
8975 		 "Allow setting tx power table of country; 0: disable (default), 1: enable.");
8976 module_param(init_hostcmd_cfg, charp, 0);
8977 MODULE_PARM_DESC(init_hostcmd_cfg, "Init hostcmd file name");
8978 module_param(cfg80211_wext, int, 0660);
8979 MODULE_PARM_DESC(cfg80211_wext,
8980 #ifdef STA_WEXT
8981 		 "Bit 0: STA WEXT; "
8982 #endif
8983 #ifdef UAP_WEXT
8984 		 "Bit 1: UAP WEXT; "
8985 #endif
8986 #ifdef STA_CFG80211
8987 		 "Bit 2: STA CFG80211; "
8988 #endif
8989 #ifdef UAP_CFG80211
8990 		 "Bit 3: UAP CFG80211;"
8991 #endif
8992 	);
8993 module_param(wq_sched_prio, int, 0);
8994 module_param(wq_sched_policy, int, 0);
8995 MODULE_PARM_DESC(wq_sched_prio, "Priority of work queue");
8996 MODULE_PARM_DESC(wq_sched_policy,
8997 		 "0: SCHED_NORMAL; 1: SCHED_FIFO; 2: SCHED_RR; 3: SCHED_BATCH; 5: SCHED_IDLE");
8998 module_param(rx_work, int, 0);
8999 MODULE_PARM_DESC(rx_work,
9000 		 "0: default; 1: Enable rx_work_queue; 2: Disable rx_work_queue");
9001 #if defined(WIFI_DIRECT_SUPPORT)
9002 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
9003 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
9004 module_param(p2p_enh, int, 0);
9005 MODULE_PARM_DESC(p2p_enh, "1: Enable enhanced P2P; 0: Disable enhanced P2P");
9006 #endif
9007 #endif
9008 #endif
9009 
9010 #ifdef ANDROID_KERNEL
9011 module_param(wakelock_timeout, int, 0);
9012 MODULE_PARM_DESC(wakelock_timeout, "set wakelock_timeout value (ms)");
9013 #endif
9014 
9015 module_param(dev_cap_mask, uint, 0);
9016 MODULE_PARM_DESC(dev_cap_mask, "Device capability mask");
9017 
9018 module_param(sdio_rx_aggr, int, 0);
9019 MODULE_PARM_DESC(sdio_rx_aggr,
9020 		 "1: Enable SDIO rx aggr; 0: Disable SDIO rx aggr");
9021 
9022 module_param(pmic, int, 0);
9023 MODULE_PARM_DESC(pmic,
9024 		 "1: Send pmic configure cmd to firmware; 0: No pmic configure cmd sent to firmware");
9025 
9026 module_param(uap_oper_ctrl, uint, 0);
9027 MODULE_PARM_DESC(uap_oper_ctrl, "0:default; 0x20001:uap restarts on channel 6");
9028 
9029 module_param(hs_wake_interval, int, 0660);
9030 MODULE_PARM_DESC(hs_wake_interval,
9031 		 "Host sleep wakeup interval,it will round to nearest multiple dtim*beacon_period in fw");
9032 module_param(indication_gpio, int, 0);
9033 MODULE_PARM_DESC(indication_gpio,
9034 		 "GPIO to indicate wakeup source; high four bits: level for normal wakeup; low four bits: GPIO pin number.");
9035 
9036 module_param(indrstcfg, int, 0);
9037 MODULE_PARM_DESC(indrstcfg,
9038 		 "Independent reset configuration; high byte: GPIO pin number; low byte: IR mode");
9039 
9040 module_param(fixed_beacon_buffer, int, 0);
9041 MODULE_PARM_DESC(fixed_beacon_buffer,
9042 		 "0: allocate default buffer size; 1: allocate max buffer size.");
9043 
9044 #ifdef WIFI_DIRECT_SUPPORT
9045 module_param(GoAgeoutTime, int, 0);
9046 MODULE_PARM_DESC(GoAgeoutTime,
9047 		 "0: use default ageout time; set Go age out time (TU 100ms)");
9048 #endif
9049 
9050 module_param(gtk_rekey_offload, int, 0);
9051 MODULE_PARM_DESC(gtk_rekey_offload,
9052 		 "0: disable gtk_rekey_offload; 1: enable gtk_rekey_offload (default); 2: enable gtk_rekey_offload in suspend mode only;");
9053 
9054 module_param(multi_dtim, int, 0);
9055 MODULE_PARM_DESC(multi_dtim, "DTIM interval");
9056 
9057 module_param(inact_tmo, int, 0);
9058 MODULE_PARM_DESC(inact_tmo, "IEEE ps inactivity timout value");
9059 
9060 module_param(napi, int, 0);
9061 MODULE_PARM_DESC(napi, "1: enable napi api; 0: disable napi");
9062 
9063 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
9064 module_param(dfs_offload, int, 0);
9065 MODULE_PARM_DESC(dfs_offload, "1: enable dfs offload; 0: disable dfs offload.");
9066 #endif
9067 
9068 module_param(drcs_chantime_mode, int, 0);
9069 MODULE_PARM_DESC(drcs_chantime_mode,
9070 		 "0: use default value;Bit31~Bit24:Channel time for channel index0;Bit23~Bit16:mode for channel index0;Bit15~Bit8:Channel time for channel index1;Bit7~Bit0:mode for channel index1; mode:0--PM1,1--Null2Self.");
9071 
9072 module_param(roamoffload_in_hs, int, 0);
9073 MODULE_PARM_DESC(roamoffload_in_hs,
9074 		 "1: enable fw roaming only when host suspend; 0: always enable fw roaming.");
9075 
9076 MODULE_DESCRIPTION("M-WLAN Driver");
9077 MODULE_AUTHOR("Marvell International Ltd.");
9078 MODULE_VERSION(MLAN_RELEASE_VERSION);
9079 MODULE_LICENSE("GPL");
9080