[go: nahoru, domu]

1/******************************************************************************
2 *
3 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 ******************************************************************************/
15#define _RTW_MLME_C_
16
17#include <osdep_service.h>
18#include <drv_types.h>
19#include <recv_osdep.h>
20#include <xmit_osdep.h>
21#include <hal_intf.h>
22#include <mlme_osdep.h>
23#include <sta_info.h>
24#include <linux/ieee80211.h>
25#include <wifi.h>
26#include <wlan_bssdef.h>
27#include <rtw_sreset.h>
28
29static struct wlan_network *
30rtw_select_candidate_from_queue(struct mlme_priv *pmlmepriv);
31static int rtw_do_join(struct rtw_adapter *padapter);
32
33static void rtw_init_mlme_timer(struct rtw_adapter *padapter)
34{
35	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
36
37	setup_timer(&pmlmepriv->assoc_timer, rtw23a_join_to_handler,
38		    (unsigned long)padapter);
39
40	setup_timer(&pmlmepriv->scan_to_timer, rtw_scan_timeout_handler23a,
41		    (unsigned long)padapter);
42
43	setup_timer(&pmlmepriv->dynamic_chk_timer,
44		    rtw_dynamic_check_timer_handler, (unsigned long)padapter);
45
46	setup_timer(&pmlmepriv->set_scan_deny_timer,
47		    rtw_set_scan_deny_timer_hdl, (unsigned long)padapter);
48}
49
50int rtw_init_mlme_priv23a(struct rtw_adapter *padapter)
51{
52	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
53	int res = _SUCCESS;
54
55	pmlmepriv->nic_hdl = padapter;
56
57	pmlmepriv->fw_state = 0;
58	pmlmepriv->cur_network.network.ifmode = NL80211_IFTYPE_UNSPECIFIED;
59	/*  1: active, 0: pasive. Maybe someday we should rename this
60	    varable to "active_mode" (Jeff) */
61	pmlmepriv->scan_mode = SCAN_ACTIVE;
62
63	spin_lock_init(&pmlmepriv->lock);
64	_rtw_init_queue23a(&pmlmepriv->scanned_queue);
65
66	memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct cfg80211_ssid));
67
68	rtw_clear_scan_deny(padapter);
69
70	rtw_init_mlme_timer(padapter);
71	return res;
72}
73
74#ifdef CONFIG_8723AU_AP_MODE
75static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen)
76{
77	if (*ppie) {
78		kfree(*ppie);
79		*plen = 0;
80		*ppie = NULL;
81	}
82}
83#endif
84
85void rtw23a_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv)
86{
87#ifdef CONFIG_8723AU_AP_MODE
88	kfree(pmlmepriv->assoc_req);
89	kfree(pmlmepriv->assoc_rsp);
90	rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_req_ie,
91			      &pmlmepriv->wps_probe_req_ie_len);
92#endif
93}
94
95void rtw_free_mlme_priv23a(struct mlme_priv *pmlmepriv)
96{
97	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
98		 ("rtw_free_mlme_priv23a\n"));
99
100	rtw23a_free_mlme_priv_ie_data(pmlmepriv);
101}
102
103struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv, gfp_t gfp)
104{
105	struct wlan_network *pnetwork;
106
107	pnetwork = kzalloc(sizeof(struct wlan_network), gfp);
108	if (pnetwork) {
109		INIT_LIST_HEAD(&pnetwork->list);
110		pnetwork->network_type = 0;
111		pnetwork->fixed = false;
112		pnetwork->last_scanned = jiffies;
113		pnetwork->aid = 0;
114		pnetwork->join_res = 0;
115	}
116
117	return pnetwork;
118}
119
120static void _rtw_free_network23a(struct mlme_priv *pmlmepriv,
121				 struct wlan_network *pnetwork)
122{
123	if (!pnetwork)
124		return;
125
126	if (pnetwork->fixed == true)
127		return;
128
129	list_del_init(&pnetwork->list);
130
131	kfree(pnetwork);
132}
133
134/*
135 return the wlan_network with the matching addr
136
137 Shall be called under atomic context... to avoid possible racing condition...
138*/
139struct wlan_network *
140rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr)
141{
142	struct list_head *phead, *plist;
143	struct wlan_network *pnetwork = NULL;
144
145	if (is_zero_ether_addr(addr)) {
146		pnetwork = NULL;
147		goto exit;
148	}
149
150	/* spin_lock_bh(&scanned_queue->lock); */
151
152	phead = get_list_head(scanned_queue);
153	plist = phead->next;
154
155	while (plist != phead) {
156		pnetwork = container_of(plist, struct wlan_network, list);
157
158		if (ether_addr_equal(addr, pnetwork->network.MacAddress))
159			break;
160
161		plist = plist->next;
162	}
163
164	if (plist == phead)
165		pnetwork = NULL;
166
167	/* spin_unlock_bh(&scanned_queue->lock); */
168
169exit:
170
171	return pnetwork;
172}
173
174void rtw_free_network_queue23a(struct rtw_adapter *padapter)
175{
176	struct list_head *phead, *plist, *ptmp;
177	struct wlan_network *pnetwork;
178	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
179	struct rtw_queue *scanned_queue = &pmlmepriv->scanned_queue;
180
181	spin_lock_bh(&scanned_queue->lock);
182
183	phead = get_list_head(scanned_queue);
184
185	list_for_each_safe(plist, ptmp, phead) {
186		pnetwork = container_of(plist, struct wlan_network, list);
187
188		_rtw_free_network23a(pmlmepriv, pnetwork);
189	}
190
191	spin_unlock_bh(&scanned_queue->lock);
192}
193
194int rtw_if_up23a(struct rtw_adapter *padapter)
195{
196	int res;
197
198	if (padapter->bDriverStopped || padapter->bSurpriseRemoved ||
199	    !check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
200		RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
201			 ("rtw_if_up23a:bDriverStopped(%d) OR "
202			  "bSurpriseRemoved(%d)", padapter->bDriverStopped,
203			  padapter->bSurpriseRemoved));
204		res = false;
205	} else
206		res =  true;
207
208	return res;
209}
210
211void rtw_generate_random_ibss23a(u8 *pibss)
212{
213	unsigned long curtime = jiffies;
214
215	pibss[0] = 0x02;  /* in ad-hoc mode bit1 must set to 1 */
216	pibss[1] = 0x11;
217	pibss[2] = 0x87;
218	pibss[3] = curtime & 0xff;/* p[0]; */
219	pibss[4] = (curtime >> 8) & 0xff;/* p[1]; */
220	pibss[5] = (curtime >> 16) & 0xff;/* p[2]; */
221
222	return;
223}
224
225void rtw_set_roaming(struct rtw_adapter *adapter, u8 to_roaming)
226{
227	if (to_roaming == 0)
228		adapter->mlmepriv.to_join = false;
229	adapter->mlmepriv.to_roaming = to_roaming;
230}
231
232static void _rtw_roaming(struct rtw_adapter *padapter,
233			 struct wlan_network *tgt_network)
234{
235	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
236	struct wlan_network *pnetwork;
237	int do_join_r;
238
239	if (tgt_network)
240		pnetwork = tgt_network;
241	else
242		pnetwork = &pmlmepriv->cur_network;
243
244	if (padapter->mlmepriv.to_roaming > 0) {
245		DBG_8723A("roaming from %s("MAC_FMT"), length:%d\n",
246			  pnetwork->network.Ssid.ssid,
247			  MAC_ARG(pnetwork->network.MacAddress),
248			  pnetwork->network.Ssid.ssid_len);
249		memcpy(&pmlmepriv->assoc_ssid, &pnetwork->network.Ssid,
250		       sizeof(struct cfg80211_ssid));
251
252		pmlmepriv->assoc_by_bssid = false;
253
254		while (1) {
255			do_join_r = rtw_do_join(padapter);
256			if (do_join_r == _SUCCESS)
257				break;
258			else {
259				DBG_8723A("roaming do_join return %d\n",
260					  do_join_r);
261				pmlmepriv->to_roaming--;
262
263				if (padapter->mlmepriv.to_roaming > 0)
264					continue;
265				else {
266					DBG_8723A("%s(%d) -to roaming fail, "
267						  "indicate_disconnect\n",
268						  __func__, __LINE__);
269					rtw_indicate_disconnect23a(padapter);
270					break;
271				}
272			}
273		}
274	}
275}
276
277void rtw23a_roaming(struct rtw_adapter *padapter,
278		    struct wlan_network *tgt_network)
279{
280	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
281
282	spin_lock_bh(&pmlmepriv->lock);
283	_rtw_roaming(padapter, tgt_network);
284	spin_unlock_bh(&pmlmepriv->lock);
285}
286
287static void rtw_free_network_nolock(struct mlme_priv *pmlmepriv,
288				    struct wlan_network *pnetwork)
289{
290	_rtw_free_network23a(pmlmepriv, pnetwork);
291}
292
293bool rtw_is_same_ibss23a(struct rtw_adapter *adapter,
294			 struct wlan_network *pnetwork)
295{
296	int ret;
297	struct security_priv *psecuritypriv = &adapter->securitypriv;
298
299	if (psecuritypriv->dot11PrivacyAlgrthm != 0 &&
300	    pnetwork->network.Privacy == 0)
301		ret = false;
302	else if (psecuritypriv->dot11PrivacyAlgrthm == 0 &&
303		 pnetwork->network.Privacy == 1)
304		ret = false;
305	else
306		ret = true;
307
308	return ret;
309}
310
311inline int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b);
312inline int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b)
313{
314	return (a->Ssid.ssid_len == b->Ssid.ssid_len) &&
315		!memcmp(a->Ssid.ssid, b->Ssid.ssid, a->Ssid.ssid_len);
316}
317
318int is_same_network23a(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst)
319{
320	u16 s_cap, d_cap;
321
322	s_cap = src->capability;
323	d_cap = dst->capability;
324
325	return ((src->Ssid.ssid_len == dst->Ssid.ssid_len) &&
326		/*	(src->DSConfig == dst->DSConfig) && */
327		ether_addr_equal(src->MacAddress, dst->MacAddress) &&
328		!memcmp(src->Ssid.ssid, dst->Ssid.ssid, src->Ssid.ssid_len) &&
329		(s_cap & WLAN_CAPABILITY_IBSS) ==
330		(d_cap & WLAN_CAPABILITY_IBSS) &&
331		(s_cap & WLAN_CAPABILITY_ESS) == (d_cap & WLAN_CAPABILITY_ESS));
332}
333
334struct wlan_network *
335rtw_get_oldest_wlan_network23a(struct rtw_queue *scanned_queue)
336{
337	struct list_head *plist, *phead;
338	struct wlan_network *pwlan;
339	struct wlan_network *oldest = NULL;
340
341	phead = get_list_head(scanned_queue);
342
343	list_for_each(plist, phead) {
344		pwlan = container_of(plist, struct wlan_network, list);
345
346		if (pwlan->fixed != true) {
347			if (!oldest || time_after(oldest->last_scanned,
348						  pwlan->last_scanned))
349				oldest = pwlan;
350		}
351	}
352
353	return oldest;
354}
355
356void update_network23a(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src,
357		       struct rtw_adapter *padapter, bool update_ie)
358{
359	u8 ss_ori = dst->PhyInfo.SignalStrength;
360	u8 sq_ori = dst->PhyInfo.SignalQuality;
361	long rssi_ori = dst->Rssi;
362
363	u8 ss_smp = src->PhyInfo.SignalStrength;
364	u8 sq_smp = src->PhyInfo.SignalQuality;
365	long rssi_smp = src->Rssi;
366
367	u8 ss_final;
368	u8 sq_final;
369	long rssi_final;
370
371	DBG_8723A("%s %s(%pM, ch%u) ss_ori:%3u, sq_ori:%3u, rssi_ori:%3ld, "
372		  "ss_smp:%3u, sq_smp:%3u, rssi_smp:%3ld\n",
373		  __func__, src->Ssid.ssid, src->MacAddress,
374		  src->DSConfig, ss_ori, sq_ori, rssi_ori,
375		  ss_smp, sq_smp, rssi_smp
376	);
377
378	/* The rule below is 1/5 for sample value, 4/5 for history value */
379	if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) &&
380	    is_same_network23a(&padapter->mlmepriv.cur_network.network, src)) {
381		/* Take the recvpriv's value for the connected AP*/
382		ss_final = padapter->recvpriv.signal_strength;
383		sq_final = padapter->recvpriv.signal_qual;
384		/* the rssi value here is undecorated, and will be
385		   used for antenna diversity */
386		if (sq_smp != 101) /* from the right channel */
387			rssi_final = (src->Rssi+dst->Rssi*4)/5;
388		else
389			rssi_final = rssi_ori;
390	} else {
391		if (sq_smp != 101) { /* from the right channel */
392			ss_final = ((u32)src->PhyInfo.SignalStrength +
393				    (u32)dst->PhyInfo.SignalStrength * 4) / 5;
394			sq_final = ((u32)src->PhyInfo.SignalQuality +
395				    (u32)dst->PhyInfo.SignalQuality * 4) / 5;
396			rssi_final = src->Rssi+dst->Rssi * 4 / 5;
397		} else {
398			/* bss info not receiving from the right channel, use
399			   the original RX signal infos */
400			ss_final = dst->PhyInfo.SignalStrength;
401			sq_final = dst->PhyInfo.SignalQuality;
402			rssi_final = dst->Rssi;
403		}
404
405	}
406
407	if (update_ie)
408		memcpy(dst, src, get_wlan_bssid_ex_sz(src));
409
410	dst->PhyInfo.SignalStrength = ss_final;
411	dst->PhyInfo.SignalQuality = sq_final;
412	dst->Rssi = rssi_final;
413
414	DBG_8723A("%s %s(%pM), SignalStrength:%u, SignalQuality:%u, "
415		  "RawRSSI:%ld\n",  __func__, dst->Ssid.ssid, dst->MacAddress,
416		  dst->PhyInfo.SignalStrength,
417		  dst->PhyInfo.SignalQuality, dst->Rssi);
418}
419
420static void update_current_network(struct rtw_adapter *adapter,
421				   struct wlan_bssid_ex *pnetwork)
422{
423	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
424
425	if (check_fwstate(pmlmepriv, _FW_LINKED) &&
426	    is_same_network23a(&pmlmepriv->cur_network.network, pnetwork)) {
427		update_network23a(&pmlmepriv->cur_network.network,
428				  pnetwork, adapter, true);
429
430		rtw_update_protection23a(adapter,
431					 pmlmepriv->cur_network.network.IEs,
432					 pmlmepriv->cur_network.network.IELength);
433	}
434}
435
436/*
437
438Caller must hold pmlmepriv->lock first.
439
440*/
441static void rtw_update_scanned_network(struct rtw_adapter *adapter,
442				       struct wlan_bssid_ex *target)
443{
444	struct list_head *plist, *phead;
445	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
446	struct wlan_network *pnetwork = NULL;
447	struct wlan_network *oldest = NULL;
448	struct rtw_queue *queue = &pmlmepriv->scanned_queue;
449	u32 bssid_ex_sz;
450	int found = 0;
451
452	spin_lock_bh(&queue->lock);
453	phead = get_list_head(queue);
454
455	list_for_each(plist, phead) {
456		pnetwork = container_of(plist, struct wlan_network, list);
457
458		if (is_same_network23a(&pnetwork->network, target)) {
459			found = 1;
460			break;
461		}
462		if (!oldest || time_after(oldest->last_scanned,
463					  pnetwork->last_scanned))
464			oldest = pnetwork;
465	}
466
467	/* If we didn't find a match, then get a new network slot to initialize
468	 * with this beacon's information */
469	if (!found) {
470		pnetwork = rtw_alloc_network(pmlmepriv, GFP_ATOMIC);
471		if (!pnetwork) {
472			if (!oldest) {
473				RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
474					 ("\n\n\nsomething wrong here\n\n\n"));
475				goto exit;
476			}
477			pnetwork = oldest;
478		} else
479			list_add_tail(&pnetwork->list, &queue->queue);
480
481		bssid_ex_sz = get_wlan_bssid_ex_sz(target);
482		target->Length = bssid_ex_sz;
483		memcpy(&pnetwork->network, target, bssid_ex_sz);
484
485		/*  variable initialize */
486		pnetwork->fixed = false;
487		pnetwork->last_scanned = jiffies;
488
489		pnetwork->network_type = 0;
490		pnetwork->aid = 0;
491		pnetwork->join_res = 0;
492
493		/* bss info not receiving from the right channel */
494		if (pnetwork->network.PhyInfo.SignalQuality == 101)
495			pnetwork->network.PhyInfo.SignalQuality = 0;
496	} else {
497		/*
498		 * we have an entry and we are going to update it. But
499		 * this entry may be already expired. In this case we
500		 * do the same as we found a new net and call the
501		 * new_net handler
502		 */
503		bool update_ie = true;
504
505		pnetwork->last_scanned = jiffies;
506
507		/* target.reserved == 1, means that scanned network is
508		 * a bcn frame. */
509		if (pnetwork->network.IELength > target->IELength &&
510		    target->reserved == 1)
511			update_ie = false;
512
513		update_network23a(&pnetwork->network, target, adapter,
514				  update_ie);
515	}
516
517exit:
518	spin_unlock_bh(&queue->lock);
519}
520
521static void rtw_add_network(struct rtw_adapter *adapter,
522			    struct wlan_bssid_ex *pnetwork)
523{
524	update_current_network(adapter, pnetwork);
525	rtw_update_scanned_network(adapter, pnetwork);
526}
527
528/* select the desired network based on the capability of the (i)bss. */
529/*  check items: (1) security */
530/*			   (2) network_type */
531/*			   (3) WMM */
532/*			   (4) HT */
533/*                      (5) others */
534static int rtw_is_desired_network(struct rtw_adapter *adapter,
535				  struct wlan_network *pnetwork)
536{
537	struct security_priv *psecuritypriv = &adapter->securitypriv;
538	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
539	u32 desired_encmode;
540	u32 privacy;
541	int bselected = true;
542
543	desired_encmode = psecuritypriv->ndisencryptstatus;
544	privacy = pnetwork->network.Privacy;
545
546	if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
547		if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
548					    WLAN_OUI_TYPE_MICROSOFT_WPA,
549					    pnetwork->network.IEs,
550					    pnetwork->network.IELength))
551			return true;
552		else
553			return false;
554	}
555	if (adapter->registrypriv.wifi_spec == 1) {
556		/* for  correct flow of 8021X  to do.... */
557		if (desired_encmode == Ndis802_11EncryptionDisabled &&
558		    privacy != 0)
559			bselected = false;
560	}
561
562	if (desired_encmode != Ndis802_11EncryptionDisabled && privacy == 0) {
563		DBG_8723A("desired_encmode: %d, privacy: %d\n",
564			  desired_encmode, privacy);
565		bselected = false;
566	}
567
568	if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
569		if (pnetwork->network.ifmode !=
570		    pmlmepriv->cur_network.network.ifmode)
571			bselected = false;
572	}
573
574	return bselected;
575}
576
577/* TODO: Perry : For Power Management */
578void rtw_atimdone_event_callback23a(struct rtw_adapter *adapter, const u8 *pbuf)
579{
580	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
581		 ("receive atimdone_evet\n"));
582
583	return;
584}
585
586void rtw_survey_event_cb23a(struct rtw_adapter *adapter, const u8 *pbuf)
587{
588	u32 len;
589	struct wlan_bssid_ex *pnetwork;
590	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
591	struct survey_event *survey = (struct survey_event *)pbuf;
592
593	pnetwork = survey->bss;
594
595	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
596		 ("rtw_survey_event_cb23a, ssid=%s\n", pnetwork->Ssid.ssid));
597
598	len = get_wlan_bssid_ex_sz(pnetwork);
599	if (len > (sizeof(struct wlan_bssid_ex))) {
600		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
601			 ("\n ****rtw_survey_event_cb23a: return a wrong "
602			  "bss ***\n"));
603		return;
604	}
605
606	spin_lock_bh(&pmlmepriv->lock);
607
608	/*  update IBSS_network 's timestamp */
609	if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
610		/* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
611		   "rtw_survey_event_cb23a : WIFI_ADHOC_MASTER_STATE\n\n"); */
612		if (ether_addr_equal(pmlmepriv->cur_network.network.MacAddress,
613				     pnetwork->MacAddress)) {
614			struct wlan_network *ibss_wlan;
615
616			pmlmepriv->cur_network.network.beacon_interval =
617				pnetwork->beacon_interval;
618			pmlmepriv->cur_network.network.capability =
619				pnetwork->capability;
620			pmlmepriv->cur_network.network.tsf = pnetwork->tsf;
621			spin_lock_bh(&pmlmepriv->scanned_queue.lock);
622			ibss_wlan = rtw_find_network23a(
623				&pmlmepriv->scanned_queue,
624				pnetwork->MacAddress);
625			if (ibss_wlan) {
626				pmlmepriv->cur_network.network.beacon_interval =
627					ibss_wlan->network.beacon_interval;
628				pmlmepriv->cur_network.network.capability =
629					ibss_wlan->network.capability;
630				pmlmepriv->cur_network.network.tsf =
631					ibss_wlan->network.tsf;
632				spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
633				goto exit;
634			}
635			spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
636		}
637	}
638
639	/*  lock pmlmepriv->lock when you accessing network_q */
640	if (!check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
641		if (pnetwork->Ssid.ssid[0] == 0)
642			pnetwork->Ssid.ssid_len = 0;
643
644		rtw_add_network(adapter, pnetwork);
645	}
646
647exit:
648
649	spin_unlock_bh(&pmlmepriv->lock);
650
651	kfree(survey->bss);
652	survey->bss = NULL;
653
654	return;
655}
656
657void
658rtw_surveydone_event_callback23a(struct rtw_adapter *adapter, const u8 *pbuf)
659{
660	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
661	struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
662	int ret;
663
664	spin_lock_bh(&pmlmepriv->lock);
665
666	if (pmlmepriv->wps_probe_req_ie) {
667		pmlmepriv->wps_probe_req_ie_len = 0;
668		kfree(pmlmepriv->wps_probe_req_ie);
669		pmlmepriv->wps_probe_req_ie = NULL;
670	}
671
672	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
673		 ("rtw_surveydone_event_callback23a: fw_state:%x\n\n",
674		  get_fwstate(pmlmepriv)));
675
676	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
677		del_timer_sync(&pmlmepriv->scan_to_timer);
678
679		_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
680	} else {
681		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
682			 ("nic status =%x, survey done event comes too late!\n",
683			  get_fwstate(pmlmepriv)));
684	}
685
686	rtw_set_signal_stat_timer(&adapter->recvpriv);
687
688	if (pmlmepriv->to_join == true) {
689		set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
690		if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
691			ret = rtw_select_and_join_from_scanned_queue23a(
692				pmlmepriv);
693			if (ret != _SUCCESS)
694				rtw_do_join_adhoc(adapter);
695		} else {
696			pmlmepriv->to_join = false;
697			ret = rtw_select_and_join_from_scanned_queue23a(
698				pmlmepriv);
699			if (ret != _SUCCESS) {
700				DBG_8723A("try_to_join, but select scanning "
701					  "queue fail, to_roaming:%d\n",
702					  adapter->mlmepriv.to_roaming);
703				if (adapter->mlmepriv.to_roaming) {
704					if (--pmlmepriv->to_roaming == 0 ||
705					    rtw_sitesurvey_cmd23a(
706						    adapter,
707						    &pmlmepriv->assoc_ssid, 1,
708						    NULL, 0) != _SUCCESS) {
709						rtw_set_roaming(adapter, 0);
710						rtw_free_assoc_resources23a(
711							adapter, 1);
712						rtw_indicate_disconnect23a(
713							adapter);
714					} else
715						pmlmepriv->to_join = true;
716				}
717				_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
718			}
719		}
720	}
721
722	spin_unlock_bh(&pmlmepriv->lock);
723
724	rtw_os_xmit_schedule23a(adapter);
725
726	if (pmlmeext->sitesurvey_res.bss_cnt == 0)
727		rtw_sreset_reset(adapter);
728
729	rtw_cfg80211_surveydone_event_callback(adapter);
730}
731
732static void free_scanqueue(struct mlme_priv *pmlmepriv)
733{
734	struct wlan_network *pnetwork;
735	struct rtw_queue *scan_queue = &pmlmepriv->scanned_queue;
736	struct list_head *plist, *phead, *ptemp;
737
738	RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+free_scanqueue\n"));
739	spin_lock_bh(&scan_queue->lock);
740
741	phead = get_list_head(scan_queue);
742
743	list_for_each_safe(plist, ptemp, phead) {
744		pnetwork = container_of(plist, struct wlan_network, list);
745		pnetwork->fixed = false;
746		_rtw_free_network23a(pmlmepriv, pnetwork);
747	}
748
749	spin_unlock_bh(&scan_queue->lock);
750}
751
752/*
753 *rtw_free_assoc_resources23a: the caller has to lock pmlmepriv->lock
754 */
755void rtw_free_assoc_resources23a(struct rtw_adapter *adapter,
756				 int lock_scanned_queue)
757{
758	struct wlan_network *pwlan;
759	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
760	struct sta_priv *pstapriv = &adapter->stapriv;
761	struct wlan_network *tgt_network = &pmlmepriv->cur_network;
762	struct sta_info *psta;
763
764	RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
765		 ("+rtw_free_assoc_resources23a\n"));
766	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
767		 ("tgt_network->network.MacAddress="MAC_FMT" ssid=%s\n",
768		  MAC_ARG(tgt_network->network.MacAddress),
769		  tgt_network->network.Ssid.ssid));
770
771	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_AP_STATE)) {
772		psta = rtw_get_stainfo23a(&adapter->stapriv,
773					  tgt_network->network.MacAddress);
774
775		spin_lock_bh(&pstapriv->sta_hash_lock);
776		rtw_free_stainfo23a(adapter,  psta);
777		spin_unlock_bh(&pstapriv->sta_hash_lock);
778	}
779
780	if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE |
781			  WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE)) {
782		rtw_free_all_stainfo23a(adapter);
783
784		psta = rtw_get_bcmc_stainfo23a(adapter);
785		spin_lock_bh(&pstapriv->sta_hash_lock);
786		rtw_free_stainfo23a(adapter, psta);
787		spin_unlock_bh(&pstapriv->sta_hash_lock);
788
789		rtw_init_bcmc_stainfo23a(adapter);
790	}
791
792	if (lock_scanned_queue)
793		spin_lock_bh(&pmlmepriv->scanned_queue.lock);
794
795	pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue,
796				    tgt_network->network.MacAddress);
797	if (pwlan)
798		pwlan->fixed = false;
799	else
800		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
801			 ("rtw_free_assoc_resources23a : pwlan== NULL\n"));
802
803	if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) &&
804	    adapter->stapriv.asoc_sta_count == 1)
805		rtw_free_network_nolock(pmlmepriv, pwlan);
806
807	if (lock_scanned_queue)
808		spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
809
810	pmlmepriv->key_mask = 0;
811}
812
813/*
814*rtw_indicate_connect23a: the caller has to lock pmlmepriv->lock
815*/
816void rtw_indicate_connect23a(struct rtw_adapter *padapter)
817{
818	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
819
820	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
821		 ("+rtw_indicate_connect23a\n"));
822
823	pmlmepriv->to_join = false;
824
825	if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
826		set_fwstate(pmlmepriv, _FW_LINKED);
827
828		rtw_led_control(padapter, LED_CTL_LINK);
829
830		rtw_cfg80211_indicate_connect(padapter);
831
832		netif_carrier_on(padapter->pnetdev);
833
834		if (padapter->pid[2] != 0)
835			kill_pid(find_vpid(padapter->pid[2]), SIGALRM, 1);
836	}
837
838	rtw_set_roaming(padapter, 0);
839
840	rtw_set_scan_deny(padapter, 3000);
841
842	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
843		 ("-rtw_indicate_connect23a: fw_state=0x%08x\n",
844		  get_fwstate(pmlmepriv)));
845}
846
847/*
848 *rtw_indicate_disconnect23a: the caller has to lock pmlmepriv->lock
849 */
850void rtw_indicate_disconnect23a(struct rtw_adapter *padapter)
851{
852	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
853
854	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
855		 ("+rtw_indicate_disconnect23a\n"));
856
857	_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING|WIFI_UNDER_WPS);
858
859	/* DBG_8723A("clear wps when %s\n", __func__); */
860
861	if (padapter->mlmepriv.to_roaming > 0)
862		_clr_fwstate_(pmlmepriv, _FW_LINKED);
863
864	if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) ||
865	    padapter->mlmepriv.to_roaming <= 0) {
866		rtw_os_indicate_disconnect23a(padapter);
867
868		/* set ips_deny_time to avoid enter IPS before LPS leave */
869		padapter->pwrctrlpriv.ips_deny_time =
870			jiffies + msecs_to_jiffies(3000);
871
872		_clr_fwstate_(pmlmepriv, _FW_LINKED);
873
874		rtw_led_control(padapter, LED_CTL_NO_LINK);
875
876		rtw_clear_scan_deny(padapter);
877
878	}
879
880	rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_DISCONNECT, 1);
881}
882
883void rtw_scan_abort23a(struct rtw_adapter *adapter)
884{
885	unsigned long start;
886	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
887	struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
888
889	start = jiffies;
890	pmlmeext->scan_abort = true;
891	while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) &&
892	       jiffies_to_msecs(jiffies - start) <= 200) {
893		if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
894			break;
895
896		DBG_8723A("%s(%s): fw_state = _FW_UNDER_SURVEY!\n",
897			  __func__, adapter->pnetdev->name);
898		msleep(20);
899	}
900
901	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
902		if (!adapter->bDriverStopped && !adapter->bSurpriseRemoved)
903			DBG_8723A("%s(%s): waiting for scan_abort time out!\n",
904				  __func__, adapter->pnetdev->name);
905		rtw_cfg80211_indicate_scan_done(wdev_to_priv(adapter->rtw_wdev),
906						true);
907	}
908	pmlmeext->scan_abort = false;
909}
910
911static struct sta_info *
912rtw_joinbss_update_stainfo(struct rtw_adapter *padapter,
913			   struct wlan_network *pnetwork)
914{
915	int i;
916	struct sta_info *bmc_sta, *psta;
917	struct recv_reorder_ctrl *preorder_ctrl;
918	struct sta_priv *pstapriv = &padapter->stapriv;
919
920	psta = rtw_get_stainfo23a(pstapriv, pnetwork->network.MacAddress);
921	if (!psta)
922		psta = rtw_alloc_stainfo23a(pstapriv,
923					    pnetwork->network.MacAddress,
924					    GFP_ATOMIC);
925
926	if (psta) { /* update ptarget_sta */
927		DBG_8723A("%s\n", __func__);
928
929		psta->aid  = pnetwork->join_res;
930		psta->mac_id = 0;
931
932		/* sta mode */
933		rtl8723a_SetHalODMVar(padapter, HAL_ODM_STA_INFO, psta, true);
934
935		/* security related */
936		if (padapter->securitypriv.dot11AuthAlgrthm ==
937		    dot11AuthAlgrthm_8021X) {
938			padapter->securitypriv.binstallGrpkey = 0;
939			padapter->securitypriv.busetkipkey = 0;
940
941			psta->ieee8021x_blocked = true;
942			psta->dot118021XPrivacy =
943				padapter->securitypriv.dot11PrivacyAlgrthm;
944
945			memset(&psta->dot118021x_UncstKey, 0,
946			       sizeof (union Keytype));
947
948			memset(&psta->dot11tkiprxmickey, 0,
949			       sizeof (union Keytype));
950			memset(&psta->dot11tkiptxmickey, 0,
951			       sizeof (union Keytype));
952
953			memset(&psta->dot11txpn, 0, sizeof (union pn48));
954			memset(&psta->dot11rxpn, 0, sizeof (union pn48));
955		}
956
957		/*	Commented by Albert 2012/07/21 */
958		/*	When doing the WPS, the wps_ie_len won't equal to 0 */
959		/*	And the Wi-Fi driver shouldn't allow the data packet
960			to be transmitted. */
961		if (padapter->securitypriv.wps_ie_len != 0) {
962			psta->ieee8021x_blocked = true;
963			padapter->securitypriv.wps_ie_len = 0;
964		}
965
966		/* for A-MPDU Rx reordering buffer control for bmc_sta &
967		 * sta_info */
968		/* if A-MPDU Rx is enabled, resetting
969		   rx_ordering_ctrl wstart_b(indicate_seq) to default
970		   value = 0xffff */
971		/* todo: check if AP can send A-MPDU packets */
972		for (i = 0; i < 16 ; i++) {
973			/* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */
974			preorder_ctrl = &psta->recvreorder_ctrl[i];
975			preorder_ctrl->enable = false;
976			preorder_ctrl->indicate_seq = 0xffff;
977			preorder_ctrl->wend_b = 0xffff;
978			/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */
979			preorder_ctrl->wsize_b = 64;
980		}
981
982		bmc_sta = rtw_get_bcmc_stainfo23a(padapter);
983		if (bmc_sta) {
984			for (i = 0; i < 16 ; i++) {
985				preorder_ctrl = &bmc_sta->recvreorder_ctrl[i];
986				preorder_ctrl->enable = false;
987				preorder_ctrl->indicate_seq = 0xffff;
988				preorder_ctrl->wend_b = 0xffff;
989				/* max_ampdu_sz; ex. 32(kbytes) ->
990				   wsize_b = 32 */
991				preorder_ctrl->wsize_b = 64;
992			}
993		}
994
995		/* misc. */
996		update_sta_info23a(padapter, psta);
997
998	}
999
1000	return psta;
1001}
1002
1003/* pnetwork : returns from rtw23a_joinbss_event_cb */
1004/* ptarget_wlan: found from scanned_queue */
1005static void
1006rtw_joinbss_update_network23a(struct rtw_adapter *padapter,
1007			      struct wlan_network *ptarget_wlan,
1008			      struct wlan_network  *pnetwork)
1009{
1010	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1011	struct wlan_network *cur_network = &pmlmepriv->cur_network;
1012
1013	DBG_8723A("%s\n", __func__);
1014
1015	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
1016		 ("\nfw_state:%x, BSSID:"MAC_FMT"\n", get_fwstate(pmlmepriv),
1017		  MAC_ARG(pnetwork->network.MacAddress)));
1018
1019	/*  why not use ptarget_wlan?? */
1020	memcpy(&cur_network->network, &pnetwork->network,
1021	       pnetwork->network.Length);
1022	/*  some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs */
1023	cur_network->network.IELength = ptarget_wlan->network.IELength;
1024	memcpy(&cur_network->network.IEs[0], &ptarget_wlan->network.IEs[0],
1025	       MAX_IE_SZ);
1026
1027	cur_network->network.capability = ptarget_wlan->network.capability;
1028	cur_network->network.beacon_interval =
1029		ptarget_wlan->network.beacon_interval;
1030	cur_network->network.tsf = ptarget_wlan->network.tsf;
1031	cur_network->aid = pnetwork->join_res;
1032
1033	rtw_set_signal_stat_timer(&padapter->recvpriv);
1034	padapter->recvpriv.signal_strength =
1035		ptarget_wlan->network.PhyInfo.SignalStrength;
1036	padapter->recvpriv.signal_qual =
1037		ptarget_wlan->network.PhyInfo.SignalQuality;
1038	/*
1039	 * the ptarget_wlan->network.Rssi is raw data, we use
1040	 * ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled)
1041	 */
1042	padapter->recvpriv.rssi = translate_percentage_to_dbm(
1043		ptarget_wlan->network.PhyInfo.SignalStrength);
1044	DBG_8723A("%s signal_strength:%3u, rssi:%3d, signal_qual:%3u\n",
1045		  __func__, padapter->recvpriv.signal_strength,
1046		  padapter->recvpriv.rssi, padapter->recvpriv.signal_qual);
1047	rtw_set_signal_stat_timer(&padapter->recvpriv);
1048
1049	/* update fw_state will clr _FW_UNDER_LINKING here indirectly */
1050	switch (pnetwork->network.ifmode) {
1051	case NL80211_IFTYPE_P2P_CLIENT:
1052	case NL80211_IFTYPE_STATION:
1053		if (pmlmepriv->fw_state & WIFI_UNDER_WPS)
1054			pmlmepriv->fw_state = WIFI_STATION_STATE|WIFI_UNDER_WPS;
1055		else
1056			pmlmepriv->fw_state = WIFI_STATION_STATE;
1057		break;
1058	case NL80211_IFTYPE_ADHOC:
1059		pmlmepriv->fw_state = WIFI_ADHOC_STATE;
1060		break;
1061	default:
1062		pmlmepriv->fw_state = WIFI_NULL_STATE;
1063		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1064			 ("Invalid network_mode\n"));
1065		break;
1066	}
1067
1068	rtw_update_protection23a(padapter, cur_network->network.IEs,
1069				 cur_network->network.IELength);
1070
1071	rtw_update_ht_cap23a(padapter, cur_network->network.IEs,
1072			     cur_network->network.IELength);
1073}
1074
1075/*
1076 * Notes:
1077 * the function could be > passive_level (the same context as Rx tasklet)
1078 * pnetwork : returns from rtw23a_joinbss_event_cb
1079 * ptarget_wlan: found from scanned_queue
1080 * if join_res > 0, for (fw_state==WIFI_STATION_STATE),
1081 * we check if  "ptarget_sta" & "ptarget_wlan" exist.
1082 * if join_res > 0, for (fw_state==WIFI_ADHOC_STATE),
1083 * we only check if "ptarget_wlan" exist.
1084 * if join_res > 0, update "cur_network->network" from "pnetwork->network"
1085 * if (ptarget_wlan !=NULL).
1086 */
1087
1088void rtw_joinbss_event_prehandle23a(struct rtw_adapter *adapter, u8 *pbuf)
1089{
1090	struct sta_info *ptarget_sta, *pcur_sta;
1091	struct sta_priv *pstapriv = &adapter->stapriv;
1092	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
1093	struct wlan_network *pnetwork = (struct wlan_network *)pbuf;
1094	struct wlan_network *cur_network = &pmlmepriv->cur_network;
1095	struct wlan_network *pcur_wlan, *ptarget_wlan = NULL;
1096	bool the_same_macaddr;
1097
1098	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
1099		 ("joinbss event call back received with res=%d\n",
1100		  pnetwork->join_res));
1101
1102	if (pmlmepriv->assoc_ssid.ssid_len == 0) {
1103		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1104			 ("@@@@@   joinbss event call back  for Any SSid\n"));
1105	} else {
1106		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1107			 ("@@@@@   rtw23a_joinbss_event_cb for SSid:%s\n",
1108			  pmlmepriv->assoc_ssid.ssid));
1109	}
1110
1111	if (ether_addr_equal(pnetwork->network.MacAddress,
1112			     cur_network->network.MacAddress))
1113		the_same_macaddr = true;
1114	else
1115		the_same_macaddr = false;
1116
1117	pnetwork->network.Length = get_wlan_bssid_ex_sz(&pnetwork->network);
1118	if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) {
1119		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1120			 ("\n\n ***joinbss_evt_callback return a wrong bss "
1121			  "***\n\n"));
1122		return;
1123	}
1124
1125	spin_lock_bh(&pmlmepriv->lock);
1126
1127	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
1128		 ("\n rtw23a_joinbss_event_cb !! _enter_critical\n"));
1129
1130	if (pnetwork->join_res > 0) {
1131		spin_lock_bh(&pmlmepriv->scanned_queue.lock);
1132		if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
1133			/* s1. find ptarget_wlan */
1134			if (check_fwstate(pmlmepriv, _FW_LINKED)) {
1135				if (the_same_macaddr == true) {
1136					ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
1137				} else {
1138					pcur_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
1139					if (pcur_wlan)
1140						pcur_wlan->fixed = false;
1141
1142					pcur_sta = rtw_get_stainfo23a(pstapriv, cur_network->network.MacAddress);
1143					if (pcur_sta) {
1144						spin_lock_bh(&pstapriv->sta_hash_lock);
1145						rtw_free_stainfo23a(adapter,
1146								    pcur_sta);
1147						spin_unlock_bh(&pstapriv->sta_hash_lock);
1148					}
1149
1150					ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress);
1151					if (check_fwstate(pmlmepriv,
1152							  WIFI_STATION_STATE)) {
1153						if (ptarget_wlan)
1154							ptarget_wlan->fixed =
1155								true;
1156					}
1157				}
1158
1159			} else {
1160				ptarget_wlan = rtw_find_network23a(
1161					&pmlmepriv->scanned_queue,
1162					pnetwork->network.MacAddress);
1163				if (check_fwstate(pmlmepriv,
1164						  WIFI_STATION_STATE)) {
1165					if (ptarget_wlan)
1166						ptarget_wlan->fixed = true;
1167				}
1168			}
1169
1170			/* s2. update cur_network */
1171			if (ptarget_wlan)
1172				rtw_joinbss_update_network23a(adapter,
1173							      ptarget_wlan,
1174							      pnetwork);
1175			else {
1176				RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1177					 ("Can't find ptarget_wlan when "
1178					  "joinbss_event callback\n"));
1179				spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1180				goto ignore_joinbss_callback;
1181			}
1182
1183			/* s3. find ptarget_sta & update ptarget_sta after
1184			   update cur_network only for station mode */
1185			if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
1186				ptarget_sta = rtw_joinbss_update_stainfo(
1187					adapter, pnetwork);
1188				if (!ptarget_sta) {
1189					RT_TRACE(_module_rtl871x_mlme_c_,
1190						 _drv_err_,
1191						 ("Can't update stainfo when "
1192						  "joinbss_event callback\n"));
1193					spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1194					goto ignore_joinbss_callback;
1195				}
1196			}
1197
1198			/* s4. indicate connect */
1199			if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
1200				rtw_indicate_connect23a(adapter);
1201			else {
1202				/* adhoc mode will rtw_indicate_connect23a
1203				   when rtw_stassoc_event_callback23a */
1204				RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
1205					 ("adhoc mode, fw_state:%x",
1206					  get_fwstate(pmlmepriv)));
1207			}
1208
1209			/* s5. Cancle assoc_timer */
1210			del_timer_sync(&pmlmepriv->assoc_timer);
1211
1212			RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
1213				 ("Cancle assoc_timer\n"));
1214		} else {
1215			RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1216				 ("rtw23a_joinbss_event_cb err: fw_state:%x",
1217				 get_fwstate(pmlmepriv)));
1218			spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1219			goto ignore_joinbss_callback;
1220		}
1221		spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1222	} else if (pnetwork->join_res == -4) {
1223		rtw_reset_securitypriv23a(adapter);
1224		mod_timer(&pmlmepriv->assoc_timer,
1225			  jiffies + msecs_to_jiffies(1));
1226
1227		/* rtw_free_assoc_resources23a(adapter, 1); */
1228
1229		if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
1230			RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1231				 ("fail! clear _FW_UNDER_LINKING ^^^fw_state="
1232				  "%x\n", get_fwstate(pmlmepriv)));
1233			_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
1234		}
1235	} else {
1236		/* if join_res < 0 (join fails), then try again */
1237		mod_timer(&pmlmepriv->assoc_timer,
1238			  jiffies + msecs_to_jiffies(1));
1239		_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
1240	}
1241
1242ignore_joinbss_callback:
1243
1244	spin_unlock_bh(&pmlmepriv->lock);
1245}
1246
1247void rtw23a_joinbss_event_cb(struct rtw_adapter *adapter, const u8 *pbuf)
1248{
1249	struct wlan_network *pnetwork = (struct wlan_network *)pbuf;
1250
1251	mlmeext_joinbss_event_callback23a(adapter, pnetwork->join_res);
1252
1253	rtw_os_xmit_schedule23a(adapter);
1254}
1255
1256void rtw_stassoc_event_callback23a(struct rtw_adapter *adapter, const u8 *pbuf)
1257{
1258	struct sta_info *psta;
1259	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
1260	struct stassoc_event *pstassoc = (struct stassoc_event *)pbuf;
1261	struct wlan_network *cur_network = &pmlmepriv->cur_network;
1262	struct wlan_network *ptarget_wlan;
1263
1264	if (rtw_access_ctrl23a(adapter, pstassoc->macaddr) == false)
1265		return;
1266
1267#ifdef CONFIG_8723AU_AP_MODE
1268	if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
1269		psta = rtw_get_stainfo23a(&adapter->stapriv, pstassoc->macaddr);
1270		if (psta) {
1271			/* bss_cap_update_on_sta_join23a(adapter, psta); */
1272			/* sta_info_update23a(adapter, psta); */
1273			ap_sta_info_defer_update23a(adapter, psta);
1274		}
1275		return;
1276	}
1277#endif
1278	/* for AD-HOC mode */
1279	psta = rtw_get_stainfo23a(&adapter->stapriv, pstassoc->macaddr);
1280	if (psta != NULL) {
1281		/* the sta have been in sta_info_queue => do nothing */
1282		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1283			 ("Error: rtw_stassoc_event_callback23a: sta has "
1284			  "been in sta_hash_queue\n"));
1285		/* between drv has received this event before and
1286		   fw have not yet to set key to CAM_ENTRY) */
1287		return;
1288	}
1289
1290	psta = rtw_alloc_stainfo23a(&adapter->stapriv, pstassoc->macaddr,
1291		GFP_KERNEL);
1292	if (!psta) {
1293		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1294			 ("Can't alloc sta_info when "
1295			  "rtw_stassoc_event_callback23a\n"));
1296		return;
1297	}
1298
1299	/* to do : init sta_info variable */
1300	psta->qos_option = 0;
1301	psta->mac_id = (uint)pstassoc->cam_id;
1302	/* psta->aid = (uint)pstassoc->cam_id; */
1303	DBG_8723A("%s\n", __func__);
1304	/* for ad-hoc mode */
1305	rtl8723a_SetHalODMVar(adapter, HAL_ODM_STA_INFO, psta, true);
1306
1307	if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
1308		psta->dot118021XPrivacy =
1309			adapter->securitypriv.dot11PrivacyAlgrthm;
1310
1311	psta->ieee8021x_blocked = false;
1312
1313	spin_lock_bh(&pmlmepriv->lock);
1314
1315	if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
1316	    check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
1317		if (adapter->stapriv.asoc_sta_count == 2) {
1318			spin_lock_bh(&pmlmepriv->scanned_queue.lock);
1319			ptarget_wlan =
1320				rtw_find_network23a(&pmlmepriv->scanned_queue,
1321						    cur_network->network.MacAddress);
1322			if (ptarget_wlan)
1323				ptarget_wlan->fixed = true;
1324			spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1325			/*  a sta + bc/mc_stainfo (not Ibss_stainfo) */
1326			rtw_indicate_connect23a(adapter);
1327		}
1328	}
1329
1330	spin_unlock_bh(&pmlmepriv->lock);
1331
1332	mlmeext_sta_add_event_callback23a(adapter, psta);
1333}
1334
1335void rtw_stadel_event_callback23a(struct rtw_adapter *adapter, const u8 *pbuf)
1336{
1337	int mac_id;
1338	struct sta_info *psta;
1339	struct wlan_network *pwlan;
1340	struct wlan_bssid_ex *pdev_network;
1341	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
1342	struct stadel_event *pstadel = (struct stadel_event *)pbuf;
1343	struct sta_priv *pstapriv = &adapter->stapriv;
1344	struct wlan_network *tgt_network = &pmlmepriv->cur_network;
1345
1346	psta = rtw_get_stainfo23a(&adapter->stapriv, pstadel->macaddr);
1347	if (psta)
1348		mac_id = psta->mac_id;
1349	else
1350		mac_id = pstadel->mac_id;
1351
1352	DBG_8723A("%s(mac_id=%d)=" MAC_FMT "\n", __func__, mac_id,
1353		  MAC_ARG(pstadel->macaddr));
1354
1355	if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
1356		return;
1357
1358	mlmeext_sta_del_event_callback23a(adapter);
1359
1360	spin_lock_bh(&pmlmepriv->lock);
1361
1362	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
1363		if (adapter->mlmepriv.to_roaming > 0) {
1364			/* this stadel_event is caused by roaming,
1365			   decrease to_roaming */
1366			pmlmepriv->to_roaming--;
1367		} else if (adapter->mlmepriv.to_roaming == 0)
1368			rtw_set_roaming(adapter, adapter->registrypriv.max_roaming_times);
1369		if (*((u16 *)pstadel->rsvd) != WLAN_REASON_EXPIRATION_CHK)
1370			rtw_set_roaming(adapter, 0); /* don't roam */
1371
1372		rtw_free_uc_swdec_pending_queue23a(adapter);
1373
1374		rtw_free_assoc_resources23a(adapter, 1);
1375		rtw_indicate_disconnect23a(adapter);
1376		spin_lock_bh(&pmlmepriv->scanned_queue.lock);
1377		/*  remove the network entry in scanned_queue */
1378		pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue,
1379					    tgt_network->network.MacAddress);
1380		if (pwlan) {
1381			pwlan->fixed = false;
1382			rtw_free_network_nolock(pmlmepriv, pwlan);
1383		}
1384		spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1385
1386		_rtw_roaming(adapter, tgt_network);
1387	}
1388
1389	if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
1390	    check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
1391
1392		spin_lock_bh(&pstapriv->sta_hash_lock);
1393		rtw_free_stainfo23a(adapter,  psta);
1394		spin_unlock_bh(&pstapriv->sta_hash_lock);
1395
1396		/* a sta + bc/mc_stainfo (not Ibss_stainfo) */
1397		if (adapter->stapriv.asoc_sta_count == 1) {
1398			spin_lock_bh(&pmlmepriv->scanned_queue.lock);
1399			/* free old ibss network */
1400			/* pwlan = rtw_find_network23a(
1401			   &pmlmepriv->scanned_queue, pstadel->macaddr); */
1402			pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue,
1403						    tgt_network->network.MacAddress);
1404			if (pwlan) {
1405				pwlan->fixed = false;
1406				rtw_free_network_nolock(pmlmepriv, pwlan);
1407			}
1408			spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1409			/* re-create ibss */
1410			pdev_network = &adapter->registrypriv.dev_network;
1411
1412			memcpy(pdev_network, &tgt_network->network,
1413			       get_wlan_bssid_ex_sz(&tgt_network->network));
1414
1415			rtw_do_join_adhoc(adapter);
1416		}
1417	}
1418
1419	spin_unlock_bh(&pmlmepriv->lock);
1420}
1421
1422/*
1423* rtw23a_join_to_handler - Timeout/failure handler for CMD JoinBss
1424* @adapter: pointer to _adapter structure
1425*/
1426void rtw23a_join_to_handler (unsigned long data)
1427{
1428	struct rtw_adapter *adapter = (struct rtw_adapter *)data;
1429	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
1430	int do_join_r;
1431
1432	DBG_8723A("%s, fw_state=%x\n", __func__, get_fwstate(pmlmepriv));
1433
1434	if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
1435		return;
1436
1437	spin_lock_bh(&pmlmepriv->lock);
1438
1439	if (adapter->mlmepriv.to_roaming > 0) {
1440		/* join timeout caused by roaming */
1441		while (1) {
1442			pmlmepriv->to_roaming--;
1443			if (adapter->mlmepriv.to_roaming != 0) {
1444				/* try another */
1445				DBG_8723A("%s try another roaming\n", __func__);
1446				do_join_r = rtw_do_join(adapter);
1447				if (do_join_r != _SUCCESS) {
1448					DBG_8723A("%s roaming do_join return "
1449						  "%d\n", __func__ , do_join_r);
1450					continue;
1451				}
1452				break;
1453			} else {
1454				DBG_8723A("%s We've try roaming but fail\n",
1455					  __func__);
1456				rtw_indicate_disconnect23a(adapter);
1457				break;
1458			}
1459		}
1460	} else {
1461		rtw_indicate_disconnect23a(adapter);
1462		free_scanqueue(pmlmepriv);/*  */
1463
1464		/* indicate disconnect for the case that join_timeout and
1465		   check_fwstate != FW_LINKED */
1466		rtw_cfg80211_indicate_disconnect(adapter);
1467	}
1468
1469	spin_unlock_bh(&pmlmepriv->lock);
1470
1471}
1472
1473/*
1474* rtw_scan_timeout_handler23a - Timeout/Failure handler for CMD SiteSurvey
1475* @data: pointer to _adapter structure
1476*/
1477void rtw_scan_timeout_handler23a(unsigned long data)
1478{
1479	struct rtw_adapter *adapter = (struct rtw_adapter *)data;
1480	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
1481
1482	DBG_8723A("%s(%s): fw_state =%x\n", __func__, adapter->pnetdev->name,
1483		  get_fwstate(pmlmepriv));
1484
1485	spin_lock_bh(&pmlmepriv->lock);
1486
1487	_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
1488
1489	spin_unlock_bh(&pmlmepriv->lock);
1490
1491	rtw_cfg80211_indicate_scan_done(wdev_to_priv(adapter->rtw_wdev), true);
1492}
1493
1494void rtw_dynamic_check_timer_handler(unsigned long data)
1495{
1496	struct rtw_adapter *adapter = (struct rtw_adapter *)data;
1497
1498	if (adapter->hw_init_completed == false)
1499		goto out;
1500
1501	if (adapter->bDriverStopped == true ||
1502	    adapter->bSurpriseRemoved == true)
1503		goto out;
1504
1505	if (adapter->net_closed == true)
1506		goto out;
1507
1508	rtw_dynamic_chk_wk_cmd23a(adapter);
1509
1510out:
1511	mod_timer(&adapter->mlmepriv.dynamic_chk_timer,
1512		  jiffies + msecs_to_jiffies(2000));
1513}
1514
1515inline bool rtw_is_scan_deny(struct rtw_adapter *adapter)
1516{
1517	struct mlme_priv *mlmepriv = &adapter->mlmepriv;
1518	return (atomic_read(&mlmepriv->set_scan_deny) != 0) ? true : false;
1519}
1520
1521void rtw_clear_scan_deny(struct rtw_adapter *adapter)
1522{
1523	struct mlme_priv *mlmepriv = &adapter->mlmepriv;
1524	atomic_set(&mlmepriv->set_scan_deny, 0);
1525}
1526
1527void rtw_set_scan_deny_timer_hdl(unsigned long data)
1528{
1529	struct rtw_adapter *adapter = (struct rtw_adapter *)data;
1530	rtw_clear_scan_deny(adapter);
1531}
1532
1533void rtw_set_scan_deny(struct rtw_adapter *adapter, u32 ms)
1534{
1535	struct mlme_priv *mlmepriv = &adapter->mlmepriv;
1536
1537	atomic_set(&mlmepriv->set_scan_deny, 1);
1538	mod_timer(&mlmepriv->set_scan_deny_timer,
1539		  jiffies + msecs_to_jiffies(ms));
1540}
1541
1542#if defined(IEEE80211_SCAN_RESULT_EXPIRE)
1543#define RTW_SCAN_RESULT_EXPIRE IEEE80211_SCAN_RESULT_EXPIRE/HZ*1000 -1000 /* 3000 -1000 */
1544#else
1545#define RTW_SCAN_RESULT_EXPIRE 2000
1546#endif
1547
1548/*
1549* Select a new join candidate from the original @param candidate and
1550*     @param competitor
1551* @return true: candidate is updated
1552* @return false: candidate is not updated
1553*/
1554static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv,
1555				    struct wlan_network **candidate,
1556				    struct wlan_network *competitor)
1557{
1558	int updated = false;
1559	struct rtw_adapter *adapter;
1560
1561	adapter = container_of(pmlmepriv, struct rtw_adapter, mlmepriv);
1562
1563	/* check bssid, if needed */
1564	if (pmlmepriv->assoc_by_bssid == true) {
1565		if (!ether_addr_equal(competitor->network.MacAddress,
1566				      pmlmepriv->assoc_bssid))
1567			goto exit;
1568	}
1569
1570	/* check ssid, if needed */
1571	if (pmlmepriv->assoc_ssid.ssid_len) {
1572		if (competitor->network.Ssid.ssid_len !=
1573		    pmlmepriv->assoc_ssid.ssid_len ||
1574		    memcmp(competitor->network.Ssid.ssid,
1575			   pmlmepriv->assoc_ssid.ssid,
1576			   pmlmepriv->assoc_ssid.ssid_len))
1577			goto exit;
1578	}
1579
1580	if (rtw_is_desired_network(adapter, competitor) == false)
1581		goto exit;
1582
1583	if (adapter->mlmepriv.to_roaming > 0) {
1584		unsigned int passed;
1585
1586		passed = jiffies_to_msecs(jiffies - competitor->last_scanned);
1587		if (passed >= RTW_SCAN_RESULT_EXPIRE ||
1588		    is_same_ess(&competitor->network,
1589				&pmlmepriv->cur_network.network) == false)
1590			goto exit;
1591	}
1592
1593	if (!*candidate ||
1594	    (*candidate)->network.Rssi<competitor->network.Rssi) {
1595		*candidate = competitor;
1596		updated = true;
1597	}
1598
1599	if (updated) {
1600		DBG_8723A("[by_bssid:%u][assoc_ssid:%s][to_roaming:%u] "
1601			  "new candidate: %s("MAC_FMT") rssi:%d\n",
1602			  pmlmepriv->assoc_by_bssid,
1603			  pmlmepriv->assoc_ssid.ssid,
1604			  adapter->mlmepriv.to_roaming,
1605			  (*candidate)->network.Ssid.ssid,
1606			  MAC_ARG((*candidate)->network.MacAddress),
1607			  (int)(*candidate)->network.Rssi);
1608	}
1609
1610exit:
1611	return updated;
1612}
1613
1614/*
1615Calling context:
1616The caller of the sub-routine will be in critical section...
1617
1618The caller must hold the following spinlock
1619
1620pmlmepriv->lock
1621
1622*/
1623
1624static int rtw_do_join(struct rtw_adapter *padapter)
1625{
1626	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1627	int ret;
1628
1629	pmlmepriv->cur_network.join_res = -2;
1630
1631	set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
1632
1633	pmlmepriv->to_join = true;
1634
1635	ret = rtw_select_and_join_from_scanned_queue23a(pmlmepriv);
1636	if (ret == _SUCCESS) {
1637		pmlmepriv->to_join = false;
1638	} else {
1639		if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
1640			/* switch to ADHOC_MASTER */
1641			ret = rtw_do_join_adhoc(padapter);
1642			if (ret != _SUCCESS)
1643				goto exit;
1644		} else {
1645			/*  can't associate ; reset under-linking */
1646			_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
1647
1648			ret = _FAIL;
1649			pmlmepriv->to_join = false;
1650		}
1651	}
1652
1653exit:
1654	return ret;
1655}
1656
1657static struct wlan_network *
1658rtw_select_candidate_from_queue(struct mlme_priv *pmlmepriv)
1659{
1660	struct wlan_network *pnetwork, *candidate = NULL;
1661	struct rtw_queue *queue = &pmlmepriv->scanned_queue;
1662	struct list_head *phead, *plist, *ptmp;
1663
1664	spin_lock_bh(&pmlmepriv->scanned_queue.lock);
1665	phead = get_list_head(queue);
1666
1667	list_for_each_safe(plist, ptmp, phead) {
1668		pnetwork = container_of(plist, struct wlan_network, list);
1669		if (!pnetwork) {
1670			RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1671				 ("%s: return _FAIL:(pnetwork == NULL)\n",
1672				  __func__));
1673			goto exit;
1674		}
1675
1676		rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork);
1677	}
1678
1679exit:
1680	spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1681	return candidate;
1682}
1683
1684
1685int rtw_do_join_adhoc(struct rtw_adapter *adapter)
1686{
1687	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
1688	struct wlan_bssid_ex *pdev_network;
1689	u8 *ibss;
1690	int ret;
1691
1692	pdev_network = &adapter->registrypriv.dev_network;
1693	ibss = adapter->registrypriv.dev_network.MacAddress;
1694
1695	_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
1696
1697	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1698		 ("switching to adhoc master\n"));
1699
1700	memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid,
1701	       sizeof(struct cfg80211_ssid));
1702
1703	rtw_update_registrypriv_dev_network23a(adapter);
1704	rtw_generate_random_ibss23a(ibss);
1705
1706	pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
1707
1708	ret = rtw_createbss_cmd23a(adapter);
1709	if (ret != _SUCCESS) {
1710		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1711			 ("Error =>rtw_createbss_cmd23a status FAIL\n"));
1712	} else  {
1713		pmlmepriv->to_join = false;
1714	}
1715
1716	return ret;
1717}
1718
1719int rtw_do_join_network(struct rtw_adapter *adapter,
1720			struct wlan_network *candidate)
1721{
1722	int ret;
1723
1724	/*  check for situation of  _FW_LINKED */
1725	if (check_fwstate(&adapter->mlmepriv, _FW_LINKED)) {
1726		DBG_8723A("%s: _FW_LINKED while ask_for_joinbss!\n", __func__);
1727
1728		rtw_disassoc_cmd23a(adapter, 0, true);
1729		rtw_indicate_disconnect23a(adapter);
1730		rtw_free_assoc_resources23a(adapter, 0);
1731	}
1732	set_fwstate(&adapter->mlmepriv, _FW_UNDER_LINKING);
1733
1734	ret = rtw_joinbss_cmd23a(adapter, candidate);
1735
1736	if (ret == _SUCCESS)
1737		mod_timer(&adapter->mlmepriv.assoc_timer,
1738			  jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT));
1739
1740	return ret;
1741}
1742
1743int rtw_select_and_join_from_scanned_queue23a(struct mlme_priv *pmlmepriv)
1744{
1745	struct rtw_adapter *adapter;
1746	struct wlan_network *candidate = NULL;
1747	int ret;
1748
1749	adapter = pmlmepriv->nic_hdl;
1750
1751	candidate = rtw_select_candidate_from_queue(pmlmepriv);
1752	if (!candidate) {
1753		DBG_8723A("%s: return _FAIL(candidate == NULL)\n", __func__);
1754		ret = _FAIL;
1755		goto exit;
1756	} else {
1757		DBG_8723A("%s: candidate: %s("MAC_FMT", ch:%u)\n", __func__,
1758			  candidate->network.Ssid.ssid,
1759			  MAC_ARG(candidate->network.MacAddress),
1760			  candidate->network.DSConfig);
1761	}
1762
1763	ret = rtw_do_join_network(adapter, candidate);
1764
1765exit:
1766	return ret;
1767}
1768
1769int rtw_set_auth23a(struct rtw_adapter * adapter,
1770		    struct security_priv *psecuritypriv)
1771{
1772	struct cmd_obj *pcmd;
1773	struct setauth_parm *psetauthparm;
1774	struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
1775	int res = _SUCCESS;
1776
1777	pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
1778	if (!pcmd) {
1779		res = _FAIL;  /* try again */
1780		goto exit;
1781	}
1782
1783	psetauthparm = kzalloc(sizeof(struct setauth_parm), GFP_KERNEL);
1784	if (!psetauthparm) {
1785		kfree(pcmd);
1786		res = _FAIL;
1787		goto exit;
1788	}
1789
1790	psetauthparm->mode = (unsigned char)psecuritypriv->dot11AuthAlgrthm;
1791
1792	pcmd->cmdcode = _SetAuth_CMD_;
1793	pcmd->parmbuf = (unsigned char *)psetauthparm;
1794	pcmd->cmdsz =  (sizeof(struct setauth_parm));
1795	pcmd->rsp = NULL;
1796	pcmd->rspsz = 0;
1797
1798	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1799		 ("after enqueue set_auth_cmd, auth_mode=%x\n",
1800		  psecuritypriv->dot11AuthAlgrthm));
1801
1802	res = rtw_enqueue_cmd23a(pcmdpriv, pcmd);
1803
1804exit:
1805
1806	return res;
1807}
1808
1809int rtw_set_key23a(struct rtw_adapter *adapter,
1810		   struct security_priv *psecuritypriv, int keyid, u8 set_tx)
1811{
1812	u8 keylen;
1813	struct cmd_obj *pcmd;
1814	struct setkey_parm *psetkeyparm;
1815	struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
1816	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
1817	int res = _SUCCESS;
1818
1819	if (keyid >= 4) {
1820		res = _FAIL;
1821		goto exit;
1822	}
1823
1824	pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
1825	if (!pcmd) {
1826		res = _FAIL;  /* try again */
1827		goto exit;
1828	}
1829	psetkeyparm = kzalloc(sizeof(struct setkey_parm), GFP_KERNEL);
1830	if (!psetkeyparm) {
1831		kfree(pcmd);
1832		res = _FAIL;
1833		goto exit;
1834	}
1835
1836	if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
1837		psetkeyparm->algorithm = (unsigned char)
1838			psecuritypriv->dot118021XGrpPrivacy;
1839		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1840			 ("\n rtw_set_key23a: psetkeyparm->algorithm = "
1841			  "(unsigned char)psecuritypriv->dot118021XGrpPrivacy "
1842			  "=%d\n", psetkeyparm->algorithm));
1843	} else {
1844		psetkeyparm->algorithm = (u8)psecuritypriv->dot11PrivacyAlgrthm;
1845		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1846			 ("\n rtw_set_key23a: psetkeyparm->algorithm = (u8)"
1847			  "psecuritypriv->dot11PrivacyAlgrthm =%d\n",
1848			  psetkeyparm->algorithm));
1849	}
1850	psetkeyparm->keyid = keyid;/* 0~3 */
1851	psetkeyparm->set_tx = set_tx;
1852	if (is_wep_enc(psetkeyparm->algorithm))
1853		pmlmepriv->key_mask |= BIT(psetkeyparm->keyid);
1854
1855	DBG_8723A("==> rtw_set_key23a algorithm(%x), keyid(%x), key_mask(%x)\n",
1856		  psetkeyparm->algorithm, psetkeyparm->keyid,
1857		  pmlmepriv->key_mask);
1858	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1859		 ("\n rtw_set_key23a: psetkeyparm->algorithm =%d psetkeyparm->"
1860		  "keyid = (u8)keyid =%d\n", psetkeyparm->algorithm, keyid));
1861
1862	switch (psetkeyparm->algorithm) {
1863	case WLAN_CIPHER_SUITE_WEP40:
1864		keylen = 5;
1865		memcpy(&psetkeyparm->key[0],
1866		       &psecuritypriv->wep_key[keyid].key, keylen);
1867		break;
1868	case WLAN_CIPHER_SUITE_WEP104:
1869		keylen = 13;
1870		memcpy(&psetkeyparm->key[0],
1871		       &psecuritypriv->wep_key[keyid].key, keylen);
1872		break;
1873	case WLAN_CIPHER_SUITE_TKIP:
1874		keylen = 16;
1875		memcpy(&psetkeyparm->key,
1876		       &psecuritypriv->dot118021XGrpKey[keyid], keylen);
1877		psetkeyparm->grpkey = 1;
1878		break;
1879	case WLAN_CIPHER_SUITE_CCMP:
1880		keylen = 16;
1881		memcpy(&psetkeyparm->key,
1882		       &psecuritypriv->dot118021XGrpKey[keyid], keylen);
1883		psetkeyparm->grpkey = 1;
1884		break;
1885	default:
1886		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
1887			 ("\n rtw_set_key23a:psecuritypriv->dot11PrivacyAlgrthm"
1888			  " = %x (must be 1 or 2 or 4 or 5)\n",
1889			  psecuritypriv->dot11PrivacyAlgrthm));
1890		res = _FAIL;
1891		kfree(pcmd);
1892		kfree(psetkeyparm);
1893		goto exit;
1894	}
1895
1896	pcmd->cmdcode = _SetKey_CMD_;
1897	pcmd->parmbuf = (u8 *)psetkeyparm;
1898	pcmd->cmdsz =  (sizeof(struct setkey_parm));
1899	pcmd->rsp = NULL;
1900	pcmd->rspsz = 0;
1901
1902	/* sema_init(&pcmd->cmd_sem, 0); */
1903
1904	res = rtw_enqueue_cmd23a(pcmdpriv, pcmd);
1905
1906exit:
1907
1908	return res;
1909}
1910
1911/* adjust IEs for rtw_joinbss_cmd23a in WMM */
1912int rtw_restruct_wmm_ie23a(struct rtw_adapter *adapter, u8 *in_ie,
1913			   u8 *out_ie, uint in_len, uint initial_out_len)
1914{
1915	int ielength;
1916	const u8 *p;
1917
1918	ielength = initial_out_len;
1919
1920	p = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
1921				    WLAN_OUI_TYPE_MICROSOFT_WMM,
1922				    in_ie, in_len);
1923
1924	if (p && p[1]) {
1925		memcpy(out_ie + initial_out_len, p, 9);
1926
1927		out_ie[initial_out_len + 1] = 7;
1928		out_ie[initial_out_len + 6] = 0;
1929		out_ie[initial_out_len + 8] = 0;
1930
1931		ielength += 9;
1932	}
1933
1934	return ielength;
1935}
1936
1937/*  */
1938/*  Ported from 8185: IsInPreAuthKeyList().
1939    (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.) */
1940/*  Added by Annie, 2006-05-07. */
1941/*  */
1942/*  Search by BSSID, */
1943/*  Return Value: */
1944/*		-1	:if there is no pre-auth key in the  table */
1945/*		>= 0	:if there is pre-auth key, and   return the entry id */
1946/*  */
1947/*  */
1948
1949static int SecIsInPMKIDList(struct rtw_adapter *Adapter, u8 *bssid)
1950{
1951	struct security_priv *psecuritypriv = &Adapter->securitypriv;
1952	int i = 0;
1953
1954	do {
1955		if (psecuritypriv->PMKIDList[i].bUsed &&
1956                    ether_addr_equal(psecuritypriv->PMKIDList[i].Bssid, bssid)) {
1957			break;
1958		} else {
1959			i++;
1960			/* continue; */
1961		}
1962	} while (i < NUM_PMKID_CACHE);
1963
1964	if (i == NUM_PMKID_CACHE)
1965		i = -1;/*  Could not find. */
1966	else {
1967		/*  There is one Pre-Authentication Key for
1968		    the specific BSSID. */
1969	}
1970
1971	return i;
1972}
1973
1974/*  */
1975/*  Check the RSN IE length */
1976/*  If the RSN IE length <= 20, the RSN IE didn't include
1977    the PMKID information */
1978/*  0-11th element in the array are the fixed IE */
1979/*  12th element in the array is the IE */
1980/*  13th element in the array is the IE length */
1981/*  */
1982
1983static int rtw_append_pmkid(struct rtw_adapter *Adapter, int iEntry,
1984			    u8 *ie, uint ie_len)
1985{
1986	struct security_priv *psecuritypriv = &Adapter->securitypriv;
1987
1988	if (ie[1] <= 20) {
1989		/*  The RSN IE didn't include the PMK ID,
1990		    append the PMK information */
1991			ie[ie_len] = 1;
1992			ie_len++;
1993			ie[ie_len] = 0;	/* PMKID count = 0x0100 */
1994			ie_len++;
1995			memcpy(&ie[ie_len],
1996			       &psecuritypriv->PMKIDList[iEntry].PMKID, 16);
1997
1998			ie_len += 16;
1999			ie[1] += 18;/* PMKID length = 2+16 */
2000	}
2001	return ie_len;
2002}
2003
2004int rtw_restruct_sec_ie23a(struct rtw_adapter *adapter, u8 *in_ie, u8 *out_ie,
2005			   uint in_len)
2006{
2007	u8 authmode;
2008	uint ielength;
2009	int iEntry;
2010	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
2011	struct security_priv *psecuritypriv = &adapter->securitypriv;
2012	uint ndisauthmode = psecuritypriv->ndisauthtype;
2013	uint ndissecuritytype = psecuritypriv->ndisencryptstatus;
2014
2015	RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
2016		 ("+rtw_restruct_sec_ie23a: ndisauthmode=%d "
2017		  "ndissecuritytype=%d\n", ndisauthmode, ndissecuritytype));
2018
2019	ielength = 0;
2020	if (ndisauthmode == Ndis802_11AuthModeWPA ||
2021	    ndisauthmode == Ndis802_11AuthModeWPAPSK)
2022		authmode = WLAN_EID_VENDOR_SPECIFIC;
2023	if (ndisauthmode == Ndis802_11AuthModeWPA2 ||
2024	    ndisauthmode == Ndis802_11AuthModeWPA2PSK)
2025		authmode = WLAN_EID_RSN;
2026
2027	if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
2028		memcpy(out_ie + ielength, psecuritypriv->wps_ie,
2029		       psecuritypriv->wps_ie_len);
2030
2031		ielength += psecuritypriv->wps_ie_len;
2032	} else if (authmode == WLAN_EID_VENDOR_SPECIFIC ||
2033		   authmode == WLAN_EID_RSN) {
2034		/* copy RSN or SSN */
2035		memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0],
2036		       psecuritypriv->supplicant_ie[1] + 2);
2037		ielength += psecuritypriv->supplicant_ie[1] + 2;
2038	}
2039
2040	iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid);
2041	if (iEntry < 0)
2042		return ielength;
2043	else {
2044		if (authmode == WLAN_EID_RSN)
2045			ielength = rtw_append_pmkid(adapter, iEntry,
2046						    out_ie, ielength);
2047	}
2048
2049	return ielength;
2050}
2051
2052void rtw_init_registrypriv_dev_network23a(struct rtw_adapter *adapter)
2053{
2054	struct registry_priv *pregistrypriv = &adapter->registrypriv;
2055	struct eeprom_priv *peepriv = &adapter->eeprompriv;
2056	struct wlan_bssid_ex    *pdev_network = &pregistrypriv->dev_network;
2057	u8 *myhwaddr = myid(peepriv);
2058
2059	ether_addr_copy(pdev_network->MacAddress, myhwaddr);
2060
2061	memcpy(&pdev_network->Ssid, &pregistrypriv->ssid,
2062	       sizeof(struct cfg80211_ssid));
2063
2064	pdev_network->beacon_interval = 100;
2065}
2066
2067void rtw_update_registrypriv_dev_network23a(struct rtw_adapter *adapter)
2068{
2069	int sz = 0;
2070	struct registry_priv *pregistrypriv = &adapter->registrypriv;
2071	struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
2072	struct security_priv *psecuritypriv = &adapter->securitypriv;
2073	struct wlan_network *cur_network = &adapter->mlmepriv.cur_network;
2074	/* struct	xmit_priv	*pxmitpriv = &adapter->xmitpriv; */
2075
2076	pdev_network->Privacy =
2077		(psecuritypriv->dot11PrivacyAlgrthm > 0 ? 1 : 0);
2078
2079	pdev_network->Rssi = 0;
2080
2081	pdev_network->DSConfig = pregistrypriv->channel;
2082	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
2083		 ("pregistrypriv->channel =%d, pdev_network->DSConfig = 0x%x\n",
2084		  pregistrypriv->channel, pdev_network->DSConfig));
2085
2086	if (cur_network->network.ifmode == NL80211_IFTYPE_ADHOC)
2087		pdev_network->ATIMWindow = 0;
2088
2089	pdev_network->ifmode = cur_network->network.ifmode;
2090
2091	/*  1. Supported rates */
2092	/*  2. IE */
2093
2094	sz = rtw_generate_ie23a(pregistrypriv);
2095
2096	pdev_network->IELength = sz;
2097
2098	pdev_network->Length =
2099		get_wlan_bssid_ex_sz(pdev_network);
2100
2101	/* notes: translate IELength & Length after assign the
2102	   Length to cmdsz in createbss_cmd(); */
2103	/* pdev_network->IELength = cpu_to_le32(sz); */
2104}
2105
2106/* the function is at passive_level */
2107void rtw_joinbss_reset23a(struct rtw_adapter *padapter)
2108{
2109	u8 threshold;
2110	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
2111	struct ht_priv *phtpriv = &pmlmepriv->htpriv;
2112
2113	/* todo: if you want to do something io/reg/hw setting
2114	   before join_bss, please add code here */
2115
2116	pmlmepriv->num_FortyMHzIntolerant = 0;
2117
2118	pmlmepriv->num_sta_no_ht = 0;
2119
2120	phtpriv->ampdu_enable = false;/* reset to disabled */
2121
2122	/*  TH = 1 => means that invalidate usb rx aggregation */
2123	/*  TH = 0 => means that validate usb rx aggregation, use init value. */
2124	if (phtpriv->ht_option) {
2125		if (padapter->registrypriv.wifi_spec == 1)
2126			threshold = 1;
2127		else
2128			threshold = 0;
2129	} else
2130		threshold = 1;
2131
2132	rtl8723a_set_rxdma_agg_pg_th(padapter, threshold);
2133}
2134
2135/* the function is >= passive_level */
2136bool rtw_restructure_ht_ie23a(struct rtw_adapter *padapter, u8 *in_ie,
2137			      u8 *out_ie, uint in_len, uint *pout_len)
2138{
2139	u32 out_len;
2140	int max_rx_ampdu_factor;
2141	unsigned char *pframe;
2142	const u8 *p;
2143	struct ieee80211_ht_cap ht_capie;
2144	u8 WMM_IE[7] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00};
2145	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
2146	struct ht_priv *phtpriv = &pmlmepriv->htpriv;
2147
2148	phtpriv->ht_option = false;
2149
2150	p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, in_ie, in_len);
2151
2152	if (p && p[1] > 0) {
2153		u32 rx_packet_offset, max_recvbuf_sz;
2154		if (pmlmepriv->qos_option == 0) {
2155			out_len = *pout_len;
2156			pframe = rtw_set_ie23a(out_ie + out_len,
2157					       WLAN_EID_VENDOR_SPECIFIC,
2158					       sizeof(WMM_IE), WMM_IE,
2159					       pout_len);
2160
2161			pmlmepriv->qos_option = 1;
2162		}
2163
2164		out_len = *pout_len;
2165
2166		memset(&ht_capie, 0, sizeof(struct ieee80211_ht_cap));
2167
2168		ht_capie.cap_info = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
2169			IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
2170			IEEE80211_HT_CAP_TX_STBC | IEEE80211_HT_CAP_DSSSCCK40;
2171
2172		GetHalDefVar8192CUsb(padapter, HAL_DEF_RX_PACKET_OFFSET,
2173				     &rx_packet_offset);
2174		GetHalDefVar8192CUsb(padapter, HAL_DEF_MAX_RECVBUF_SZ,
2175				     &max_recvbuf_sz);
2176
2177		GetHalDefVar8192CUsb(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR,
2178				     &max_rx_ampdu_factor);
2179		ht_capie.ampdu_params_info = max_rx_ampdu_factor & 0x03;
2180
2181		if (padapter->securitypriv.dot11PrivacyAlgrthm ==
2182		    WLAN_CIPHER_SUITE_CCMP)
2183			ht_capie.ampdu_params_info |=
2184				(IEEE80211_HT_AMPDU_PARM_DENSITY& (0x07 << 2));
2185		else
2186			ht_capie.ampdu_params_info |=
2187				(IEEE80211_HT_AMPDU_PARM_DENSITY & 0x00);
2188
2189		pframe = rtw_set_ie23a(out_ie + out_len, WLAN_EID_HT_CAPABILITY,
2190				    sizeof(struct ieee80211_ht_cap),
2191				    (unsigned char *)&ht_capie, pout_len);
2192
2193		phtpriv->ht_option = true;
2194
2195		p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, in_ie, in_len);
2196		if (p && (p[1] == sizeof(struct ieee80211_ht_operation))) {
2197			out_len = *pout_len;
2198			pframe = rtw_set_ie23a(out_ie + out_len,
2199					       WLAN_EID_HT_OPERATION,
2200					       p[1], p + 2 , pout_len);
2201		}
2202	}
2203
2204	return phtpriv->ht_option;
2205}
2206
2207/* the function is > passive_level (in critical_section) */
2208void rtw_update_ht_cap23a(struct rtw_adapter *padapter, u8 *pie, uint ie_len)
2209{
2210	u8 max_ampdu_sz;
2211	const u8 *p;
2212	struct ieee80211_ht_cap *pht_capie;
2213	struct ieee80211_ht_operation *pht_addtinfo;
2214	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
2215	struct ht_priv *phtpriv = &pmlmepriv->htpriv;
2216	struct registry_priv *pregistrypriv = &padapter->registrypriv;
2217	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
2218	struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
2219
2220	if (!phtpriv->ht_option)
2221		return;
2222
2223	if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable))
2224		return;
2225
2226	DBG_8723A("+rtw_update_ht_cap23a()\n");
2227
2228	/* maybe needs check if ap supports rx ampdu. */
2229	if (!phtpriv->ampdu_enable && pregistrypriv->ampdu_enable == 1) {
2230		if (pregistrypriv->wifi_spec == 1)
2231			phtpriv->ampdu_enable = false;
2232		else
2233			phtpriv->ampdu_enable = true;
2234	} else if (pregistrypriv->ampdu_enable == 2)
2235		phtpriv->ampdu_enable = true;
2236
2237	/* check Max Rx A-MPDU Size */
2238	p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, pie, ie_len);
2239
2240	if (p && p[1] > 0) {
2241		pht_capie = (struct ieee80211_ht_cap *)(p + 2);
2242		max_ampdu_sz = pht_capie->ampdu_params_info &
2243			IEEE80211_HT_AMPDU_PARM_FACTOR;
2244		/*  max_ampdu_sz (kbytes); */
2245		max_ampdu_sz = 1 << (max_ampdu_sz + 3);
2246
2247		phtpriv->rx_ampdu_maxlen = max_ampdu_sz;
2248	}
2249
2250	p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, pie, ie_len);
2251	if (p && p[1] > 0) {
2252		pht_addtinfo = (struct ieee80211_ht_operation *)(p + 2);
2253		/* todo: */
2254	}
2255
2256	/* update cur_bwmode & cur_ch_offset */
2257	if (pregistrypriv->cbw40_enable &&
2258	    pmlmeinfo->ht_cap.cap_info &
2259	    cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
2260	    pmlmeinfo->HT_info.ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY) {
2261		int i;
2262		u8 rf_type;
2263
2264		rf_type = rtl8723a_get_rf_type(padapter);
2265
2266		/* update the MCS rates */
2267		for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
2268			if (rf_type == RF_1T1R || rf_type == RF_1T2R)
2269				pmlmeinfo->ht_cap.mcs.rx_mask[i] &=
2270					MCS_rate_1R23A[i];
2271			else
2272				pmlmeinfo->ht_cap.mcs.rx_mask[i] &=
2273					MCS_rate_2R23A[i];
2274		}
2275		/* switch to the 40M Hz mode according to the AP */
2276		pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40;
2277		switch (pmlmeinfo->HT_info.ht_param &
2278			IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
2279		case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
2280			pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
2281			break;
2282
2283		case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
2284			pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
2285			break;
2286
2287		default:
2288			pmlmeext->cur_ch_offset =
2289				HAL_PRIME_CHNL_OFFSET_DONT_CARE;
2290			break;
2291		}
2292	}
2293
2294	/*  */
2295	/*  Config SM Power Save setting */
2296	/*  */
2297	pmlmeinfo->SM_PS =
2298		(le16_to_cpu(pmlmeinfo->ht_cap.cap_info) &
2299		 IEEE80211_HT_CAP_SM_PS) >> IEEE80211_HT_CAP_SM_PS_SHIFT;
2300	if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC)
2301		DBG_8723A("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__);
2302
2303	/*  */
2304	/*  Config current HT Protection mode. */
2305	/*  */
2306	pmlmeinfo->HT_protection =
2307		le16_to_cpu(pmlmeinfo->HT_info.operation_mode) &
2308		IEEE80211_HT_OP_MODE_PROTECTION;
2309}
2310
2311void rtw_issue_addbareq_cmd23a(struct rtw_adapter *padapter,
2312			       struct xmit_frame *pxmitframe)
2313{
2314	u8 issued;
2315	int priority;
2316	struct sta_info *psta;
2317	struct ht_priv	*phtpriv;
2318	struct pkt_attrib *pattrib = &pxmitframe->attrib;
2319	s32 bmcst = is_multicast_ether_addr(pattrib->ra);
2320
2321	if (bmcst || padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod < 100)
2322		return;
2323
2324	priority = pattrib->priority;
2325
2326	if (pattrib->psta)
2327		psta = pattrib->psta;
2328	else {
2329		DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
2330		psta = rtw_get_stainfo23a(&padapter->stapriv, pattrib->ra);
2331	}
2332
2333	if (!psta) {
2334		DBG_8723A("%s, psta == NUL\n", __func__);
2335		return;
2336	}
2337
2338	if (!(psta->state &_FW_LINKED)) {
2339		DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n",
2340			  __func__, psta->state);
2341		return;
2342	}
2343
2344	phtpriv = &psta->htpriv;
2345
2346	if (phtpriv->ht_option && phtpriv->ampdu_enable) {
2347		issued = (phtpriv->agg_enable_bitmap>>priority)&0x1;
2348		issued |= (phtpriv->candidate_tid_bitmap>>priority)&0x1;
2349
2350		if (issued == 0) {
2351			DBG_8723A("rtw_issue_addbareq_cmd23a, p =%d\n",
2352				  priority);
2353			psta->htpriv.candidate_tid_bitmap |= BIT(priority);
2354			rtw_addbareq_cmd23a(padapter, (u8) priority,
2355					    pattrib->ra);
2356		}
2357	}
2358}
2359
2360int rtw_linked_check(struct rtw_adapter *padapter)
2361{
2362	if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) ||
2363	    check_fwstate(&padapter->mlmepriv,
2364			  WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) {
2365		if (padapter->stapriv.asoc_sta_count > 2)
2366			return true;
2367	} else {	/* Station mode */
2368		if (check_fwstate(&padapter->mlmepriv, _FW_LINKED))
2369			return true;
2370	}
2371	return false;
2372}
2373