xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/wl_iapsta.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun 
2*4882a593Smuzhiyun #ifdef WL_EXT_IAPSTA
3*4882a593Smuzhiyun #include <net/rtnetlink.h>
4*4882a593Smuzhiyun #include <bcmendian.h>
5*4882a593Smuzhiyun #include <dhd_linux.h>
6*4882a593Smuzhiyun #include <wlioctl_utils.h>
7*4882a593Smuzhiyun #include <wl_android.h>
8*4882a593Smuzhiyun #include <dhd_config.h>
9*4882a593Smuzhiyun #ifdef WL_CFG80211
10*4882a593Smuzhiyun #include <wl_cfg80211.h>
11*4882a593Smuzhiyun #include <wl_cfgscan.h>
12*4882a593Smuzhiyun #endif /* WL_CFG80211 */
13*4882a593Smuzhiyun #ifdef WL_ESCAN
14*4882a593Smuzhiyun #include <wl_escan.h>
15*4882a593Smuzhiyun #endif /* WL_ESCAN */
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #ifdef BTC_WAR
18*4882a593Smuzhiyun /* btc_war:
19*4882a593Smuzhiyun  * -1(don't apply btc)
20*4882a593Smuzhiyun  *   0(disable btc war): btc_mode=1; txchain=3; rxchain=3
21*4882a593Smuzhiyun  *   1(enable btc war): txchain=2; rxchain=2; btc_mode=5
22*4882a593Smuzhiyun  */
23*4882a593Smuzhiyun int btc_war = -1;
24*4882a593Smuzhiyun module_param(btc_war, int, 0644);
25*4882a593Smuzhiyun #endif /* BTC_WAR */
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #define IAPSTA_ERROR(name, arg1, args...) \
28*4882a593Smuzhiyun 	do { \
29*4882a593Smuzhiyun 		if (android_msg_level & ANDROID_ERROR_LEVEL) { \
30*4882a593Smuzhiyun 			printf("[%s] IAPSTA-ERROR) %s : " arg1, name, __func__, ## args); \
31*4882a593Smuzhiyun 		} \
32*4882a593Smuzhiyun 	} while (0)
33*4882a593Smuzhiyun #define IAPSTA_TRACE(name, arg1, args...) \
34*4882a593Smuzhiyun 	do { \
35*4882a593Smuzhiyun 		if (android_msg_level & ANDROID_TRACE_LEVEL) { \
36*4882a593Smuzhiyun 			printf("[%s] IAPSTA-TRACE) %s : " arg1, name, __func__, ## args); \
37*4882a593Smuzhiyun 		} \
38*4882a593Smuzhiyun 	} while (0)
39*4882a593Smuzhiyun #define IAPSTA_INFO(name, arg1, args...) \
40*4882a593Smuzhiyun 	do { \
41*4882a593Smuzhiyun 		if (android_msg_level & ANDROID_INFO_LEVEL) { \
42*4882a593Smuzhiyun 			printf("[%s] IAPSTA-INFO) %s : " arg1, name, __func__, ## args); \
43*4882a593Smuzhiyun 		} \
44*4882a593Smuzhiyun 	} while (0)
45*4882a593Smuzhiyun #define IAPSTA_DBG(name, arg1, args...) \
46*4882a593Smuzhiyun 	do { \
47*4882a593Smuzhiyun 		if (android_msg_level & ANDROID_DBG_LEVEL) { \
48*4882a593Smuzhiyun 			printf("[%s] IAPSTA-DBG) %s : " arg1, name, __func__, ## args); \
49*4882a593Smuzhiyun 		} \
50*4882a593Smuzhiyun 	} while (0)
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #ifdef PROP_TXSTATUS
53*4882a593Smuzhiyun #include <dhd_wlfc.h>
54*4882a593Smuzhiyun #ifdef PROP_TXSTATUS_VSDB
55*4882a593Smuzhiyun extern int disable_proptx;
56*4882a593Smuzhiyun #endif /* PROP_TXSTATUS_VSDB */
57*4882a593Smuzhiyun #endif /* PROP_TXSTATUS */
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #ifndef WL_CFG80211
60*4882a593Smuzhiyun #define htod32(i) i
61*4882a593Smuzhiyun #define htod16(i) i
62*4882a593Smuzhiyun #define dtoh32(i) i
63*4882a593Smuzhiyun #define dtoh16(i) i
64*4882a593Smuzhiyun #define IEEE80211_BAND_2GHZ 0
65*4882a593Smuzhiyun #define IEEE80211_BAND_5GHZ 1
66*4882a593Smuzhiyun #endif /* WL_CFG80211 */
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #define CSA_FW_BIT		(1<<0)
69*4882a593Smuzhiyun #define CSA_DRV_BIT		(1<<1)
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun #define WL_DUMP_BUF_LEN (127 * 1024)
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun #define MAX_AP_LINK_WAIT_TIME   3000
74*4882a593Smuzhiyun #define MAX_STA_LINK_WAIT_TIME   15000
75*4882a593Smuzhiyun #define STA_LINKDOWN_TIMEOUT	10000
76*4882a593Smuzhiyun #define STA_CONNECT_TIMEOUT	10500
77*4882a593Smuzhiyun #define STA_CONNECT_FULL_CHAN_TIMEOUT	3000
78*4882a593Smuzhiyun #define STA_CONNECT_RETRY_TIMEOUT	600
79*4882a593Smuzhiyun #define STA_RECONNECT_RETRY_TIMEOUT	300
80*4882a593Smuzhiyun #define STA_DISCONNECT_RECONNECT_TIMEOUT	30000
81*4882a593Smuzhiyun #define STA_DISCONNECT_RECONNECT_MAX	3
82*4882a593Smuzhiyun #define STA_4WAY_TIMEOUT	1000
83*4882a593Smuzhiyun #ifdef EAPOL_RESEND_M4
84*4882a593Smuzhiyun #define STA_KEY_INSTALL_INTERVAL	50
85*4882a593Smuzhiyun #define STA_KEY_INSTALL_MAX	(STA_4WAY_TIMEOUT/STA_KEY_INSTALL_INTERVAL)
86*4882a593Smuzhiyun #else
87*4882a593Smuzhiyun #define STA_KEY_INSTALL_INTERVAL	50
88*4882a593Smuzhiyun #define STA_KEY_INSTALL_MAX	3
89*4882a593Smuzhiyun #endif
90*4882a593Smuzhiyun #define STA_EAPOL_TIMEOUT	100
91*4882a593Smuzhiyun #define STA_EMPTY_SCAN_MAX	6
92*4882a593Smuzhiyun #define AP_RESTART_TIMEOUT	1000
93*4882a593Smuzhiyun #define AP_TXBCNFRM_TIMEOUT	10000
94*4882a593Smuzhiyun #ifdef RXF0OVFL_REINIT_WAR
95*4882a593Smuzhiyun #define RXF0OVFL_POLLING_TIMEOUT	1000
96*4882a593Smuzhiyun #define RXF0OVFL_THRESHOLD	100
97*4882a593Smuzhiyun #endif /* RXF0OVFL_REINIT_WAR */
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun #define MAX_DWDS_IF_NUM 4
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun enum wl_if_list {
102*4882a593Smuzhiyun 	IF_PIF,
103*4882a593Smuzhiyun 	IF_VIF,
104*4882a593Smuzhiyun 	IF_VIF2,
105*4882a593Smuzhiyun 	MAX_IF_NUM
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun typedef enum WL_PRIO {
109*4882a593Smuzhiyun 	PRIO_AP,
110*4882a593Smuzhiyun 	PRIO_MESH,
111*4882a593Smuzhiyun 	PRIO_P2P,
112*4882a593Smuzhiyun 	PRIO_STA
113*4882a593Smuzhiyun } wl_prio_t;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun typedef enum APSTAMODE {
116*4882a593Smuzhiyun 	IUNKNOWN_MODE = 0,
117*4882a593Smuzhiyun 	ISTAONLY_MODE = 1,
118*4882a593Smuzhiyun 	IAPONLY_MODE = 2,
119*4882a593Smuzhiyun 	ISTAAP_MODE = 3,
120*4882a593Smuzhiyun 	ISTAGO_MODE = 4,
121*4882a593Smuzhiyun 	ISTASTA_MODE = 5,
122*4882a593Smuzhiyun 	IDUALAP_MODE = 6,
123*4882a593Smuzhiyun 	ISTAAPAP_MODE = 7,
124*4882a593Smuzhiyun 	IMESHONLY_MODE = 8,
125*4882a593Smuzhiyun 	ISTAMESH_MODE = 9,
126*4882a593Smuzhiyun 	IMESHAP_MODE = 10,
127*4882a593Smuzhiyun 	ISTAAPMESH_MODE = 11,
128*4882a593Smuzhiyun 	IMESHAPAP_MODE = 12
129*4882a593Smuzhiyun } apstamode_t;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun typedef enum BGNMODE {
132*4882a593Smuzhiyun 	IEEE80211B = 1,
133*4882a593Smuzhiyun 	IEEE80211G,
134*4882a593Smuzhiyun 	IEEE80211BG,
135*4882a593Smuzhiyun 	IEEE80211BGN,
136*4882a593Smuzhiyun 	IEEE80211BGNAC
137*4882a593Smuzhiyun } bgnmode_t;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun typedef enum AUTHMODE {
140*4882a593Smuzhiyun 	AUTH_OPEN,
141*4882a593Smuzhiyun 	AUTH_SHARED,
142*4882a593Smuzhiyun 	AUTH_WPAPSK,
143*4882a593Smuzhiyun 	AUTH_WPA2PSK,
144*4882a593Smuzhiyun 	AUTH_WPAWPA2PSK,
145*4882a593Smuzhiyun 	AUTH_SAE
146*4882a593Smuzhiyun } authmode_t;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun typedef enum ENCMODE {
149*4882a593Smuzhiyun 	ENC_NONE,
150*4882a593Smuzhiyun 	ENC_WEP,
151*4882a593Smuzhiyun 	ENC_TKIP,
152*4882a593Smuzhiyun 	ENC_AES,
153*4882a593Smuzhiyun 	ENC_TKIPAES
154*4882a593Smuzhiyun } encmode_t;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun #ifdef STA_MGMT
157*4882a593Smuzhiyun typedef struct wl_sta_info {
158*4882a593Smuzhiyun 	int ifidx;
159*4882a593Smuzhiyun 	struct ether_addr bssid;
160*4882a593Smuzhiyun 	struct list_head list;
161*4882a593Smuzhiyun } wl_sta_info_t;
162*4882a593Smuzhiyun #endif /* STA_MGMT */
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun #ifdef TPUT_MONITOR
165*4882a593Smuzhiyun typedef struct wl_tput_info {
166*4882a593Smuzhiyun 	unsigned long last_tx;
167*4882a593Smuzhiyun 	unsigned long last_rx;
168*4882a593Smuzhiyun 	struct osl_timespec tput_ts;
169*4882a593Smuzhiyun 	int32 tput_tx;
170*4882a593Smuzhiyun 	int32 tput_rx;
171*4882a593Smuzhiyun 	int32 tput_tx_kb;
172*4882a593Smuzhiyun 	int32 tput_rx_kb;
173*4882a593Smuzhiyun } wl_tput_info_t;
174*4882a593Smuzhiyun #endif /* TPUT_MONITOR */
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun #ifdef WLDWDS
177*4882a593Smuzhiyun typedef struct wl_dwds_info {
178*4882a593Smuzhiyun 	struct net_device *dev;
179*4882a593Smuzhiyun 	int ifidx;
180*4882a593Smuzhiyun 	uint8 bssidx;
181*4882a593Smuzhiyun #ifdef TPUT_MONITOR
182*4882a593Smuzhiyun 	struct wl_tput_info tput_info;
183*4882a593Smuzhiyun #endif /* TPUT_MONITOR */
184*4882a593Smuzhiyun } wl_dwds_info_t;
185*4882a593Smuzhiyun #endif /* WLDWDS */
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun typedef struct wl_if_info {
188*4882a593Smuzhiyun 	struct net_device *dev;
189*4882a593Smuzhiyun 	ifmode_t ifmode;
190*4882a593Smuzhiyun 	unsigned long status;
191*4882a593Smuzhiyun 	char prefix;
192*4882a593Smuzhiyun 	wl_prio_t prio;
193*4882a593Smuzhiyun 	int ifidx;
194*4882a593Smuzhiyun 	uint8 bssidx;
195*4882a593Smuzhiyun 	char ifname[IFNAMSIZ+1];
196*4882a593Smuzhiyun 	char ssid[DOT11_MAX_SSID_LEN];
197*4882a593Smuzhiyun 	struct ether_addr bssid;
198*4882a593Smuzhiyun 	bgnmode_t bgnmode;
199*4882a593Smuzhiyun 	int hidden;
200*4882a593Smuzhiyun 	int maxassoc;
201*4882a593Smuzhiyun 	struct wl_chan_info chan_info;
202*4882a593Smuzhiyun 	authmode_t amode;
203*4882a593Smuzhiyun 	encmode_t emode;
204*4882a593Smuzhiyun 	bool vsdb;
205*4882a593Smuzhiyun 	char key[100];
206*4882a593Smuzhiyun #ifdef WL_ESCAN
207*4882a593Smuzhiyun #if (defined(WLMESH) || defined(ACS_MONITOR))
208*4882a593Smuzhiyun 	struct wl_escan_info *escan;
209*4882a593Smuzhiyun #ifdef WLMESH
210*4882a593Smuzhiyun 	timer_list_compat_t delay_scan;
211*4882a593Smuzhiyun #endif /* WLMESH */
212*4882a593Smuzhiyun #ifdef ACS_MONITOR
213*4882a593Smuzhiyun 	timer_list_compat_t acs_timer;
214*4882a593Smuzhiyun #endif /* ACS_MONITOR */
215*4882a593Smuzhiyun #endif /* WLMESH || ACS_MONITOR */
216*4882a593Smuzhiyun #endif /* WL_ESCAN */
217*4882a593Smuzhiyun 	struct delayed_work pm_enable_work;
218*4882a593Smuzhiyun 	struct mutex pm_sync;
219*4882a593Smuzhiyun #ifdef PROPTX_MAXCOUNT
220*4882a593Smuzhiyun 	int transit_maxcount;
221*4882a593Smuzhiyun #endif /* PROPTX_MAXCOUNT */
222*4882a593Smuzhiyun 	uint conn_state;
223*4882a593Smuzhiyun 	uint16 prev_channel;
224*4882a593Smuzhiyun 	uint16 post_channel;
225*4882a593Smuzhiyun 	struct osl_timespec sta_disc_ts;
226*4882a593Smuzhiyun 	struct osl_timespec sta_conn_ts;
227*4882a593Smuzhiyun 	bool ap_recon_sta;
228*4882a593Smuzhiyun 	wait_queue_head_t ap_recon_sta_event;
229*4882a593Smuzhiyun 	struct ether_addr ap_disc_sta_bssid;
230*4882a593Smuzhiyun 	struct osl_timespec ap_disc_sta_ts;
231*4882a593Smuzhiyun #ifdef TPUT_MONITOR
232*4882a593Smuzhiyun 	struct wl_tput_info tput_info;
233*4882a593Smuzhiyun #endif /* TPUT_MONITOR */
234*4882a593Smuzhiyun 	timer_list_compat_t connect_timer;
235*4882a593Smuzhiyun #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
236*4882a593Smuzhiyun 	wlcfg_assoc_info_t assoc_info;
237*4882a593Smuzhiyun 	timer_list_compat_t reconnect_timer;
238*4882a593Smuzhiyun #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
239*4882a593Smuzhiyun #ifdef EAPOL_RESEND
240*4882a593Smuzhiyun 	void *pend_eapol_pkt;
241*4882a593Smuzhiyun 	timer_list_compat_t eapol_timer;
242*4882a593Smuzhiyun #ifdef EAPOL_DYNAMATIC_RESEND
243*4882a593Smuzhiyun 	struct osl_timespec eapol_tx_ts;
244*4882a593Smuzhiyun 	bool eapol_retry;
245*4882a593Smuzhiyun 	int eapol_cnt;
246*4882a593Smuzhiyun 	int eapol_avg_intvl;
247*4882a593Smuzhiyun 	int eapol_min_intvl;
248*4882a593Smuzhiyun 	int eapol_max_intvl;
249*4882a593Smuzhiyun 	int eapol_resend_intvl;
250*4882a593Smuzhiyun #endif /* EAPOL_DYNAMATIC_RESEND */
251*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
252*4882a593Smuzhiyun #ifdef KEY_INSTALL_CHECK
253*4882a593Smuzhiyun 	timer_list_compat_t key_install_timer;
254*4882a593Smuzhiyun 	int key_install_cnt;
255*4882a593Smuzhiyun #endif /* KEY_INSTALL_CHECK */
256*4882a593Smuzhiyun 	int empty_scan;
257*4882a593Smuzhiyun #ifdef RESTART_AP_WAR
258*4882a593Smuzhiyun 	timer_list_compat_t restart_ap_timer;
259*4882a593Smuzhiyun #endif /* RESTART_AP_WAR */
260*4882a593Smuzhiyun #ifdef RESET_AP_WAR
261*4882a593Smuzhiyun 	timer_list_compat_t reset_ap_timer;
262*4882a593Smuzhiyun 	uint32 txbcnfrm;
263*4882a593Smuzhiyun #endif /* RESET_AP_WAR */
264*4882a593Smuzhiyun #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
265*4882a593Smuzhiyun #ifdef WL_EXT_DISCONNECT_RECONNECT
266*4882a593Smuzhiyun 	struct osl_timespec sta_disc_conn_ts;
267*4882a593Smuzhiyun 	int sta_disc_recon_cnt;
268*4882a593Smuzhiyun #endif /* WL_EXT_DISCONNECT_RECONNECT */
269*4882a593Smuzhiyun #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
270*4882a593Smuzhiyun } wl_if_info_t;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun typedef struct wl_apsta_params {
273*4882a593Smuzhiyun 	struct wl_if_info if_info[MAX_IF_NUM];
274*4882a593Smuzhiyun #ifdef WLDWDS
275*4882a593Smuzhiyun 	struct wl_dwds_info dwds_info[MAX_DWDS_IF_NUM];
276*4882a593Smuzhiyun #endif /* WLDWDS */
277*4882a593Smuzhiyun 	u8 *ioctl_buf;
278*4882a593Smuzhiyun 	bool init;
279*4882a593Smuzhiyun 	int rsdb;
280*4882a593Smuzhiyun 	bool vsdb;
281*4882a593Smuzhiyun 	uint csa;
282*4882a593Smuzhiyun 	uint acs;
283*4882a593Smuzhiyun #ifdef ACS_MONITOR
284*4882a593Smuzhiyun 	uint acs_tmo;
285*4882a593Smuzhiyun #endif /* ACS_MONITOR */
286*4882a593Smuzhiyun 	bool radar;
287*4882a593Smuzhiyun 	apstamode_t apstamode;
288*4882a593Smuzhiyun 	wait_queue_head_t netif_change_event;
289*4882a593Smuzhiyun 	struct mutex usr_sync;
290*4882a593Smuzhiyun #if defined(WLMESH) && defined(WL_ESCAN)
291*4882a593Smuzhiyun 	int macs;
292*4882a593Smuzhiyun 	struct wl_mesh_params mesh_info;
293*4882a593Smuzhiyun #endif /* WLMESH && WL_ESCAN */
294*4882a593Smuzhiyun 	struct mutex in4way_sync;
295*4882a593Smuzhiyun 	int sta_btc_mode;
296*4882a593Smuzhiyun #ifdef TPUT_MONITOR
297*4882a593Smuzhiyun 	timer_list_compat_t monitor_timer;
298*4882a593Smuzhiyun 	int32 tput_sum;
299*4882a593Smuzhiyun 	int32 tput_sum_kb;
300*4882a593Smuzhiyun #endif /* TPUT_MONITOR */
301*4882a593Smuzhiyun #ifdef SCAN_SUPPRESS
302*4882a593Smuzhiyun 	struct osl_timespec scan_busy_ts;
303*4882a593Smuzhiyun 	int scan_busy_cnt;
304*4882a593Smuzhiyun #endif /* SCAN_SUPPRESS */
305*4882a593Smuzhiyun 	uint32 linkdown_reason;
306*4882a593Smuzhiyun #ifdef EAPOL_RESEND
307*4882a593Smuzhiyun 	spinlock_t eapol_lock;
308*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
309*4882a593Smuzhiyun #ifdef STA_MGMT
310*4882a593Smuzhiyun 	struct list_head sta_list;
311*4882a593Smuzhiyun #endif /* STA_MGMT */
312*4882a593Smuzhiyun #ifdef RXF0OVFL_REINIT_WAR
313*4882a593Smuzhiyun 	timer_list_compat_t rxf0ovfl_timer;
314*4882a593Smuzhiyun 	uint32 rxbeaconmbss;
315*4882a593Smuzhiyun 	uint32 rxf0ovfl;
316*4882a593Smuzhiyun 	int war_reason;
317*4882a593Smuzhiyun #endif /* RXF0OVFL_REINIT_WAR */
318*4882a593Smuzhiyun } wl_apsta_params_t;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun enum wifi_isam_status {
321*4882a593Smuzhiyun 	ISAM_STATUS_IF_ADDING = 0,
322*4882a593Smuzhiyun 	ISAM_STATUS_IF_READY,
323*4882a593Smuzhiyun 	ISAM_STATUS_STA_CONNECTING,
324*4882a593Smuzhiyun 	ISAM_STATUS_STA_CONNECTED,
325*4882a593Smuzhiyun 	ISAM_STATUS_AP_CREATING,
326*4882a593Smuzhiyun 	ISAM_STATUS_AP_CREATED
327*4882a593Smuzhiyun };
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun enum wifi_isam_reason {
330*4882a593Smuzhiyun 	ISAM_RC_MESH_ACS = 1,
331*4882a593Smuzhiyun 	ISAM_RC_TPUT_MONITOR = 2,
332*4882a593Smuzhiyun 	ISAM_RC_AP_ACS = 3,
333*4882a593Smuzhiyun 	ISAM_RC_AP_RESTART = 4,
334*4882a593Smuzhiyun 	ISAM_RC_AP_RESET = 5,
335*4882a593Smuzhiyun 	ISAM_RC_EAPOL_RESEND = 6,
336*4882a593Smuzhiyun 	ISAM_RC_KEY_INSTALL = 7,
337*4882a593Smuzhiyun 	ISAM_RC_RXF0OVFL_REINIT = 8
338*4882a593Smuzhiyun };
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun #define wl_get_isam_status(cur_if, stat) \
341*4882a593Smuzhiyun 	(test_bit(ISAM_STATUS_ ## stat, &(cur_if)->status))
342*4882a593Smuzhiyun #define wl_set_isam_status(cur_if, stat) \
343*4882a593Smuzhiyun 	(set_bit(ISAM_STATUS_ ## stat, &(cur_if)->status))
344*4882a593Smuzhiyun #define wl_clr_isam_status(cur_if, stat) \
345*4882a593Smuzhiyun 	(clear_bit(ISAM_STATUS_ ## stat, &(cur_if)->status))
346*4882a593Smuzhiyun #define wl_chg_isam_status(cur_if, stat) \
347*4882a593Smuzhiyun 	(change_bit(ISAM_STATUS_ ## stat, &(cur_if)->status))
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun static int wl_ext_enable_iface(struct net_device *dev, char *ifname,
350*4882a593Smuzhiyun 	int wait_up, bool lock);
351*4882a593Smuzhiyun static int wl_ext_disable_iface(struct net_device *dev, char *ifname);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun static struct wl_if_info *
wl_get_cur_if(struct net_device * dev)354*4882a593Smuzhiyun wl_get_cur_if(struct net_device *dev)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun 	dhd_pub_t *dhd = dhd_get_pub(dev);
357*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
358*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL, *tmp_if = NULL;
359*4882a593Smuzhiyun 	int i;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
362*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
363*4882a593Smuzhiyun 		if (tmp_if->dev && tmp_if->dev == dev) {
364*4882a593Smuzhiyun 			cur_if = tmp_if;
365*4882a593Smuzhiyun 			break;
366*4882a593Smuzhiyun 		}
367*4882a593Smuzhiyun 	}
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	return cur_if;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun #define WL_PM_ENABLE_TIMEOUT 10000
373*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
374*4882a593Smuzhiyun 	4 && __GNUC_MINOR__ >= 6))
375*4882a593Smuzhiyun #define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
376*4882a593Smuzhiyun _Pragma("GCC diagnostic push") \
377*4882a593Smuzhiyun _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
378*4882a593Smuzhiyun entry = container_of((ptr), type, member); \
379*4882a593Smuzhiyun _Pragma("GCC diagnostic pop")
380*4882a593Smuzhiyun #else
381*4882a593Smuzhiyun #define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
382*4882a593Smuzhiyun entry = container_of((ptr), type, member);
383*4882a593Smuzhiyun #endif /* STRICT_GCC_WARNINGS */
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun static void
wl_ext_pm_work_handler(struct work_struct * work)386*4882a593Smuzhiyun wl_ext_pm_work_handler(struct work_struct *work)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
389*4882a593Smuzhiyun 	s32 pm = PM_FAST;
390*4882a593Smuzhiyun 	dhd_pub_t *dhd;
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	BCM_SET_CONTAINER_OF(cur_if, work, struct wl_if_info, pm_enable_work.work);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	IAPSTA_TRACE("wlan", "%s: Enter\n", __FUNCTION__);
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	if (cur_if->dev == NULL)
397*4882a593Smuzhiyun 		return;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
400*4882a593Smuzhiyun 	4 && __GNUC_MINOR__ >= 6))
401*4882a593Smuzhiyun _Pragma("GCC diagnostic push")
402*4882a593Smuzhiyun _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
403*4882a593Smuzhiyun #endif
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	dhd = dhd_get_pub(cur_if->dev);
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	if (!dhd || !dhd->up) {
408*4882a593Smuzhiyun 		IAPSTA_TRACE(cur_if->ifname, "dhd is null or not up\n");
409*4882a593Smuzhiyun 		return;
410*4882a593Smuzhiyun 	}
411*4882a593Smuzhiyun 	if (dhd_conf_get_pm(dhd) >= 0)
412*4882a593Smuzhiyun 		pm = dhd_conf_get_pm(dhd);
413*4882a593Smuzhiyun 	wl_ext_ioctl(cur_if->dev, WLC_SET_PM, &pm, sizeof(pm), 1);
414*4882a593Smuzhiyun #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
415*4882a593Smuzhiyun 	4 && __GNUC_MINOR__ >= 6))
416*4882a593Smuzhiyun _Pragma("GCC diagnostic pop")
417*4882a593Smuzhiyun #endif
418*4882a593Smuzhiyun 	DHD_PM_WAKE_UNLOCK(dhd);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun void
wl_ext_add_remove_pm_enable_work(struct net_device * dev,bool add)423*4882a593Smuzhiyun wl_ext_add_remove_pm_enable_work(struct net_device *dev, bool add)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun 	dhd_pub_t *dhd = dhd_get_pub(dev);
426*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
427*4882a593Smuzhiyun 	u16 wq_duration = 0;
428*4882a593Smuzhiyun 	s32 pm = PM_OFF;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
431*4882a593Smuzhiyun 	if (!cur_if)
432*4882a593Smuzhiyun 		return;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	mutex_lock(&cur_if->pm_sync);
435*4882a593Smuzhiyun 	/*
436*4882a593Smuzhiyun 	 * Make cancel and schedule work part mutually exclusive
437*4882a593Smuzhiyun 	 * so that while cancelling, we are sure that there is no
438*4882a593Smuzhiyun 	 * work getting scheduled.
439*4882a593Smuzhiyun 	 */
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	if (delayed_work_pending(&cur_if->pm_enable_work)) {
442*4882a593Smuzhiyun 		cancel_delayed_work_sync(&cur_if->pm_enable_work);
443*4882a593Smuzhiyun 		DHD_PM_WAKE_UNLOCK(dhd);
444*4882a593Smuzhiyun 	}
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	if (add) {
447*4882a593Smuzhiyun 		wq_duration = (WL_PM_ENABLE_TIMEOUT);
448*4882a593Smuzhiyun 	}
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	/* It should schedule work item only if driver is up */
451*4882a593Smuzhiyun 	if (dhd->up) {
452*4882a593Smuzhiyun 		if (add) {
453*4882a593Smuzhiyun 			if (dhd_conf_get_pm(dhd) >= 0)
454*4882a593Smuzhiyun 				pm = dhd_conf_get_pm(dhd);
455*4882a593Smuzhiyun 			wl_ext_ioctl(cur_if->dev, WLC_SET_PM, &pm, sizeof(pm), 1);
456*4882a593Smuzhiyun 		}
457*4882a593Smuzhiyun 		if (wq_duration) {
458*4882a593Smuzhiyun 			if (schedule_delayed_work(&cur_if->pm_enable_work,
459*4882a593Smuzhiyun 					msecs_to_jiffies((const unsigned int)wq_duration))) {
460*4882a593Smuzhiyun 				DHD_PM_WAKE_LOCK_TIMEOUT(dhd, wq_duration);
461*4882a593Smuzhiyun 			} else {
462*4882a593Smuzhiyun 				IAPSTA_ERROR(cur_if->ifname, "Can't schedule pm work handler\n");
463*4882a593Smuzhiyun 			}
464*4882a593Smuzhiyun 		}
465*4882a593Smuzhiyun 	}
466*4882a593Smuzhiyun 	mutex_unlock(&cur_if->pm_sync);
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun static int
wl_ext_parse_wep(char * key,struct wl_wsec_key * wsec_key)471*4882a593Smuzhiyun wl_ext_parse_wep(char *key, struct wl_wsec_key *wsec_key)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun 	char hex[] = "XX";
474*4882a593Smuzhiyun 	unsigned char *data = wsec_key->data;
475*4882a593Smuzhiyun 	char *keystr = key;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	switch (strlen(keystr)) {
478*4882a593Smuzhiyun 	case 5:
479*4882a593Smuzhiyun 	case 13:
480*4882a593Smuzhiyun 	case 16:
481*4882a593Smuzhiyun 		wsec_key->len = strlen(keystr);
482*4882a593Smuzhiyun 		memcpy(data, keystr, wsec_key->len + 1);
483*4882a593Smuzhiyun 		break;
484*4882a593Smuzhiyun 	case 12:
485*4882a593Smuzhiyun 	case 28:
486*4882a593Smuzhiyun 	case 34:
487*4882a593Smuzhiyun 	case 66:
488*4882a593Smuzhiyun 		/* strip leading 0x */
489*4882a593Smuzhiyun 		if (!strnicmp(keystr, "0x", 2))
490*4882a593Smuzhiyun 			keystr += 2;
491*4882a593Smuzhiyun 		else
492*4882a593Smuzhiyun 			return -1;
493*4882a593Smuzhiyun 		/* fall through */
494*4882a593Smuzhiyun 	case 10:
495*4882a593Smuzhiyun 	case 26:
496*4882a593Smuzhiyun 	case 32:
497*4882a593Smuzhiyun 	case 64:
498*4882a593Smuzhiyun 		wsec_key->len = strlen(keystr) / 2;
499*4882a593Smuzhiyun 		while (*keystr) {
500*4882a593Smuzhiyun 			strncpy(hex, keystr, 2);
501*4882a593Smuzhiyun 			*data++ = (char) strtoul(hex, NULL, 16);
502*4882a593Smuzhiyun 			keystr += 2;
503*4882a593Smuzhiyun 		}
504*4882a593Smuzhiyun 		break;
505*4882a593Smuzhiyun 	default:
506*4882a593Smuzhiyun 		return -1;
507*4882a593Smuzhiyun 	}
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	switch (wsec_key->len) {
510*4882a593Smuzhiyun 	case 5:
511*4882a593Smuzhiyun 		wsec_key->algo = CRYPTO_ALGO_WEP1;
512*4882a593Smuzhiyun 		break;
513*4882a593Smuzhiyun 	case 13:
514*4882a593Smuzhiyun 		wsec_key->algo = CRYPTO_ALGO_WEP128;
515*4882a593Smuzhiyun 		break;
516*4882a593Smuzhiyun 	case 16:
517*4882a593Smuzhiyun 		/* default to AES-CCM */
518*4882a593Smuzhiyun 		wsec_key->algo = CRYPTO_ALGO_AES_CCM;
519*4882a593Smuzhiyun 		break;
520*4882a593Smuzhiyun 	case 32:
521*4882a593Smuzhiyun 		wsec_key->algo = CRYPTO_ALGO_TKIP;
522*4882a593Smuzhiyun 		break;
523*4882a593Smuzhiyun 	default:
524*4882a593Smuzhiyun 		return -1;
525*4882a593Smuzhiyun 	}
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	/* Set as primary wsec_key by default */
528*4882a593Smuzhiyun 	wsec_key->flags |= WL_PRIMARY_KEY;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	return 0;
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun static int
wl_ext_set_bgnmode(struct wl_if_info * cur_if)534*4882a593Smuzhiyun wl_ext_set_bgnmode(struct wl_if_info *cur_if)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun 	struct net_device *dev = cur_if->dev;
537*4882a593Smuzhiyun 	bgnmode_t bgnmode = cur_if->bgnmode;
538*4882a593Smuzhiyun 	int val;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	if (bgnmode == 0)
541*4882a593Smuzhiyun 		return 0;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
544*4882a593Smuzhiyun 	if (bgnmode == IEEE80211B) {
545*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "nmode", 0);
546*4882a593Smuzhiyun 		val = 0;
547*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
548*4882a593Smuzhiyun 		IAPSTA_TRACE(dev->name, "Network mode: B only\n");
549*4882a593Smuzhiyun 	} else if (bgnmode == IEEE80211G) {
550*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "nmode", 0);
551*4882a593Smuzhiyun 		val = 2;
552*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
553*4882a593Smuzhiyun 		IAPSTA_TRACE(dev->name, "Network mode: G only\n");
554*4882a593Smuzhiyun 	} else if (bgnmode == IEEE80211BG) {
555*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "nmode", 0);
556*4882a593Smuzhiyun 		val = 1;
557*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
558*4882a593Smuzhiyun 		IAPSTA_TRACE(dev->name, "Network mode: B/G mixed\n");
559*4882a593Smuzhiyun 	} else if (bgnmode == IEEE80211BGN) {
560*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "nmode", 0);
561*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "nmode", 1);
562*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "vhtmode", 0);
563*4882a593Smuzhiyun 		val = 1;
564*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
565*4882a593Smuzhiyun 		IAPSTA_TRACE(dev->name, "Network mode: B/G/N mixed\n");
566*4882a593Smuzhiyun 	} else if (bgnmode == IEEE80211BGNAC) {
567*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "nmode", 0);
568*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "nmode", 1);
569*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "vhtmode", 1);
570*4882a593Smuzhiyun 		val = 1;
571*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
572*4882a593Smuzhiyun 		IAPSTA_TRACE(dev->name, "Network mode: B/G/N/AC mixed\n");
573*4882a593Smuzhiyun 	}
574*4882a593Smuzhiyun 	wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	return 0;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun static int
wl_ext_set_amode(struct wl_if_info * cur_if)580*4882a593Smuzhiyun wl_ext_set_amode(struct wl_if_info *cur_if)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun 	struct net_device *dev = cur_if->dev;
583*4882a593Smuzhiyun 	authmode_t amode = cur_if->amode;
584*4882a593Smuzhiyun 	int auth=0, wpa_auth=0;
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun #ifdef WLMESH
587*4882a593Smuzhiyun 	if (cur_if->ifmode == IMESH_MODE) {
588*4882a593Smuzhiyun 		if (amode == AUTH_SAE) {
589*4882a593Smuzhiyun 			auth = WL_AUTH_OPEN_SYSTEM;
590*4882a593Smuzhiyun 			wpa_auth = WPA2_AUTH_PSK;
591*4882a593Smuzhiyun 			IAPSTA_INFO(dev->name, "SAE\n");
592*4882a593Smuzhiyun 		} else {
593*4882a593Smuzhiyun 			auth = WL_AUTH_OPEN_SYSTEM;
594*4882a593Smuzhiyun 			wpa_auth = WPA_AUTH_DISABLED;
595*4882a593Smuzhiyun 			IAPSTA_INFO(dev->name, "Open System\n");
596*4882a593Smuzhiyun 		}
597*4882a593Smuzhiyun 	} else
598*4882a593Smuzhiyun #endif /* WLMESH */
599*4882a593Smuzhiyun 	if (amode == AUTH_OPEN) {
600*4882a593Smuzhiyun 		auth = WL_AUTH_OPEN_SYSTEM;
601*4882a593Smuzhiyun 		wpa_auth = WPA_AUTH_DISABLED;
602*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "Open System\n");
603*4882a593Smuzhiyun 	} else if (amode == AUTH_SHARED) {
604*4882a593Smuzhiyun 		auth = WL_AUTH_SHARED_KEY;
605*4882a593Smuzhiyun 		wpa_auth = WPA_AUTH_DISABLED;
606*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "Shared Key\n");
607*4882a593Smuzhiyun 	} else if (amode == AUTH_WPAPSK) {
608*4882a593Smuzhiyun 		auth = WL_AUTH_OPEN_SYSTEM;
609*4882a593Smuzhiyun 		wpa_auth = WPA_AUTH_PSK;
610*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "WPA-PSK\n");
611*4882a593Smuzhiyun 	} else if (amode == AUTH_WPA2PSK) {
612*4882a593Smuzhiyun 		auth = WL_AUTH_OPEN_SYSTEM;
613*4882a593Smuzhiyun 		wpa_auth = WPA2_AUTH_PSK;
614*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "WPA2-PSK\n");
615*4882a593Smuzhiyun 	} else if (amode == AUTH_WPAWPA2PSK) {
616*4882a593Smuzhiyun 		auth = WL_AUTH_OPEN_SYSTEM;
617*4882a593Smuzhiyun 		wpa_auth = WPA2_AUTH_PSK | WPA_AUTH_PSK;
618*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "WPA/WPA2-PSK\n");
619*4882a593Smuzhiyun 	}
620*4882a593Smuzhiyun #ifdef WLMESH
621*4882a593Smuzhiyun 	if (cur_if->ifmode == IMESH_MODE) {
622*4882a593Smuzhiyun 		s32 val = WL_BSSTYPE_MESH;
623*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_SET_INFRA, &val, sizeof(val), 1);
624*4882a593Smuzhiyun 	} else
625*4882a593Smuzhiyun #endif /* WLMESH */
626*4882a593Smuzhiyun 	if (cur_if->ifmode == ISTA_MODE) {
627*4882a593Smuzhiyun 		s32 val = WL_BSSTYPE_INFRA;
628*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_SET_INFRA, &val, sizeof(val), 1);
629*4882a593Smuzhiyun 	}
630*4882a593Smuzhiyun 	wl_ext_iovar_setint(dev, "auth", auth);
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	wl_ext_iovar_setint(dev, "wpa_auth", wpa_auth);
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	return 0;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun static int
wl_ext_set_emode(struct wl_if_info * cur_if)638*4882a593Smuzhiyun wl_ext_set_emode(struct wl_if_info *cur_if)
639*4882a593Smuzhiyun {
640*4882a593Smuzhiyun 	struct net_device *dev = cur_if->dev;
641*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
642*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
643*4882a593Smuzhiyun 	struct wl_wsec_key wsec_key;
644*4882a593Smuzhiyun 	wsec_pmk_t psk;
645*4882a593Smuzhiyun 	authmode_t amode = cur_if->amode;
646*4882a593Smuzhiyun 	encmode_t emode = cur_if->emode;
647*4882a593Smuzhiyun 	int wsec=0;
648*4882a593Smuzhiyun 	char *key = cur_if->key;
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	memset(&wsec_key, 0, sizeof(wsec_key));
651*4882a593Smuzhiyun 	memset(&psk, 0, sizeof(psk));
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun #ifdef WLMESH
654*4882a593Smuzhiyun 	if (cur_if->ifmode == IMESH_MODE) {
655*4882a593Smuzhiyun 		if (amode == AUTH_SAE) {
656*4882a593Smuzhiyun 			wsec = AES_ENABLED;
657*4882a593Smuzhiyun 		} else {
658*4882a593Smuzhiyun 			wsec = WSEC_NONE;
659*4882a593Smuzhiyun 		}
660*4882a593Smuzhiyun 	} else
661*4882a593Smuzhiyun #endif /* WLMESH */
662*4882a593Smuzhiyun 	if (emode == ENC_NONE) {
663*4882a593Smuzhiyun 		wsec = WSEC_NONE;
664*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "No securiy\n");
665*4882a593Smuzhiyun 	} else if (emode == ENC_WEP) {
666*4882a593Smuzhiyun 		wsec = WEP_ENABLED;
667*4882a593Smuzhiyun 		wl_ext_parse_wep(key, &wsec_key);
668*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "WEP key \"%s\"\n", wsec_key.data);
669*4882a593Smuzhiyun 	} else if (emode == ENC_TKIP) {
670*4882a593Smuzhiyun 		wsec = TKIP_ENABLED;
671*4882a593Smuzhiyun 		psk.key_len = strlen(key);
672*4882a593Smuzhiyun 		psk.flags = WSEC_PASSPHRASE;
673*4882a593Smuzhiyun 		memcpy(psk.key, key, strlen(key));
674*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "TKIP key \"%s\"\n", psk.key);
675*4882a593Smuzhiyun 	} else if (emode == ENC_AES || amode == AUTH_SAE) {
676*4882a593Smuzhiyun 		wsec = AES_ENABLED;
677*4882a593Smuzhiyun 		psk.key_len = strlen(key);
678*4882a593Smuzhiyun 		psk.flags = WSEC_PASSPHRASE;
679*4882a593Smuzhiyun 		memcpy(psk.key, key, strlen(key));
680*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "AES key \"%s\"\n", psk.key);
681*4882a593Smuzhiyun 	} else if (emode == ENC_TKIPAES) {
682*4882a593Smuzhiyun 		wsec = TKIP_ENABLED | AES_ENABLED;
683*4882a593Smuzhiyun 		psk.key_len = strlen(key);
684*4882a593Smuzhiyun 		psk.flags = WSEC_PASSPHRASE;
685*4882a593Smuzhiyun 		memcpy(psk.key, key, strlen(key));
686*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "TKIP/AES key \"%s\"\n", psk.key);
687*4882a593Smuzhiyun 	}
688*4882a593Smuzhiyun 	if (dhd->conf->chip == BCM43430_CHIP_ID && cur_if->ifidx > 0 && wsec >= 2 &&
689*4882a593Smuzhiyun 			apsta_params->apstamode == ISTAAP_MODE) {
690*4882a593Smuzhiyun 		wsec |= WSEC_SWFLAG; // terence 20180628: fix me, this is a workaround
691*4882a593Smuzhiyun 	}
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	wl_ext_iovar_setint(dev, "wsec", wsec);
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun #ifdef WLMESH
696*4882a593Smuzhiyun 	if (cur_if->ifmode == IMESH_MODE) {
697*4882a593Smuzhiyun 		if (amode == AUTH_SAE) {
698*4882a593Smuzhiyun 			s8 iovar_buf[WLC_IOCTL_SMLEN];
699*4882a593Smuzhiyun 			IAPSTA_INFO(dev->name, "AES key \"%s\"\n", key);
700*4882a593Smuzhiyun 			wl_ext_iovar_setint(dev, "mesh_auth_proto", 1);
701*4882a593Smuzhiyun 			wl_ext_iovar_setint(dev, "mfp", WL_MFP_REQUIRED);
702*4882a593Smuzhiyun 			wl_ext_iovar_setbuf(dev, "sae_password", key, strlen(key),
703*4882a593Smuzhiyun 				iovar_buf, WLC_IOCTL_SMLEN, NULL);
704*4882a593Smuzhiyun 		} else {
705*4882a593Smuzhiyun 			IAPSTA_INFO(dev->name, "No securiy\n");
706*4882a593Smuzhiyun 			wl_ext_iovar_setint(dev, "mesh_auth_proto", 0);
707*4882a593Smuzhiyun 			wl_ext_iovar_setint(dev, "mfp", WL_MFP_NONE);
708*4882a593Smuzhiyun 		}
709*4882a593Smuzhiyun 	} else
710*4882a593Smuzhiyun #endif /* WLMESH */
711*4882a593Smuzhiyun 	if (emode == ENC_WEP) {
712*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_SET_KEY, &wsec_key, sizeof(wsec_key), 1);
713*4882a593Smuzhiyun 	} else if (emode == ENC_TKIP || emode == ENC_AES || emode == ENC_TKIPAES) {
714*4882a593Smuzhiyun 		if (cur_if->ifmode == ISTA_MODE)
715*4882a593Smuzhiyun 			wl_ext_iovar_setint(dev, "sup_wpa", 1);
716*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk), 1);
717*4882a593Smuzhiyun 	}
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	return 0;
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun static void
wl_ext_set_chan_info(struct wl_if_info * cur_if,uint band,uint16 chan)723*4882a593Smuzhiyun wl_ext_set_chan_info(struct wl_if_info *cur_if, uint band, uint16 chan)
724*4882a593Smuzhiyun {
725*4882a593Smuzhiyun 	cur_if->chan_info.band = band;
726*4882a593Smuzhiyun 	cur_if->chan_info.chan = chan;
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun static bool
wl_ext_associated(struct net_device * dev)730*4882a593Smuzhiyun wl_ext_associated(struct net_device *dev)
731*4882a593Smuzhiyun {
732*4882a593Smuzhiyun 	struct ether_addr bssid;
733*4882a593Smuzhiyun 	int ret = 0;
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 	ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
736*4882a593Smuzhiyun 	if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
737*4882a593Smuzhiyun 		return TRUE;
738*4882a593Smuzhiyun 	}
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	return FALSE;
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun static u32
wl_ext_get_chanspec(struct net_device * dev,struct wl_chan_info * chan_info)744*4882a593Smuzhiyun wl_ext_get_chanspec(struct net_device *dev, struct wl_chan_info *chan_info)
745*4882a593Smuzhiyun {
746*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
747*4882a593Smuzhiyun 	u32 chanspec = 0;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	if (wl_ext_associated(dev)) {
750*4882a593Smuzhiyun 		if (wl_ext_iovar_getint(dev, "chanspec", (s32 *)&chanspec) == BCME_OK) {
751*4882a593Smuzhiyun 			chanspec = wl_ext_chspec_driver_to_host(dhd, chanspec);
752*4882a593Smuzhiyun 			if (chan_info) {
753*4882a593Smuzhiyun 				chan_info->band = CHSPEC2WLC_BAND(chanspec);
754*4882a593Smuzhiyun 				chan_info->chan = wf_chspec_ctlchan(chanspec);
755*4882a593Smuzhiyun 			}
756*4882a593Smuzhiyun 			return chanspec;
757*4882a593Smuzhiyun 		}
758*4882a593Smuzhiyun 	}
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 	return 0;
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun static uint16
wl_ext_get_chan(struct net_device * dev,struct wl_chan_info * chan_info)764*4882a593Smuzhiyun wl_ext_get_chan(struct net_device *dev, struct wl_chan_info *chan_info)
765*4882a593Smuzhiyun {
766*4882a593Smuzhiyun 	uint16 chan = 0, ctl_chan;
767*4882a593Smuzhiyun 	u32 chanspec = 0;
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	chanspec = wl_ext_get_chanspec(dev, chan_info);
770*4882a593Smuzhiyun 	if (chanspec) {
771*4882a593Smuzhiyun 		ctl_chan = wf_chspec_ctlchan(chanspec);
772*4882a593Smuzhiyun 		chan = (u16)(ctl_chan & 0x00FF);
773*4882a593Smuzhiyun 	}
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	return chan;
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun void
wl_ext_get_chan_str(struct net_device * dev,char * chan_str,int total_len)779*4882a593Smuzhiyun wl_ext_get_chan_str(struct net_device *dev, char *chan_str, int total_len)
780*4882a593Smuzhiyun {
781*4882a593Smuzhiyun 	struct wl_chan_info chan_info;
782*4882a593Smuzhiyun 	int bytes_written=0;
783*4882a593Smuzhiyun 	u32 chanspec = 0;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	memset(chan_str, 0, total_len);
786*4882a593Smuzhiyun 	chanspec = wl_ext_get_chanspec(dev, &chan_info);
787*4882a593Smuzhiyun 	if (chanspec) {
788*4882a593Smuzhiyun 		bytes_written += snprintf(chan_str+bytes_written, total_len, "%s-%d %sMHz",
789*4882a593Smuzhiyun 			WLCBAND2STR(chan_info.band), chan_info.chan,
790*4882a593Smuzhiyun 			wf_chspec_to_bw_str(chanspec));
791*4882a593Smuzhiyun 	}
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun static chanspec_t
wl_ext_chan_to_chanspec(struct net_device * dev,struct wl_chan_info * chan_info)795*4882a593Smuzhiyun wl_ext_chan_to_chanspec(struct net_device *dev, struct wl_chan_info *chan_info)
796*4882a593Smuzhiyun {
797*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
798*4882a593Smuzhiyun 	chanspec_band_t chanspec_band;
799*4882a593Smuzhiyun 	chanspec_t chspec = 0, fw_chspec = 0;
800*4882a593Smuzhiyun 	u32 bw = WL_CHANSPEC_BW_20;
801*4882a593Smuzhiyun 	s32 err = BCME_OK, bw_cap = 0;
802*4882a593Smuzhiyun 	s8 iovar_buf[WLC_IOCTL_SMLEN];
803*4882a593Smuzhiyun 	struct {
804*4882a593Smuzhiyun 		u32 band;
805*4882a593Smuzhiyun 		u32 bw_cap;
806*4882a593Smuzhiyun 	} param = {0, 0};
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun 	if ((chan_info->band != WLC_BAND_2G) && (chan_info->band != WLC_BAND_5G) &&
809*4882a593Smuzhiyun 			(chan_info->band != WLC_BAND_6G)) {
810*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "bad band %d\n", chan_info->band);
811*4882a593Smuzhiyun 		return BCME_BADBAND;
812*4882a593Smuzhiyun 	}
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun 	param.band = chan_info->band;
815*4882a593Smuzhiyun 	err = wl_ext_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
816*4882a593Smuzhiyun 		iovar_buf, WLC_IOCTL_SMLEN, NULL);
817*4882a593Smuzhiyun 	if (err) {
818*4882a593Smuzhiyun 		if (err != BCME_UNSUPPORTED) {
819*4882a593Smuzhiyun 			IAPSTA_ERROR(dev->name, "bw_cap failed, %d\n", err);
820*4882a593Smuzhiyun 			return err;
821*4882a593Smuzhiyun 		} else {
822*4882a593Smuzhiyun 			err = wl_ext_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
823*4882a593Smuzhiyun 			if (bw_cap != WLC_N_BW_20ALL)
824*4882a593Smuzhiyun 				bw = WL_CHANSPEC_BW_40;
825*4882a593Smuzhiyun 		}
826*4882a593Smuzhiyun 	} else {
827*4882a593Smuzhiyun 		if (WL_BW_CAP_80MHZ(iovar_buf[0]))
828*4882a593Smuzhiyun 			bw = WL_CHANSPEC_BW_80;
829*4882a593Smuzhiyun 		else if (WL_BW_CAP_40MHZ(iovar_buf[0]))
830*4882a593Smuzhiyun 			bw = WL_CHANSPEC_BW_40;
831*4882a593Smuzhiyun 		else
832*4882a593Smuzhiyun 			bw = WL_CHANSPEC_BW_20;
833*4882a593Smuzhiyun 	}
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun set_channel:
836*4882a593Smuzhiyun 	chanspec_band = wl_ext_wlcband_to_chanspec_band(chan_info->band);
837*4882a593Smuzhiyun 	chspec = wf_create_chspec_from_primary(chan_info->chan, bw, chanspec_band);
838*4882a593Smuzhiyun 	if (wf_chspec_valid(chspec)) {
839*4882a593Smuzhiyun 		fw_chspec = wl_ext_chspec_host_to_driver(dhd, chspec);
840*4882a593Smuzhiyun 		if (fw_chspec == INVCHANSPEC) {
841*4882a593Smuzhiyun 			IAPSTA_ERROR(dev->name, "failed to convert host chanspec to fw chanspec\n");
842*4882a593Smuzhiyun 			fw_chspec = 0;
843*4882a593Smuzhiyun 		}
844*4882a593Smuzhiyun 	} else {
845*4882a593Smuzhiyun 		if (bw == WL_CHANSPEC_BW_80)
846*4882a593Smuzhiyun 			bw = WL_CHANSPEC_BW_40;
847*4882a593Smuzhiyun 		else if (bw == WL_CHANSPEC_BW_40)
848*4882a593Smuzhiyun 			bw = WL_CHANSPEC_BW_20;
849*4882a593Smuzhiyun 		else
850*4882a593Smuzhiyun 			bw = 0;
851*4882a593Smuzhiyun 		if (bw)
852*4882a593Smuzhiyun 			goto set_channel;
853*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "Invalid chanspec 0x%x\n", chspec);
854*4882a593Smuzhiyun 		err = BCME_ERROR;
855*4882a593Smuzhiyun 	}
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	return fw_chspec;
858*4882a593Smuzhiyun }
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun static bool
wl_ext_radar_detect(struct net_device * dev)861*4882a593Smuzhiyun wl_ext_radar_detect(struct net_device *dev)
862*4882a593Smuzhiyun {
863*4882a593Smuzhiyun 	int ret = BCME_OK;
864*4882a593Smuzhiyun 	bool radar = FALSE;
865*4882a593Smuzhiyun 	s32 val = 0;
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	if ((ret = wldev_ioctl(dev, WLC_GET_RADAR, &val, sizeof(int), false) == 0)) {
868*4882a593Smuzhiyun 		radar = TRUE;
869*4882a593Smuzhiyun 	}
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 	return radar;
872*4882a593Smuzhiyun }
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun static int
wl_ext_assoclist(struct net_device * dev,char * data,char * command,int total_len)875*4882a593Smuzhiyun wl_ext_assoclist(struct net_device *dev, char *data, char *command,
876*4882a593Smuzhiyun 	int total_len)
877*4882a593Smuzhiyun {
878*4882a593Smuzhiyun 	int ret = 0, i, maxassoc = 0, bytes_written = 0;
879*4882a593Smuzhiyun 	char mac_buf[MAX_NUM_OF_ASSOCLIST *
880*4882a593Smuzhiyun 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
881*4882a593Smuzhiyun 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun 	assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
884*4882a593Smuzhiyun 	ret = wl_ext_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf), 0);
885*4882a593Smuzhiyun 	if (ret)
886*4882a593Smuzhiyun 		return 0;
887*4882a593Smuzhiyun 	maxassoc = dtoh32(assoc_maclist->count);
888*4882a593Smuzhiyun 	for (i=0; i<maxassoc; i++) {
889*4882a593Smuzhiyun 		bytes_written += snprintf(command+bytes_written, total_len,
890*4882a593Smuzhiyun 			"\n#%02d: %pM", i, &assoc_maclist->ea[i]);
891*4882a593Smuzhiyun 	}
892*4882a593Smuzhiyun 
893*4882a593Smuzhiyun 	return bytes_written;
894*4882a593Smuzhiyun }
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun void
wl_ext_send_event_msg(struct net_device * dev,int event,int status,int reason)897*4882a593Smuzhiyun wl_ext_send_event_msg(struct net_device *dev, int event, int status,
898*4882a593Smuzhiyun 	int reason)
899*4882a593Smuzhiyun {
900*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
901*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
902*4882a593Smuzhiyun 	wl_event_msg_t msg;
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	if (dhd && dhd->up) {
905*4882a593Smuzhiyun 		cur_if = wl_get_cur_if(dev);
906*4882a593Smuzhiyun 		if (!cur_if)
907*4882a593Smuzhiyun 			return;
908*4882a593Smuzhiyun 		bzero(&msg, sizeof(wl_event_msg_t));
909*4882a593Smuzhiyun 		msg.ifidx = dhd_net2idx(dhd->info, dev);
910*4882a593Smuzhiyun 		msg.event_type = hton32(event);
911*4882a593Smuzhiyun 		msg.status = hton32(status);
912*4882a593Smuzhiyun 		msg.reason = hton32(reason);
913*4882a593Smuzhiyun 		memcpy(&msg.addr, &cur_if->bssid, ETHER_ADDR_LEN);
914*4882a593Smuzhiyun #ifdef WL_EVENT
915*4882a593Smuzhiyun 		wl_ext_event_send(dhd->event_params, &msg, NULL);
916*4882a593Smuzhiyun #endif /* WL_EVENT */
917*4882a593Smuzhiyun #ifdef WL_CFG80211
918*4882a593Smuzhiyun 		wl_cfg80211_event(dev, &msg, NULL);
919*4882a593Smuzhiyun #endif /* WL_CFG80211 */
920*4882a593Smuzhiyun 	}
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun #ifdef BTC_WAR
924*4882a593Smuzhiyun bool
wl_ext_iapsta_if_2g_enabled(struct net_device * net)925*4882a593Smuzhiyun wl_ext_iapsta_if_2g_enabled(struct net_device *net)
926*4882a593Smuzhiyun {
927*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
928*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
929*4882a593Smuzhiyun 	struct wl_if_info *tmp_if;
930*4882a593Smuzhiyun 	struct wl_chan_info chan_info;
931*4882a593Smuzhiyun 	bool enabled = FALSE;
932*4882a593Smuzhiyun 	uint16 cur_chan;
933*4882a593Smuzhiyun 	int i;
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
936*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
937*4882a593Smuzhiyun 		if (tmp_if && wl_get_isam_status(tmp_if, IF_READY)) {
938*4882a593Smuzhiyun 			cur_chan = wl_ext_get_chan(tmp_if->dev, &chan_info);
939*4882a593Smuzhiyun 			if (cur_chan && chan_info.band == WLC_BAND_2G) {
940*4882a593Smuzhiyun 				enabled = TRUE;
941*4882a593Smuzhiyun 				break;
942*4882a593Smuzhiyun 			}
943*4882a593Smuzhiyun 		}
944*4882a593Smuzhiyun 	}
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	return enabled;
947*4882a593Smuzhiyun }
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun void
wl_ext_btc_config(struct net_device * dev,bool enable)950*4882a593Smuzhiyun wl_ext_btc_config(struct net_device *dev, bool enable)
951*4882a593Smuzhiyun {
952*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
953*4882a593Smuzhiyun 	bool enab = FALSE;
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 	if (dhd->conf->chip == BCM4354_CHIP_ID || dhd->conf->chip == BCM4356_CHIP_ID ||
956*4882a593Smuzhiyun 			dhd->conf->chip == BCM43752_CHIP_ID) {
957*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "btc_war=%d, enable=%d\n", btc_war, enable);
958*4882a593Smuzhiyun 		if (btc_war >= 0) {
959*4882a593Smuzhiyun 			if (enable && btc_war > 0) {
960*4882a593Smuzhiyun 				if (wl_ext_iapsta_if_2g_enabled(dev))
961*4882a593Smuzhiyun 					enab = TRUE;
962*4882a593Smuzhiyun 			}
963*4882a593Smuzhiyun 			if (enab) {
964*4882a593Smuzhiyun 				IAPSTA_INFO(dev->name, "enable\n");
965*4882a593Smuzhiyun 				wl_ext_iovar_setint(dev, "txchain", 2);
966*4882a593Smuzhiyun 				wl_ext_iovar_setint(dev, "rxchain", 2);
967*4882a593Smuzhiyun 				wl_ext_iovar_setint(dev, "btc_mode", 5);
968*4882a593Smuzhiyun 			} else {
969*4882a593Smuzhiyun 				IAPSTA_INFO(dev->name, "disable\n");
970*4882a593Smuzhiyun 				wl_ext_iovar_setint(dev, "btc_mode", 1);
971*4882a593Smuzhiyun 				wl_ext_iovar_setint(dev, "txchain", 3);
972*4882a593Smuzhiyun 				wl_ext_iovar_setint(dev, "rxchain", 3);
973*4882a593Smuzhiyun 			}
974*4882a593Smuzhiyun 		}
975*4882a593Smuzhiyun 	}
976*4882a593Smuzhiyun }
977*4882a593Smuzhiyun #endif /* BTC_WAR */
978*4882a593Smuzhiyun 
979*4882a593Smuzhiyun static void
wl_ext_connect_timeout(unsigned long data)980*4882a593Smuzhiyun wl_ext_connect_timeout(unsigned long data)
981*4882a593Smuzhiyun {
982*4882a593Smuzhiyun 	struct net_device *dev = (struct net_device *)data;
983*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 	if (!dev) {
986*4882a593Smuzhiyun 		IAPSTA_ERROR("wlan", "dev is not ready\n");
987*4882a593Smuzhiyun 		return;
988*4882a593Smuzhiyun 	}
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
991*4882a593Smuzhiyun 	if (!cur_if)
992*4882a593Smuzhiyun 		return;
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
995*4882a593Smuzhiyun 	cur_if->assoc_info.reassoc = 0;
996*4882a593Smuzhiyun #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
997*4882a593Smuzhiyun 	IAPSTA_ERROR(dev->name, "timer expired\n");
998*4882a593Smuzhiyun 	wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WLC_E_STATUS_SUCCESS);
999*4882a593Smuzhiyun }
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun #if defined(WL_CFG80211) || (defined(WLMESH) && defined(WL_ESCAN))
1002*4882a593Smuzhiyun static struct wl_if_info *
wl_ext_if_enabled(struct wl_apsta_params * apsta_params,ifmode_t ifmode)1003*4882a593Smuzhiyun wl_ext_if_enabled(struct wl_apsta_params *apsta_params, ifmode_t ifmode)
1004*4882a593Smuzhiyun {
1005*4882a593Smuzhiyun 	struct wl_if_info *tmp_if, *target_if = NULL;
1006*4882a593Smuzhiyun 	int i;
1007*4882a593Smuzhiyun 
1008*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
1009*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
1010*4882a593Smuzhiyun 		if (tmp_if && tmp_if->ifmode == ifmode &&
1011*4882a593Smuzhiyun 				wl_get_isam_status(tmp_if, IF_READY)) {
1012*4882a593Smuzhiyun 			if (wl_ext_associated(tmp_if->dev)) {
1013*4882a593Smuzhiyun 				target_if = tmp_if;
1014*4882a593Smuzhiyun 				break;
1015*4882a593Smuzhiyun 			}
1016*4882a593Smuzhiyun 		}
1017*4882a593Smuzhiyun 	}
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun 	return target_if;
1020*4882a593Smuzhiyun }
1021*4882a593Smuzhiyun #endif
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun #ifdef WLMESH
1024*4882a593Smuzhiyun static int
wl_mesh_print_peer_info(mesh_peer_info_ext_t * mpi_ext,uint32 peer_results_count,char * command,int total_len)1025*4882a593Smuzhiyun wl_mesh_print_peer_info(mesh_peer_info_ext_t *mpi_ext,
1026*4882a593Smuzhiyun 	uint32 peer_results_count, char *command, int total_len)
1027*4882a593Smuzhiyun {
1028*4882a593Smuzhiyun 	char *peering_map[] = MESH_PEERING_STATE_STRINGS;
1029*4882a593Smuzhiyun 	uint32 count = 0;
1030*4882a593Smuzhiyun 	int bytes_written = 0;
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun 	bytes_written += snprintf(command+bytes_written, total_len,
1033*4882a593Smuzhiyun 		"%2s: %12s : %6s : %-6s : %6s :"
1034*4882a593Smuzhiyun 		" %5s : %4s : %4s : %11s : %4s",
1035*4882a593Smuzhiyun 		"no", "------addr------ ", "l.aid", "state", "p.aid",
1036*4882a593Smuzhiyun 		"mppid", "llid", "plid", "entry_state", "rssi");
1037*4882a593Smuzhiyun 	for (count=0; count < peer_results_count; count++) {
1038*4882a593Smuzhiyun 		if (mpi_ext->entry_state != MESH_SELF_PEER_ENTRY_STATE_TIMEDOUT) {
1039*4882a593Smuzhiyun 			bytes_written += snprintf(command+bytes_written, total_len,
1040*4882a593Smuzhiyun 				"\n%2d: %pM : 0x%4x : %6s : 0x%4x :"
1041*4882a593Smuzhiyun 				" %5d : %4d : %4d : %11s : %4d",
1042*4882a593Smuzhiyun 				count, &mpi_ext->ea, mpi_ext->local_aid,
1043*4882a593Smuzhiyun 				peering_map[mpi_ext->peer_info.state],
1044*4882a593Smuzhiyun 				mpi_ext->peer_info.peer_aid,
1045*4882a593Smuzhiyun 				mpi_ext->peer_info.mesh_peer_prot_id,
1046*4882a593Smuzhiyun 				mpi_ext->peer_info.local_link_id,
1047*4882a593Smuzhiyun 				mpi_ext->peer_info.peer_link_id,
1048*4882a593Smuzhiyun 				(mpi_ext->entry_state == MESH_SELF_PEER_ENTRY_STATE_ACTIVE) ?
1049*4882a593Smuzhiyun 				"ACTIVE" :
1050*4882a593Smuzhiyun 				"EXTERNAL",
1051*4882a593Smuzhiyun 				mpi_ext->rssi);
1052*4882a593Smuzhiyun 		} else {
1053*4882a593Smuzhiyun 			bytes_written += snprintf(command+bytes_written, total_len,
1054*4882a593Smuzhiyun 				"\n%2d: %pM : %6s : %5s : %6s :"
1055*4882a593Smuzhiyun 				" %5s : %4s : %4s : %11s : %4s",
1056*4882a593Smuzhiyun 				count, &mpi_ext->ea, "  NA  ", "  NA  ", "  NA  ",
1057*4882a593Smuzhiyun 				"  NA ", " NA ", " NA ", "  TIMEDOUT ", " NA ");
1058*4882a593Smuzhiyun 		}
1059*4882a593Smuzhiyun 		mpi_ext++;
1060*4882a593Smuzhiyun 	}
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun 	return bytes_written;
1063*4882a593Smuzhiyun }
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun static int
wl_mesh_get_peer_results(struct net_device * dev,char * buf,int len)1066*4882a593Smuzhiyun wl_mesh_get_peer_results(struct net_device *dev, char *buf, int len)
1067*4882a593Smuzhiyun {
1068*4882a593Smuzhiyun 	int indata, inlen;
1069*4882a593Smuzhiyun 	mesh_peer_info_dump_t *peer_results;
1070*4882a593Smuzhiyun 	int ret;
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun 	memset(buf, 0, len);
1073*4882a593Smuzhiyun 	peer_results = (mesh_peer_info_dump_t *)buf;
1074*4882a593Smuzhiyun 	indata = htod32(len);
1075*4882a593Smuzhiyun 	inlen = 4;
1076*4882a593Smuzhiyun 	ret = wl_ext_iovar_getbuf(dev, "mesh_peer_status", &indata, inlen, buf, len, NULL);
1077*4882a593Smuzhiyun 	if (!ret) {
1078*4882a593Smuzhiyun 		peer_results = (mesh_peer_info_dump_t *)buf;
1079*4882a593Smuzhiyun 		ret = peer_results->count;
1080*4882a593Smuzhiyun 	}
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun 	return ret;
1083*4882a593Smuzhiyun }
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun int
wl_ext_mesh_peer_status(struct net_device * dev,char * data,char * command,int total_len)1086*4882a593Smuzhiyun wl_ext_mesh_peer_status(struct net_device *dev, char *data, char *command,
1087*4882a593Smuzhiyun 	int total_len)
1088*4882a593Smuzhiyun {
1089*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
1090*4882a593Smuzhiyun 	mesh_peer_info_dump_t *peer_results;
1091*4882a593Smuzhiyun 	mesh_peer_info_ext_t *mpi_ext;
1092*4882a593Smuzhiyun 	char *peer_buf = NULL;
1093*4882a593Smuzhiyun 	int peer_len = WLC_IOCTL_MAXLEN;
1094*4882a593Smuzhiyun 	int dump_written = 0, ret;
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun 	if (!data) {
1097*4882a593Smuzhiyun 		peer_buf = kmalloc(peer_len, GFP_KERNEL);
1098*4882a593Smuzhiyun 		if (peer_buf == NULL) {
1099*4882a593Smuzhiyun 			IAPSTA_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n",
1100*4882a593Smuzhiyun 				peer_len);
1101*4882a593Smuzhiyun 			return -1;
1102*4882a593Smuzhiyun 		}
1103*4882a593Smuzhiyun 		cur_if = wl_get_cur_if(dev);
1104*4882a593Smuzhiyun 		if (cur_if && cur_if->ifmode == IMESH_MODE) {
1105*4882a593Smuzhiyun 			memset(peer_buf, 0, peer_len);
1106*4882a593Smuzhiyun 			ret = wl_mesh_get_peer_results(dev, peer_buf, peer_len);
1107*4882a593Smuzhiyun 			if (ret >= 0) {
1108*4882a593Smuzhiyun 				peer_results = (mesh_peer_info_dump_t *)peer_buf;
1109*4882a593Smuzhiyun 				mpi_ext = (mesh_peer_info_ext_t *)peer_results->mpi_ext;
1110*4882a593Smuzhiyun 				dump_written += wl_mesh_print_peer_info(mpi_ext,
1111*4882a593Smuzhiyun 					peer_results->count, command+dump_written,
1112*4882a593Smuzhiyun 					total_len-dump_written);
1113*4882a593Smuzhiyun 			}
1114*4882a593Smuzhiyun 		} else if (cur_if) {
1115*4882a593Smuzhiyun 			IAPSTA_ERROR(dev->name, "[%s][%c] is not mesh interface\n",
1116*4882a593Smuzhiyun 				cur_if->ifname, cur_if->prefix);
1117*4882a593Smuzhiyun 		}
1118*4882a593Smuzhiyun 	}
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun 	if (peer_buf)
1121*4882a593Smuzhiyun 		kfree(peer_buf);
1122*4882a593Smuzhiyun 	return dump_written;
1123*4882a593Smuzhiyun }
1124*4882a593Smuzhiyun 
1125*4882a593Smuzhiyun #ifdef WL_ESCAN
1126*4882a593Smuzhiyun #define WL_MESH_DELAY_SCAN_TMO	3000
1127*4882a593Smuzhiyun static void
wl_mesh_timer(unsigned long data)1128*4882a593Smuzhiyun wl_mesh_timer(unsigned long data)
1129*4882a593Smuzhiyun {
1130*4882a593Smuzhiyun 	struct net_device *dev = (struct net_device *)data;
1131*4882a593Smuzhiyun 	struct dhd_pub *dhd;
1132*4882a593Smuzhiyun 	wl_event_msg_t msg;
1133*4882a593Smuzhiyun 
1134*4882a593Smuzhiyun 	if (!dev) {
1135*4882a593Smuzhiyun 		IAPSTA_ERROR("wlan", "dev is not ready\n");
1136*4882a593Smuzhiyun 		return;
1137*4882a593Smuzhiyun 	}
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 	dhd = dhd_get_pub(dev);
1140*4882a593Smuzhiyun 
1141*4882a593Smuzhiyun 	bzero(&msg, sizeof(wl_event_msg_t));
1142*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "timer expired\n");
1143*4882a593Smuzhiyun 
1144*4882a593Smuzhiyun 	msg.ifidx = dhd_net2idx(dhd->info, dev);
1145*4882a593Smuzhiyun 	msg.event_type = hton32(WLC_E_RESERVED);
1146*4882a593Smuzhiyun 	msg.reason = hton32(ISAM_RC_MESH_ACS);
1147*4882a593Smuzhiyun 	wl_ext_event_send(dhd->event_params, &msg, NULL);
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun static int
wl_mesh_clear_vndr_ie(struct net_device * dev,uchar * oui)1151*4882a593Smuzhiyun wl_mesh_clear_vndr_ie(struct net_device *dev, uchar *oui)
1152*4882a593Smuzhiyun {
1153*4882a593Smuzhiyun 	char *vndr_ie_buf = NULL;
1154*4882a593Smuzhiyun 	vndr_ie_setbuf_t *vndr_ie = NULL;
1155*4882a593Smuzhiyun 	ie_getbuf_t vndr_ie_tmp;
1156*4882a593Smuzhiyun 	char *iovar_buf = NULL;
1157*4882a593Smuzhiyun 	int err = -1, i;
1158*4882a593Smuzhiyun 	vndr_ie_buf_t *vndr_ie_dump = NULL;
1159*4882a593Smuzhiyun 	uchar *iebuf;
1160*4882a593Smuzhiyun 	vndr_ie_info_t *ie_info;
1161*4882a593Smuzhiyun 	vndr_ie_t *ie;
1162*4882a593Smuzhiyun 
1163*4882a593Smuzhiyun 	vndr_ie_buf = kzalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
1164*4882a593Smuzhiyun 	if (!vndr_ie_buf) {
1165*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "IE memory alloc failed\n");
1166*4882a593Smuzhiyun 		err = -ENOMEM;
1167*4882a593Smuzhiyun 		goto exit;
1168*4882a593Smuzhiyun 	}
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 	iovar_buf = kzalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
1171*4882a593Smuzhiyun 	if (!iovar_buf) {
1172*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "iovar_buf alloc failed\n");
1173*4882a593Smuzhiyun 		err = -ENOMEM;
1174*4882a593Smuzhiyun 		goto exit;
1175*4882a593Smuzhiyun 	}
1176*4882a593Smuzhiyun 
1177*4882a593Smuzhiyun 	memset(iovar_buf, 0, WLC_IOCTL_MEDLEN);
1178*4882a593Smuzhiyun 	vndr_ie_tmp.pktflag = (uint32) -1;
1179*4882a593Smuzhiyun 	vndr_ie_tmp.id = (uint8) DOT11_MNG_PROPR_ID;
1180*4882a593Smuzhiyun 	err = wl_ext_iovar_getbuf(dev, "vndr_ie", &vndr_ie_tmp, sizeof(vndr_ie_tmp),
1181*4882a593Smuzhiyun 		iovar_buf, WLC_IOCTL_MEDLEN, NULL);
1182*4882a593Smuzhiyun 	if (err)
1183*4882a593Smuzhiyun 		goto exit;
1184*4882a593Smuzhiyun 
1185*4882a593Smuzhiyun 	vndr_ie_dump = (vndr_ie_buf_t *)iovar_buf;
1186*4882a593Smuzhiyun 	if (!vndr_ie_dump->iecount)
1187*4882a593Smuzhiyun 		goto exit;
1188*4882a593Smuzhiyun 
1189*4882a593Smuzhiyun 	iebuf = (uchar *)&vndr_ie_dump->vndr_ie_list[0];
1190*4882a593Smuzhiyun 	for (i=0; i<vndr_ie_dump->iecount; i++) {
1191*4882a593Smuzhiyun 		ie_info = (vndr_ie_info_t *) iebuf;
1192*4882a593Smuzhiyun 		ie = &ie_info->vndr_ie_data;
1193*4882a593Smuzhiyun 		if (memcmp(ie->oui, oui, 3))
1194*4882a593Smuzhiyun 			memset(ie->oui, 0, 3);
1195*4882a593Smuzhiyun 		iebuf += sizeof(uint32) + ie->len + VNDR_IE_HDR_LEN;
1196*4882a593Smuzhiyun 	}
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun 	vndr_ie = (vndr_ie_setbuf_t *) vndr_ie_buf;
1199*4882a593Smuzhiyun 	strncpy(vndr_ie->cmd, "del", VNDR_IE_CMD_LEN - 1);
1200*4882a593Smuzhiyun 	vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
1201*4882a593Smuzhiyun 	memcpy(&vndr_ie->vndr_ie_buffer, vndr_ie_dump, WLC_IOCTL_SMLEN-VNDR_IE_CMD_LEN-1);
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun 	memset(iovar_buf, 0, WLC_IOCTL_MEDLEN);
1204*4882a593Smuzhiyun 	err = wl_ext_iovar_setbuf(dev, "vndr_ie", vndr_ie, WLC_IOCTL_SMLEN, iovar_buf,
1205*4882a593Smuzhiyun 		WLC_IOCTL_MEDLEN, NULL);
1206*4882a593Smuzhiyun 
1207*4882a593Smuzhiyun exit:
1208*4882a593Smuzhiyun 	if (vndr_ie) {
1209*4882a593Smuzhiyun 		kfree(vndr_ie);
1210*4882a593Smuzhiyun 	}
1211*4882a593Smuzhiyun 	if (iovar_buf) {
1212*4882a593Smuzhiyun 		kfree(iovar_buf);
1213*4882a593Smuzhiyun 	}
1214*4882a593Smuzhiyun 	return err;
1215*4882a593Smuzhiyun }
1216*4882a593Smuzhiyun 
1217*4882a593Smuzhiyun static int
wl_mesh_clear_mesh_info(struct wl_if_info * mesh_if,bool scan)1218*4882a593Smuzhiyun wl_mesh_clear_mesh_info(struct wl_if_info *mesh_if, bool scan)
1219*4882a593Smuzhiyun {
1220*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(mesh_if->dev);
1221*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
1222*4882a593Smuzhiyun 	struct wl_mesh_params *mesh_info = &apsta_params->mesh_info;
1223*4882a593Smuzhiyun 	uchar mesh_oui[]={0x00, 0x22, 0xf4};
1224*4882a593Smuzhiyun 	int ret;
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	IAPSTA_TRACE(mesh_if->dev->name, "Enter\n");
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 	ret = wl_mesh_clear_vndr_ie(mesh_if->dev, mesh_oui);
1229*4882a593Smuzhiyun 	memset(mesh_info, 0, sizeof(struct wl_mesh_params));
1230*4882a593Smuzhiyun 	if (scan) {
1231*4882a593Smuzhiyun 		mesh_info->scan_channel = wl_ext_get_chan(mesh_if->dev,
1232*4882a593Smuzhiyun 			&mesh_if->chan_info);
1233*4882a593Smuzhiyun 		wl_timer_mod(dhd, &mesh_if->delay_scan, 100);
1234*4882a593Smuzhiyun 	}
1235*4882a593Smuzhiyun 
1236*4882a593Smuzhiyun 	return ret;
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun 
1239*4882a593Smuzhiyun static int
wl_mesh_update_vndr_ie(struct wl_apsta_params * apsta_params,struct wl_if_info * mesh_if)1240*4882a593Smuzhiyun wl_mesh_update_vndr_ie(struct wl_apsta_params *apsta_params,
1241*4882a593Smuzhiyun 	struct wl_if_info *mesh_if)
1242*4882a593Smuzhiyun {
1243*4882a593Smuzhiyun 	struct wl_mesh_params *mesh_info = &apsta_params->mesh_info;
1244*4882a593Smuzhiyun 	char *vndr_ie;
1245*4882a593Smuzhiyun 	uchar mesh_oui[]={0x00, 0x22, 0xf4};
1246*4882a593Smuzhiyun 	int bytes_written = 0;
1247*4882a593Smuzhiyun 	int ret = 0, i, vndr_ie_len;
1248*4882a593Smuzhiyun 	uint8 *peer_bssid;
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun 	wl_mesh_clear_vndr_ie(mesh_if->dev, mesh_oui);
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 	vndr_ie_len = WLC_IOCTL_MEDLEN;
1253*4882a593Smuzhiyun 	vndr_ie = kmalloc(vndr_ie_len, GFP_KERNEL);
1254*4882a593Smuzhiyun 	if (vndr_ie == NULL) {
1255*4882a593Smuzhiyun 		IAPSTA_ERROR(mesh_if->dev->name, "Failed to allocate buffer of %d bytes\n",
1256*4882a593Smuzhiyun 			WLC_IOCTL_MEDLEN);
1257*4882a593Smuzhiyun 		ret = -1;
1258*4882a593Smuzhiyun 		goto exit;
1259*4882a593Smuzhiyun 	}
1260*4882a593Smuzhiyun 
1261*4882a593Smuzhiyun 	bytes_written += snprintf(vndr_ie+bytes_written, vndr_ie_len,
1262*4882a593Smuzhiyun 		"0x%02x%02x%02x", mesh_oui[0], mesh_oui[1], mesh_oui[2]);
1263*4882a593Smuzhiyun 
1264*4882a593Smuzhiyun 	bytes_written += snprintf(vndr_ie+bytes_written, vndr_ie_len,
1265*4882a593Smuzhiyun 		"%02x%02x%02x%02x%02x%02x%02x%02x", MESH_INFO_MASTER_BSSID, ETHER_ADDR_LEN,
1266*4882a593Smuzhiyun 		((u8 *)(&mesh_info->master_bssid))[0], ((u8 *)(&mesh_info->master_bssid))[1],
1267*4882a593Smuzhiyun 		((u8 *)(&mesh_info->master_bssid))[2], ((u8 *)(&mesh_info->master_bssid))[3],
1268*4882a593Smuzhiyun 		((u8 *)(&mesh_info->master_bssid))[4], ((u8 *)(&mesh_info->master_bssid))[5]);
1269*4882a593Smuzhiyun 
1270*4882a593Smuzhiyun 	bytes_written += snprintf(vndr_ie+bytes_written, vndr_ie_len,
1271*4882a593Smuzhiyun 		"%02x%02x%02x", MESH_INFO_MASTER_CHANNEL, 1, mesh_info->master_channel);
1272*4882a593Smuzhiyun 
1273*4882a593Smuzhiyun 	bytes_written += snprintf(vndr_ie+bytes_written, vndr_ie_len,
1274*4882a593Smuzhiyun 		"%02x%02x%02x", MESH_INFO_HOP_CNT, 1, mesh_info->hop_cnt);
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun 	bytes_written += snprintf(vndr_ie+bytes_written, vndr_ie_len,
1277*4882a593Smuzhiyun 		"%02x%02x", MESH_INFO_PEER_BSSID, mesh_info->hop_cnt*ETHER_ADDR_LEN);
1278*4882a593Smuzhiyun 	for (i=0; i<mesh_info->hop_cnt && i<MAX_HOP_LIST; i++) {
1279*4882a593Smuzhiyun 		peer_bssid = (uint8 *)&mesh_info->peer_bssid[i];
1280*4882a593Smuzhiyun 		bytes_written += snprintf(vndr_ie+bytes_written, vndr_ie_len,
1281*4882a593Smuzhiyun 			"%02x%02x%02x%02x%02x%02x",
1282*4882a593Smuzhiyun 			peer_bssid[0], peer_bssid[1], peer_bssid[2],
1283*4882a593Smuzhiyun 			peer_bssid[3], peer_bssid[4], peer_bssid[5]);
1284*4882a593Smuzhiyun 	}
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 	ret = wl_ext_add_del_ie(mesh_if->dev, VNDR_IE_BEACON_FLAG|VNDR_IE_PRBRSP_FLAG,
1287*4882a593Smuzhiyun 		vndr_ie, "add");
1288*4882a593Smuzhiyun 	if (!ret) {
1289*4882a593Smuzhiyun 		IAPSTA_INFO(mesh_if->dev->name, "mbssid=%pM, mchannel=%d, hop=%d, pbssid=%pM\n",
1290*4882a593Smuzhiyun 			&mesh_info->master_bssid, mesh_info->master_channel, mesh_info->hop_cnt,
1291*4882a593Smuzhiyun 			mesh_info->peer_bssid);
1292*4882a593Smuzhiyun 	}
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun exit:
1295*4882a593Smuzhiyun 	if (vndr_ie)
1296*4882a593Smuzhiyun 		kfree(vndr_ie);
1297*4882a593Smuzhiyun 	return ret;
1298*4882a593Smuzhiyun }
1299*4882a593Smuzhiyun 
1300*4882a593Smuzhiyun static bool
wl_mesh_update_master_info(struct wl_apsta_params * apsta_params,struct wl_if_info * mesh_if)1301*4882a593Smuzhiyun wl_mesh_update_master_info(struct wl_apsta_params *apsta_params,
1302*4882a593Smuzhiyun 	struct wl_if_info *mesh_if)
1303*4882a593Smuzhiyun {
1304*4882a593Smuzhiyun 	struct wl_mesh_params *mesh_info = &apsta_params->mesh_info;
1305*4882a593Smuzhiyun 	struct wl_if_info *sta_if = NULL;
1306*4882a593Smuzhiyun 	bool updated = FALSE;
1307*4882a593Smuzhiyun 
1308*4882a593Smuzhiyun 	sta_if = wl_ext_if_enabled(apsta_params, ISTA_MODE);
1309*4882a593Smuzhiyun 	if (sta_if) {
1310*4882a593Smuzhiyun 		wldev_ioctl(mesh_if->dev, WLC_GET_BSSID, &mesh_info->master_bssid,
1311*4882a593Smuzhiyun 			ETHER_ADDR_LEN, 0);
1312*4882a593Smuzhiyun 		mesh_info->master_channel = wl_ext_get_chan(mesh_if->dev, &mesh_if->chan_info);
1313*4882a593Smuzhiyun 		mesh_info->hop_cnt = 0;
1314*4882a593Smuzhiyun 		memset(mesh_info->peer_bssid, 0, MAX_HOP_LIST*ETHER_ADDR_LEN);
1315*4882a593Smuzhiyun 		if (!wl_mesh_update_vndr_ie(apsta_params, mesh_if))
1316*4882a593Smuzhiyun 			updated = TRUE;
1317*4882a593Smuzhiyun 	}
1318*4882a593Smuzhiyun 
1319*4882a593Smuzhiyun 	return updated;
1320*4882a593Smuzhiyun }
1321*4882a593Smuzhiyun 
1322*4882a593Smuzhiyun static bool
wl_mesh_update_mesh_info(struct wl_apsta_params * apsta_params,struct wl_if_info * mesh_if)1323*4882a593Smuzhiyun wl_mesh_update_mesh_info(struct wl_apsta_params *apsta_params,
1324*4882a593Smuzhiyun 	struct wl_if_info *mesh_if)
1325*4882a593Smuzhiyun {
1326*4882a593Smuzhiyun 	struct wl_mesh_params *mesh_info = &apsta_params->mesh_info, peer_mesh_info;
1327*4882a593Smuzhiyun 	uint32 count = 0;
1328*4882a593Smuzhiyun 	char *dump_buf = NULL;
1329*4882a593Smuzhiyun 	mesh_peer_info_dump_t *peer_results;
1330*4882a593Smuzhiyun 	mesh_peer_info_ext_t *mpi_ext;
1331*4882a593Smuzhiyun 	struct ether_addr bssid;
1332*4882a593Smuzhiyun 	bool updated = FALSE, bss_found = FALSE;
1333*4882a593Smuzhiyun 	uint16 cur_chan;
1334*4882a593Smuzhiyun 
1335*4882a593Smuzhiyun 	dump_buf = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
1336*4882a593Smuzhiyun 	if (dump_buf == NULL) {
1337*4882a593Smuzhiyun 		IAPSTA_ERROR(mesh_if->dev->name, "Failed to allocate buffer of %d bytes\n",
1338*4882a593Smuzhiyun 			WLC_IOCTL_MAXLEN);
1339*4882a593Smuzhiyun 		return FALSE;
1340*4882a593Smuzhiyun 	}
1341*4882a593Smuzhiyun 	count = wl_mesh_get_peer_results(mesh_if->dev, dump_buf, WLC_IOCTL_MAXLEN);
1342*4882a593Smuzhiyun 	if (count > 0) {
1343*4882a593Smuzhiyun 		memset(&bssid, 0, ETHER_ADDR_LEN);
1344*4882a593Smuzhiyun 		wldev_ioctl(mesh_if->dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, 0);
1345*4882a593Smuzhiyun 		peer_results = (mesh_peer_info_dump_t *)dump_buf;
1346*4882a593Smuzhiyun 		mpi_ext = (mesh_peer_info_ext_t *)peer_results->mpi_ext;
1347*4882a593Smuzhiyun 		for (count = 0; count < peer_results->count; count++) {
1348*4882a593Smuzhiyun 			if (mpi_ext->entry_state != MESH_SELF_PEER_ENTRY_STATE_TIMEDOUT &&
1349*4882a593Smuzhiyun 					mpi_ext->peer_info.state == MESH_PEERING_ESTAB) {
1350*4882a593Smuzhiyun 				memset(&peer_mesh_info, 0, sizeof(struct wl_mesh_params));
1351*4882a593Smuzhiyun 				bss_found = wl_escan_mesh_info(mesh_if->dev, mesh_if->escan,
1352*4882a593Smuzhiyun 					&mpi_ext->ea, &peer_mesh_info);
1353*4882a593Smuzhiyun 				if (bss_found && (mesh_info->master_channel == 0 ||
1354*4882a593Smuzhiyun 						peer_mesh_info.hop_cnt <= mesh_info->hop_cnt) &&
1355*4882a593Smuzhiyun 						memcmp(&peer_mesh_info.peer_bssid, &bssid, ETHER_ADDR_LEN)) {
1356*4882a593Smuzhiyun 					memcpy(&mesh_info->master_bssid, &peer_mesh_info.master_bssid,
1357*4882a593Smuzhiyun 						ETHER_ADDR_LEN);
1358*4882a593Smuzhiyun 					mesh_info->master_channel = peer_mesh_info.master_channel;
1359*4882a593Smuzhiyun 					mesh_info->hop_cnt = peer_mesh_info.hop_cnt+1;
1360*4882a593Smuzhiyun 					memset(mesh_info->peer_bssid, 0, MAX_HOP_LIST*ETHER_ADDR_LEN);
1361*4882a593Smuzhiyun 					memcpy(&mesh_info->peer_bssid, &mpi_ext->ea, ETHER_ADDR_LEN);
1362*4882a593Smuzhiyun 					memcpy(&mesh_info->peer_bssid[1], peer_mesh_info.peer_bssid,
1363*4882a593Smuzhiyun 						(MAX_HOP_LIST-1)*ETHER_ADDR_LEN);
1364*4882a593Smuzhiyun 					updated = TRUE;
1365*4882a593Smuzhiyun 				}
1366*4882a593Smuzhiyun 			}
1367*4882a593Smuzhiyun 			mpi_ext++;
1368*4882a593Smuzhiyun 		}
1369*4882a593Smuzhiyun 		if (updated) {
1370*4882a593Smuzhiyun 			if (wl_mesh_update_vndr_ie(apsta_params, mesh_if)) {
1371*4882a593Smuzhiyun 				IAPSTA_ERROR(mesh_if->dev->name, "update failed\n");
1372*4882a593Smuzhiyun 				mesh_info->master_channel = 0;
1373*4882a593Smuzhiyun 				updated = FALSE;
1374*4882a593Smuzhiyun 				goto exit;
1375*4882a593Smuzhiyun 			}
1376*4882a593Smuzhiyun 		}
1377*4882a593Smuzhiyun 	}
1378*4882a593Smuzhiyun 
1379*4882a593Smuzhiyun 	if (!mesh_info->master_channel) {
1380*4882a593Smuzhiyun 		wlc_ssid_t cur_ssid;
1381*4882a593Smuzhiyun 		char sec[64];
1382*4882a593Smuzhiyun 		bool sae = FALSE;
1383*4882a593Smuzhiyun 		memset(&peer_mesh_info, 0, sizeof(struct wl_mesh_params));
1384*4882a593Smuzhiyun 		wl_ext_ioctl(mesh_if->dev, WLC_GET_SSID, &cur_ssid, sizeof(cur_ssid), 0);
1385*4882a593Smuzhiyun 		wl_ext_get_sec(mesh_if->dev, mesh_if->ifmode, sec, sizeof(sec), FALSE);
1386*4882a593Smuzhiyun 		if (strnicmp(sec, "sae/sae", strlen("sae/sae")) == 0)
1387*4882a593Smuzhiyun 			sae = TRUE;
1388*4882a593Smuzhiyun 		cur_chan = wl_ext_get_chan(mesh_if->dev, &mesh_if->chan_info);
1389*4882a593Smuzhiyun 		bss_found = wl_escan_mesh_peer(mesh_if->dev, mesh_if->escan, &cur_ssid, cur_chan,
1390*4882a593Smuzhiyun 			sae, &peer_mesh_info);
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun 		if (bss_found && peer_mesh_info.master_channel&&
1393*4882a593Smuzhiyun 				(cur_chan != peer_mesh_info.master_channel)) {
1394*4882a593Smuzhiyun 			WL_MSG(mesh_if->ifname, "moving channel %d -> %d\n",
1395*4882a593Smuzhiyun 				cur_chan, peer_mesh_info.master_channel);
1396*4882a593Smuzhiyun 			wl_ext_disable_iface(mesh_if->dev, mesh_if->ifname);
1397*4882a593Smuzhiyun 			mesh_if->channel = peer_mesh_info.master_channel;
1398*4882a593Smuzhiyun 			wl_ext_enable_iface(mesh_if->dev, mesh_if->ifname, 500, TRUE);
1399*4882a593Smuzhiyun 		}
1400*4882a593Smuzhiyun 	}
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun exit:
1403*4882a593Smuzhiyun 	if (dump_buf)
1404*4882a593Smuzhiyun 		kfree(dump_buf);
1405*4882a593Smuzhiyun 	return updated;
1406*4882a593Smuzhiyun }
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun static void
wl_mesh_event_handler(struct wl_if_info * cur_if,const wl_event_msg_t * e,void * data)1409*4882a593Smuzhiyun wl_mesh_event_handler(struct wl_if_info *cur_if,
1410*4882a593Smuzhiyun 	const wl_event_msg_t *e, void *data)
1411*4882a593Smuzhiyun {
1412*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
1413*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
1414*4882a593Smuzhiyun 	struct wl_mesh_params *mesh_info = &apsta_params->mesh_info;
1415*4882a593Smuzhiyun 	uint32 event_type = ntoh32(e->event_type);
1416*4882a593Smuzhiyun 	uint32 status = ntoh32(e->status);
1417*4882a593Smuzhiyun 	uint32 reason = ntoh32(e->reason);
1418*4882a593Smuzhiyun 	uint16 flags =  ntoh16(e->flags);
1419*4882a593Smuzhiyun 	struct wl_if_info *mesh_if = NULL, *tmp_if = NULL;
1420*4882a593Smuzhiyun 	int ret, i;
1421*4882a593Smuzhiyun 
1422*4882a593Smuzhiyun 	if (cur_if->ifmode == IMESH_MODE)
1423*4882a593Smuzhiyun 		mesh_if = cur_if;
1424*4882a593Smuzhiyun 	else {
1425*4882a593Smuzhiyun 		for (i=0; i<MAX_IF_NUM; i++) {
1426*4882a593Smuzhiyun 			tmp_if = &apsta_params->if_info[i];
1427*4882a593Smuzhiyun 			if (tmp_if->dev && tmp_if->ifmode == IMESH_MODE) {
1428*4882a593Smuzhiyun 				mesh_if = tmp_if;
1429*4882a593Smuzhiyun 				break;
1430*4882a593Smuzhiyun 			}
1431*4882a593Smuzhiyun 		}
1432*4882a593Smuzhiyun 	}
1433*4882a593Smuzhiyun 
1434*4882a593Smuzhiyun 	if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) {
1435*4882a593Smuzhiyun 		if (event_type == WLC_E_LINK) {
1436*4882a593Smuzhiyun 			if (!(flags & WLC_EVENT_MSG_LINK)) {
1437*4882a593Smuzhiyun 				if (mesh_if && apsta_params->macs)
1438*4882a593Smuzhiyun 					wl_mesh_clear_mesh_info(mesh_if, TRUE);
1439*4882a593Smuzhiyun 			} else {
1440*4882a593Smuzhiyun 				if (mesh_if && apsta_params->macs)
1441*4882a593Smuzhiyun 					wl_mesh_update_master_info(apsta_params, mesh_if);
1442*4882a593Smuzhiyun 			}
1443*4882a593Smuzhiyun 		}
1444*4882a593Smuzhiyun 		else if (event_type == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) {
1445*4882a593Smuzhiyun 			if (mesh_if && apsta_params->macs)
1446*4882a593Smuzhiyun 				wl_mesh_clear_mesh_info(mesh_if, TRUE);
1447*4882a593Smuzhiyun 		}
1448*4882a593Smuzhiyun 		else if (event_type == WLC_E_DEAUTH || event_type == WLC_E_DEAUTH_IND ||
1449*4882a593Smuzhiyun 				event_type == WLC_E_DISASSOC || event_type == WLC_E_DISASSOC_IND) {
1450*4882a593Smuzhiyun 			if (mesh_if && apsta_params->macs)
1451*4882a593Smuzhiyun 				wl_mesh_clear_mesh_info(mesh_if, TRUE);
1452*4882a593Smuzhiyun 		}
1453*4882a593Smuzhiyun 	}
1454*4882a593Smuzhiyun 	else if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) {
1455*4882a593Smuzhiyun 		if (wl_get_isam_status(mesh_if, AP_CREATED) &&
1456*4882a593Smuzhiyun 				((event_type == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
1457*4882a593Smuzhiyun 				(event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
1458*4882a593Smuzhiyun 				reason == WLC_E_REASON_INITIAL_ASSOC))) {
1459*4882a593Smuzhiyun 			if (!wl_mesh_update_master_info(apsta_params, mesh_if)) {
1460*4882a593Smuzhiyun 				mesh_info->scan_channel = wl_ext_get_chan(&mesh_if->dev,
1461*4882a593Smuzhiyun 					mesh_if->chan_info);
1462*4882a593Smuzhiyun 				wl_timer_mod(dhd, &mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO);
1463*4882a593Smuzhiyun 			}
1464*4882a593Smuzhiyun 		}
1465*4882a593Smuzhiyun 		else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) ||
1466*4882a593Smuzhiyun 				(event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
1467*4882a593Smuzhiyun 				reason == WLC_E_REASON_DEAUTH)) {
1468*4882a593Smuzhiyun 			wl_mesh_clear_mesh_info(mesh_if, FALSE);
1469*4882a593Smuzhiyun 		}
1470*4882a593Smuzhiyun 		else if (wl_get_isam_status(mesh_if, AP_CREATED) &&
1471*4882a593Smuzhiyun 				(event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) &&
1472*4882a593Smuzhiyun 				reason == DOT11_SC_SUCCESS) {
1473*4882a593Smuzhiyun 			mesh_info->scan_channel = wl_ext_get_chan(mesh_if->dev,
1474*4882a593Smuzhiyun 				&mesh_if->chan_info);
1475*4882a593Smuzhiyun 			wl_timer_mod(dhd, &mesh_if->delay_scan, 100);
1476*4882a593Smuzhiyun 		}
1477*4882a593Smuzhiyun 		else if (event_type == WLC_E_DISASSOC_IND || event_type == WLC_E_DEAUTH_IND ||
1478*4882a593Smuzhiyun 				(event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) {
1479*4882a593Smuzhiyun 			if (!memcmp(&mesh_info->peer_bssid, &e->addr, ETHER_ADDR_LEN))
1480*4882a593Smuzhiyun 				wl_mesh_clear_mesh_info(mesh_if, TRUE);
1481*4882a593Smuzhiyun 		}
1482*4882a593Smuzhiyun 		else if (wl_get_isam_status(mesh_if, AP_CREATED) &&
1483*4882a593Smuzhiyun 				event_type == WLC_E_RESERVED && reason == ISAM_RC_MESH_ACS) {
1484*4882a593Smuzhiyun 			if (!wl_mesh_update_master_info(apsta_params, mesh_if)) {
1485*4882a593Smuzhiyun 				wl_scan_info_t scan_info;
1486*4882a593Smuzhiyun 				memset(&scan_info, 0, sizeof(wl_scan_info_t));
1487*4882a593Smuzhiyun 				wl_ext_ioctl(mesh_if->dev, WLC_GET_SSID, &scan_info.ssid, sizeof(wlc_ssid_t), 0);
1488*4882a593Smuzhiyun 				if (mesh_info->scan_channel) {
1489*4882a593Smuzhiyun 					scan_info.channels.count = 1;
1490*4882a593Smuzhiyun 					scan_info.channels.channel[0] = mesh_info->scan_channel;
1491*4882a593Smuzhiyun 				}
1492*4882a593Smuzhiyun 				ret = wl_escan_set_scan(mesh_if->dev, &scan_info);
1493*4882a593Smuzhiyun 				if (ret)
1494*4882a593Smuzhiyun 					wl_timer_mod(dhd, &mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO);
1495*4882a593Smuzhiyun 			}
1496*4882a593Smuzhiyun 		}
1497*4882a593Smuzhiyun 		else if (wl_get_isam_status(mesh_if, AP_CREATED) &&
1498*4882a593Smuzhiyun 				((event_type == WLC_E_ESCAN_RESULT && status == WLC_E_STATUS_SUCCESS) ||
1499*4882a593Smuzhiyun 				(event_type == WLC_E_ESCAN_RESULT &&
1500*4882a593Smuzhiyun 				(status == WLC_E_STATUS_ABORT || status == WLC_E_STATUS_NEWSCAN ||
1501*4882a593Smuzhiyun 				status == WLC_E_STATUS_11HQUIET || status == WLC_E_STATUS_CS_ABORT ||
1502*4882a593Smuzhiyun 				status == WLC_E_STATUS_NEWASSOC || status == WLC_E_STATUS_TIMEOUT)))) {
1503*4882a593Smuzhiyun 			if (!wl_mesh_update_master_info(apsta_params, mesh_if)) {
1504*4882a593Smuzhiyun 				if (!wl_mesh_update_mesh_info(apsta_params, mesh_if)) {
1505*4882a593Smuzhiyun 					mesh_info->scan_channel = 0;
1506*4882a593Smuzhiyun 					wl_timer_mod(dhd, &mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO);
1507*4882a593Smuzhiyun 				}
1508*4882a593Smuzhiyun 			}
1509*4882a593Smuzhiyun 		}
1510*4882a593Smuzhiyun 	}
1511*4882a593Smuzhiyun }
1512*4882a593Smuzhiyun 
1513*4882a593Smuzhiyun static void
wl_mesh_escan_detach(dhd_pub_t * dhd,struct wl_if_info * mesh_if)1514*4882a593Smuzhiyun wl_mesh_escan_detach(dhd_pub_t *dhd, struct wl_if_info *mesh_if)
1515*4882a593Smuzhiyun {
1516*4882a593Smuzhiyun 	IAPSTA_TRACE(mesh_if->dev->name, "Enter\n");
1517*4882a593Smuzhiyun 	wl_timer_deregister(mesh_if->dev, &mesh_if->delay_scan);
1518*4882a593Smuzhiyun 	if (mesh_if->escan) {
1519*4882a593Smuzhiyun 		mesh_if->escan = NULL;
1520*4882a593Smuzhiyun 	}
1521*4882a593Smuzhiyun }
1522*4882a593Smuzhiyun 
1523*4882a593Smuzhiyun static int
wl_mesh_escan_attach(dhd_pub_t * dhd,struct wl_if_info * mesh_if)1524*4882a593Smuzhiyun wl_mesh_escan_attach(dhd_pub_t *dhd, struct wl_if_info *mesh_if)
1525*4882a593Smuzhiyun {
1526*4882a593Smuzhiyun 	IAPSTA_TRACE(mesh_if->dev->name, "Enter\n");
1527*4882a593Smuzhiyun 
1528*4882a593Smuzhiyun 	mesh_if->escan = dhd->escan;
1529*4882a593Smuzhiyun 	wl_timer_register(mesh_if->dev, &mesh_if->delay_scan, wl_mesh_timer);
1530*4882a593Smuzhiyun 
1531*4882a593Smuzhiyun 	return 0;
1532*4882a593Smuzhiyun }
1533*4882a593Smuzhiyun 
1534*4882a593Smuzhiyun static uint
wl_mesh_update_peer_path(struct wl_if_info * mesh_if,char * command,int total_len)1535*4882a593Smuzhiyun wl_mesh_update_peer_path(struct wl_if_info *mesh_if, char *command,
1536*4882a593Smuzhiyun 	int total_len)
1537*4882a593Smuzhiyun {
1538*4882a593Smuzhiyun 	struct wl_mesh_params peer_mesh_info;
1539*4882a593Smuzhiyun 	uint32 count = 0;
1540*4882a593Smuzhiyun 	char *dump_buf = NULL;
1541*4882a593Smuzhiyun 	mesh_peer_info_dump_t *peer_results;
1542*4882a593Smuzhiyun 	mesh_peer_info_ext_t *mpi_ext;
1543*4882a593Smuzhiyun 	int bytes_written = 0, j, k;
1544*4882a593Smuzhiyun 	bool bss_found = FALSE;
1545*4882a593Smuzhiyun 
1546*4882a593Smuzhiyun 	dump_buf = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
1547*4882a593Smuzhiyun 	if (dump_buf == NULL) {
1548*4882a593Smuzhiyun 		IAPSTA_ERROR(mesh_if->dev->name, "Failed to allocate buffer of %d bytes\n",
1549*4882a593Smuzhiyun 			WLC_IOCTL_MAXLEN);
1550*4882a593Smuzhiyun 		return FALSE;
1551*4882a593Smuzhiyun 	}
1552*4882a593Smuzhiyun 	count = wl_mesh_get_peer_results(mesh_if->dev, dump_buf, WLC_IOCTL_MAXLEN);
1553*4882a593Smuzhiyun 	if (count > 0) {
1554*4882a593Smuzhiyun 		peer_results = (mesh_peer_info_dump_t *)dump_buf;
1555*4882a593Smuzhiyun 		mpi_ext = (mesh_peer_info_ext_t *)peer_results->mpi_ext;
1556*4882a593Smuzhiyun 		for (count = 0; count < peer_results->count; count++) {
1557*4882a593Smuzhiyun 			if (mpi_ext->entry_state != MESH_SELF_PEER_ENTRY_STATE_TIMEDOUT &&
1558*4882a593Smuzhiyun 					mpi_ext->peer_info.state == MESH_PEERING_ESTAB) {
1559*4882a593Smuzhiyun 				memset(&peer_mesh_info, 0, sizeof(struct wl_mesh_params));
1560*4882a593Smuzhiyun 				bss_found = wl_escan_mesh_info(mesh_if->dev, mesh_if->escan,
1561*4882a593Smuzhiyun 					&mpi_ext->ea, &peer_mesh_info);
1562*4882a593Smuzhiyun 				if (bss_found) {
1563*4882a593Smuzhiyun 					bytes_written += snprintf(command+bytes_written, total_len,
1564*4882a593Smuzhiyun 						"\npeer=%pM, hop=%d",
1565*4882a593Smuzhiyun 						&mpi_ext->ea, peer_mesh_info.hop_cnt);
1566*4882a593Smuzhiyun 					for (j=1; j<peer_mesh_info.hop_cnt; j++) {
1567*4882a593Smuzhiyun 						bytes_written += snprintf(command+bytes_written,
1568*4882a593Smuzhiyun 							total_len, "\n");
1569*4882a593Smuzhiyun 						for (k=0; k<j; k++) {
1570*4882a593Smuzhiyun 							bytes_written += snprintf(command+bytes_written,
1571*4882a593Smuzhiyun 								total_len, " ");
1572*4882a593Smuzhiyun 						}
1573*4882a593Smuzhiyun 						bytes_written += snprintf(command+bytes_written, total_len,
1574*4882a593Smuzhiyun 							"%pM", &peer_mesh_info.peer_bssid[j]);
1575*4882a593Smuzhiyun 					}
1576*4882a593Smuzhiyun 				}
1577*4882a593Smuzhiyun 			}
1578*4882a593Smuzhiyun 			mpi_ext++;
1579*4882a593Smuzhiyun 		}
1580*4882a593Smuzhiyun 	}
1581*4882a593Smuzhiyun 
1582*4882a593Smuzhiyun 	if (dump_buf)
1583*4882a593Smuzhiyun 		kfree(dump_buf);
1584*4882a593Smuzhiyun 	return bytes_written;
1585*4882a593Smuzhiyun }
1586*4882a593Smuzhiyun 
1587*4882a593Smuzhiyun int
wl_ext_isam_peer_path(struct net_device * dev,char * command,int total_len)1588*4882a593Smuzhiyun wl_ext_isam_peer_path(struct net_device *dev, char *command, int total_len)
1589*4882a593Smuzhiyun {
1590*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
1591*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
1592*4882a593Smuzhiyun 	struct wl_mesh_params *mesh_info = &apsta_params->mesh_info;
1593*4882a593Smuzhiyun 	struct wl_if_info *tmp_if;
1594*4882a593Smuzhiyun 	char *dump_buf = NULL;
1595*4882a593Smuzhiyun 	int dump_len = WLC_IOCTL_MEDLEN;
1596*4882a593Smuzhiyun 	int dump_written = 0;
1597*4882a593Smuzhiyun 	int i;
1598*4882a593Smuzhiyun 
1599*4882a593Smuzhiyun 	if (command || android_msg_level & ANDROID_INFO_LEVEL) {
1600*4882a593Smuzhiyun 		if (command) {
1601*4882a593Smuzhiyun 			dump_buf = command;
1602*4882a593Smuzhiyun 			dump_len = total_len;
1603*4882a593Smuzhiyun 		} else {
1604*4882a593Smuzhiyun 			dump_buf = kmalloc(dump_len, GFP_KERNEL);
1605*4882a593Smuzhiyun 			if (dump_buf == NULL) {
1606*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n",
1607*4882a593Smuzhiyun 					dump_len);
1608*4882a593Smuzhiyun 				return -1;
1609*4882a593Smuzhiyun 			}
1610*4882a593Smuzhiyun 		}
1611*4882a593Smuzhiyun 		for (i=0; i<MAX_IF_NUM; i++) {
1612*4882a593Smuzhiyun 			tmp_if = &apsta_params->if_info[i];
1613*4882a593Smuzhiyun 			if (tmp_if->dev && tmp_if->ifmode == IMESH_MODE && apsta_params->macs) {
1614*4882a593Smuzhiyun 				if (wl_ext_associated(tmp_if->dev)) {
1615*4882a593Smuzhiyun 					dump_written += snprintf(dump_buf+dump_written, dump_len,
1616*4882a593Smuzhiyun 						DHD_LOG_PREFIXS "[%s-%c] mbssid=%pM, mchan=%d, hop=%d, pbssid=%pM",
1617*4882a593Smuzhiyun 						tmp_if->ifname, tmp_if->prefix, &mesh_info->master_bssid,
1618*4882a593Smuzhiyun 						mesh_info->master_channel, mesh_info->hop_cnt,
1619*4882a593Smuzhiyun 						&mesh_info->peer_bssid);
1620*4882a593Smuzhiyun 					dump_written += wl_mesh_update_peer_path(tmp_if,
1621*4882a593Smuzhiyun 						dump_buf+dump_written, dump_len-dump_written);
1622*4882a593Smuzhiyun 				}
1623*4882a593Smuzhiyun 			}
1624*4882a593Smuzhiyun 		}
1625*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "%s\n", dump_buf);
1626*4882a593Smuzhiyun 	}
1627*4882a593Smuzhiyun 
1628*4882a593Smuzhiyun 	if (!command && dump_buf)
1629*4882a593Smuzhiyun 		kfree(dump_buf);
1630*4882a593Smuzhiyun 	return dump_written;
1631*4882a593Smuzhiyun }
1632*4882a593Smuzhiyun #endif /* WL_ESCAN */
1633*4882a593Smuzhiyun #endif /* WLMESH */
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun static bool
wl_ext_master_if(struct wl_if_info * cur_if)1636*4882a593Smuzhiyun wl_ext_master_if(struct wl_if_info *cur_if)
1637*4882a593Smuzhiyun {
1638*4882a593Smuzhiyun 	if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE)
1639*4882a593Smuzhiyun 		return TRUE;
1640*4882a593Smuzhiyun 	else
1641*4882a593Smuzhiyun 		return FALSE;
1642*4882a593Smuzhiyun }
1643*4882a593Smuzhiyun 
1644*4882a593Smuzhiyun static int
wl_ext_if_down(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)1645*4882a593Smuzhiyun wl_ext_if_down(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
1646*4882a593Smuzhiyun {
1647*4882a593Smuzhiyun 	s8 iovar_buf[WLC_IOCTL_SMLEN];
1648*4882a593Smuzhiyun 	scb_val_t scbval;
1649*4882a593Smuzhiyun 	struct {
1650*4882a593Smuzhiyun 		s32 cfg;
1651*4882a593Smuzhiyun 		s32 val;
1652*4882a593Smuzhiyun 	} bss_setbuf;
1653*4882a593Smuzhiyun 	apstamode_t apstamode = apsta_params->apstamode;
1654*4882a593Smuzhiyun 
1655*4882a593Smuzhiyun 	WL_MSG(cur_if->ifname, "[%c] Turning off...\n", cur_if->prefix);
1656*4882a593Smuzhiyun 
1657*4882a593Smuzhiyun 	if (cur_if->ifmode == ISTA_MODE) {
1658*4882a593Smuzhiyun 		wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
1659*4882a593Smuzhiyun 		return 0;
1660*4882a593Smuzhiyun 	} else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
1661*4882a593Smuzhiyun 		// deauthenticate all STA first
1662*4882a593Smuzhiyun 		memcpy(scbval.ea.octet, &ether_bcast, ETHER_ADDR_LEN);
1663*4882a593Smuzhiyun 		wl_ext_ioctl(cur_if->dev, WLC_SCB_DEAUTHENTICATE, &scbval.ea, ETHER_ADDR_LEN, 1);
1664*4882a593Smuzhiyun 	}
1665*4882a593Smuzhiyun 
1666*4882a593Smuzhiyun 	if (apstamode == IAPONLY_MODE || apstamode == IMESHONLY_MODE) {
1667*4882a593Smuzhiyun 		wl_ext_ioctl(cur_if->dev, WLC_DOWN, NULL, 0, 1);
1668*4882a593Smuzhiyun 	} else {
1669*4882a593Smuzhiyun 		bss_setbuf.cfg = 0xffffffff;
1670*4882a593Smuzhiyun 		bss_setbuf.val = htod32(0);
1671*4882a593Smuzhiyun 		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
1672*4882a593Smuzhiyun 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
1673*4882a593Smuzhiyun 	}
1674*4882a593Smuzhiyun 	wl_clr_isam_status(cur_if, AP_CREATED);
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun 	return 0;
1677*4882a593Smuzhiyun }
1678*4882a593Smuzhiyun 
1679*4882a593Smuzhiyun static int
wl_ext_if_up(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if,bool force_enable,int wait_up)1680*4882a593Smuzhiyun wl_ext_if_up(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if,
1681*4882a593Smuzhiyun 	bool force_enable, int wait_up)
1682*4882a593Smuzhiyun {
1683*4882a593Smuzhiyun 	struct wl_chan_info *chan_info = &cur_if->chan_info;
1684*4882a593Smuzhiyun 	s8 iovar_buf[WLC_IOCTL_SMLEN];
1685*4882a593Smuzhiyun 	struct {
1686*4882a593Smuzhiyun 		s32 cfg;
1687*4882a593Smuzhiyun 		s32 val;
1688*4882a593Smuzhiyun 	} bss_setbuf;
1689*4882a593Smuzhiyun 	apstamode_t apstamode = apsta_params->apstamode;
1690*4882a593Smuzhiyun 	chanspec_t fw_chspec;
1691*4882a593Smuzhiyun 	u32 timeout;
1692*4882a593Smuzhiyun 	wlc_ssid_t ssid = { 0, {0} };
1693*4882a593Smuzhiyun 	uint32 chanspec = 0;
1694*4882a593Smuzhiyun 
1695*4882a593Smuzhiyun 	if (cur_if->ifmode != IAP_MODE && cur_if->ifmode != IGO_MODE) {
1696*4882a593Smuzhiyun 		IAPSTA_ERROR(cur_if->ifname, "Wrong ifmode\n");
1697*4882a593Smuzhiyun 		return 0;
1698*4882a593Smuzhiyun 	}
1699*4882a593Smuzhiyun 
1700*4882a593Smuzhiyun 	if (wl_ext_dfs_chan(chan_info) && !apsta_params->radar && !force_enable) {
1701*4882a593Smuzhiyun 		WL_MSG(cur_if->ifname, "[%c] skip DFS channel %d\n",
1702*4882a593Smuzhiyun 			cur_if->prefix, chan_info->chan);
1703*4882a593Smuzhiyun 		return 0;
1704*4882a593Smuzhiyun 	} else if (wl_ext_passive_chan(cur_if->dev, chan_info)) {
1705*4882a593Smuzhiyun 		WL_MSG(cur_if->ifname, "[%c] skip PASSIVE channel %d\n",
1706*4882a593Smuzhiyun 			cur_if->prefix, chan_info->chan);
1707*4882a593Smuzhiyun 		return 0;
1708*4882a593Smuzhiyun 	} else if (!chan_info->chan) {
1709*4882a593Smuzhiyun 		WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix);
1710*4882a593Smuzhiyun 		return 0;
1711*4882a593Smuzhiyun 	}
1712*4882a593Smuzhiyun 
1713*4882a593Smuzhiyun 	WL_MSG(cur_if->ifname, "[%c] Turning on...\n", cur_if->prefix);
1714*4882a593Smuzhiyun 
1715*4882a593Smuzhiyun 	wl_ext_set_chanspec(cur_if->dev, chan_info, &fw_chspec);
1716*4882a593Smuzhiyun 
1717*4882a593Smuzhiyun 	wl_clr_isam_status(cur_if, AP_CREATED);
1718*4882a593Smuzhiyun 	wl_set_isam_status(cur_if, AP_CREATING);
1719*4882a593Smuzhiyun 	if (apstamode == IAPONLY_MODE) {
1720*4882a593Smuzhiyun 		wl_ext_ioctl(cur_if->dev, WLC_UP, NULL, 0, 1);
1721*4882a593Smuzhiyun 	} else {
1722*4882a593Smuzhiyun 		bss_setbuf.cfg = 0xffffffff;
1723*4882a593Smuzhiyun 		bss_setbuf.val = htod32(1);
1724*4882a593Smuzhiyun 		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf,
1725*4882a593Smuzhiyun 			sizeof(bss_setbuf), iovar_buf, WLC_IOCTL_SMLEN, NULL);
1726*4882a593Smuzhiyun 	}
1727*4882a593Smuzhiyun 
1728*4882a593Smuzhiyun 	if (wait_up) {
1729*4882a593Smuzhiyun 		OSL_SLEEP(wait_up);
1730*4882a593Smuzhiyun 	} else {
1731*4882a593Smuzhiyun 		timeout = wait_event_interruptible_timeout(apsta_params->netif_change_event,
1732*4882a593Smuzhiyun 			wl_get_isam_status(cur_if, AP_CREATED),
1733*4882a593Smuzhiyun 			msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
1734*4882a593Smuzhiyun 		if (timeout <= 0 || !wl_get_isam_status(cur_if, AP_CREATED)) {
1735*4882a593Smuzhiyun 			wl_ext_if_down(apsta_params, cur_if);
1736*4882a593Smuzhiyun 			WL_MSG(cur_if->ifname, "[%c] failed to up with SSID: \"%s\"\n",
1737*4882a593Smuzhiyun 				cur_if->prefix, cur_if->ssid);
1738*4882a593Smuzhiyun 		}
1739*4882a593Smuzhiyun 	}
1740*4882a593Smuzhiyun 
1741*4882a593Smuzhiyun 	wl_ext_ioctl(cur_if->dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0);
1742*4882a593Smuzhiyun 	chanspec = wl_ext_get_chanspec(cur_if->dev, chan_info);
1743*4882a593Smuzhiyun 	WL_MSG(cur_if->ifname, "[%c] enabled with SSID: \"%s\" on channel %s-%d(0x%x)\n",
1744*4882a593Smuzhiyun 		cur_if->prefix, ssid.SSID, CHSPEC2BANDSTR(chanspec),
1745*4882a593Smuzhiyun 		chan_info->chan, chanspec);
1746*4882a593Smuzhiyun 
1747*4882a593Smuzhiyun 	wl_clr_isam_status(cur_if, AP_CREATING);
1748*4882a593Smuzhiyun 
1749*4882a593Smuzhiyun 	wl_ext_isam_status(cur_if->dev, NULL, 0);
1750*4882a593Smuzhiyun 
1751*4882a593Smuzhiyun 	return 0;
1752*4882a593Smuzhiyun }
1753*4882a593Smuzhiyun 
1754*4882a593Smuzhiyun static bool
wl_ext_same_chan(struct wl_chan_info * chan_info_1,struct wl_chan_info * chan_info_2)1755*4882a593Smuzhiyun wl_ext_same_chan(struct wl_chan_info *chan_info_1,
1756*4882a593Smuzhiyun 	struct wl_chan_info *chan_info_2)
1757*4882a593Smuzhiyun {
1758*4882a593Smuzhiyun 	if (chan_info_1->band == chan_info_2->band &&
1759*4882a593Smuzhiyun 			chan_info_1->chan == chan_info_2->chan) {
1760*4882a593Smuzhiyun 		return TRUE;
1761*4882a593Smuzhiyun 	}
1762*4882a593Smuzhiyun 	return FALSE;
1763*4882a593Smuzhiyun }
1764*4882a593Smuzhiyun 
1765*4882a593Smuzhiyun static bool
wl_ext_rsdb_band(uint band_1,uint band_2)1766*4882a593Smuzhiyun wl_ext_rsdb_band(uint band_1, uint band_2)
1767*4882a593Smuzhiyun {
1768*4882a593Smuzhiyun 	if ((band_1 == WLC_BAND_2G && band_2 != WLC_BAND_2G) ||
1769*4882a593Smuzhiyun 		(band_2 == WLC_BAND_2G && band_1 != WLC_BAND_2G)) {
1770*4882a593Smuzhiyun 		return TRUE;
1771*4882a593Smuzhiyun 	}
1772*4882a593Smuzhiyun 	return FALSE;
1773*4882a593Smuzhiyun }
1774*4882a593Smuzhiyun 
1775*4882a593Smuzhiyun static uint16
wl_ext_get_same_band_chan(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if,bool nodfs)1776*4882a593Smuzhiyun wl_ext_get_same_band_chan(struct wl_apsta_params *apsta_params,
1777*4882a593Smuzhiyun 	struct wl_if_info *cur_if, bool nodfs)
1778*4882a593Smuzhiyun {
1779*4882a593Smuzhiyun 	struct wl_if_info *tmp_if;
1780*4882a593Smuzhiyun 	struct wl_chan_info chan_info;
1781*4882a593Smuzhiyun 	wl_prio_t max_prio;
1782*4882a593Smuzhiyun 	uint16 chan = 0;
1783*4882a593Smuzhiyun 	int i;
1784*4882a593Smuzhiyun 
1785*4882a593Smuzhiyun 	// find the max prio
1786*4882a593Smuzhiyun 	max_prio = cur_if->prio;
1787*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
1788*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
1789*4882a593Smuzhiyun 		if (cur_if != tmp_if && wl_get_isam_status(tmp_if, IF_READY) &&
1790*4882a593Smuzhiyun 				tmp_if->prio > max_prio) {
1791*4882a593Smuzhiyun 			memset(&chan_info, 0, sizeof(struct wl_chan_info));
1792*4882a593Smuzhiyun 			wl_ext_get_chan(tmp_if->dev, &chan_info);
1793*4882a593Smuzhiyun 			if (wl_ext_dfs_chan(&chan_info) && nodfs)
1794*4882a593Smuzhiyun 				continue;
1795*4882a593Smuzhiyun 			if (chan_info.chan && (cur_if->chan_info.band == chan_info.band)) {
1796*4882a593Smuzhiyun 				chan = chan_info.chan;
1797*4882a593Smuzhiyun 				max_prio = tmp_if->prio;
1798*4882a593Smuzhiyun 			}
1799*4882a593Smuzhiyun 		}
1800*4882a593Smuzhiyun 	}
1801*4882a593Smuzhiyun 
1802*4882a593Smuzhiyun 	return chan;
1803*4882a593Smuzhiyun }
1804*4882a593Smuzhiyun 
1805*4882a593Smuzhiyun static uint16
wl_ext_get_vsdb_chan(struct wl_apsta_params * apsta_params,const struct wl_if_info * cur_if,const struct wl_if_info * target_if)1806*4882a593Smuzhiyun wl_ext_get_vsdb_chan(struct wl_apsta_params *apsta_params,
1807*4882a593Smuzhiyun 	const struct wl_if_info *cur_if, const struct wl_if_info *target_if)
1808*4882a593Smuzhiyun {
1809*4882a593Smuzhiyun 	struct wl_chan_info chan_info;
1810*4882a593Smuzhiyun 	uint cur_band = cur_if->chan_info.band;
1811*4882a593Smuzhiyun 	uint16 cur_chan = cur_if->chan_info.chan;
1812*4882a593Smuzhiyun 	uint target_band;
1813*4882a593Smuzhiyun 	uint16 target_chan;
1814*4882a593Smuzhiyun 
1815*4882a593Smuzhiyun 	if (cur_if->vsdb && target_if->vsdb)
1816*4882a593Smuzhiyun 		return 0;
1817*4882a593Smuzhiyun 
1818*4882a593Smuzhiyun 	memset(&chan_info, 0, sizeof(struct wl_chan_info));
1819*4882a593Smuzhiyun 	target_chan = wl_ext_get_chan(target_if->dev, &chan_info);
1820*4882a593Smuzhiyun 	if (target_chan) {
1821*4882a593Smuzhiyun 		target_band = chan_info.band;
1822*4882a593Smuzhiyun 		IAPSTA_INFO(cur_if->ifname, "cur_chan=%s-%d, target_chan=%s-%d\n",
1823*4882a593Smuzhiyun 			WLCBAND2STR(cur_band), cur_chan,
1824*4882a593Smuzhiyun 			WLCBAND2STR(target_band), target_chan);
1825*4882a593Smuzhiyun 		if (wl_ext_rsdb_band(cur_band, target_band)) {
1826*4882a593Smuzhiyun 			if (!apsta_params->rsdb)
1827*4882a593Smuzhiyun 				return target_chan;
1828*4882a593Smuzhiyun 		} else {
1829*4882a593Smuzhiyun 			if (cur_chan != target_chan)
1830*4882a593Smuzhiyun 				return target_chan;
1831*4882a593Smuzhiyun 		}
1832*4882a593Smuzhiyun 	}
1833*4882a593Smuzhiyun 
1834*4882a593Smuzhiyun 	return 0;
1835*4882a593Smuzhiyun }
1836*4882a593Smuzhiyun 
1837*4882a593Smuzhiyun static int
wl_ext_rsdb_core_conflict(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)1838*4882a593Smuzhiyun wl_ext_rsdb_core_conflict(struct wl_apsta_params *apsta_params,
1839*4882a593Smuzhiyun 	struct wl_if_info *cur_if)
1840*4882a593Smuzhiyun {
1841*4882a593Smuzhiyun 	struct wl_if_info *tmp_if;
1842*4882a593Smuzhiyun 	struct wl_chan_info cur_chan_info, tmp_chan_info;
1843*4882a593Smuzhiyun 	int i;
1844*4882a593Smuzhiyun 
1845*4882a593Smuzhiyun 	if (apsta_params->rsdb) {
1846*4882a593Smuzhiyun 		memset(&cur_chan_info, 0, sizeof(struct wl_chan_info));
1847*4882a593Smuzhiyun 		wl_ext_get_chan(cur_if->dev, &cur_chan_info);
1848*4882a593Smuzhiyun 		for (i=0; i<MAX_IF_NUM; i++) {
1849*4882a593Smuzhiyun 			tmp_if = &apsta_params->if_info[i];
1850*4882a593Smuzhiyun 			if (tmp_if != cur_if && wl_get_isam_status(tmp_if, IF_READY) &&
1851*4882a593Smuzhiyun 					tmp_if->prio > cur_if->prio) {
1852*4882a593Smuzhiyun 				memset(&tmp_chan_info, 0, sizeof(struct wl_chan_info));
1853*4882a593Smuzhiyun 				wl_ext_get_chan(tmp_if->dev, &tmp_chan_info);
1854*4882a593Smuzhiyun 				if (!tmp_chan_info.chan)
1855*4882a593Smuzhiyun 					continue;
1856*4882a593Smuzhiyun 				if (wl_ext_rsdb_band(cur_chan_info.band, tmp_chan_info.band) &&
1857*4882a593Smuzhiyun 						wl_ext_rsdb_band(cur_chan_info.band, cur_if->chan_info.chan))
1858*4882a593Smuzhiyun 					return TRUE;
1859*4882a593Smuzhiyun 				else if (!wl_ext_rsdb_band(cur_chan_info.band, tmp_chan_info.band) &&
1860*4882a593Smuzhiyun 						wl_ext_rsdb_band(cur_chan_info.band, cur_if->chan_info.chan))
1861*4882a593Smuzhiyun 					return TRUE;
1862*4882a593Smuzhiyun 			}
1863*4882a593Smuzhiyun 		}
1864*4882a593Smuzhiyun 	}
1865*4882a593Smuzhiyun 	return FALSE;
1866*4882a593Smuzhiyun }
1867*4882a593Smuzhiyun 
1868*4882a593Smuzhiyun static int
wl_ext_trigger_csa(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)1869*4882a593Smuzhiyun wl_ext_trigger_csa(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
1870*4882a593Smuzhiyun {
1871*4882a593Smuzhiyun 	s8 iovar_buf[WLC_IOCTL_SMLEN];
1872*4882a593Smuzhiyun 	bool core_conflict = FALSE;
1873*4882a593Smuzhiyun 
1874*4882a593Smuzhiyun 	if (wl_ext_master_if(cur_if) && (apsta_params->csa & CSA_DRV_BIT)) {
1875*4882a593Smuzhiyun 		if (!cur_if->chan_info.chan) {
1876*4882a593Smuzhiyun 			WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix);
1877*4882a593Smuzhiyun 		} else if (wl_ext_dfs_chan(&cur_if->chan_info) && !apsta_params->radar) {
1878*4882a593Smuzhiyun 			WL_MSG(cur_if->ifname, "[%c] skip DFS channel %d\n",
1879*4882a593Smuzhiyun 				cur_if->prefix, cur_if->chan_info.chan);
1880*4882a593Smuzhiyun 			wl_ext_if_down(apsta_params, cur_if);
1881*4882a593Smuzhiyun 		} else {
1882*4882a593Smuzhiyun 			wl_chan_switch_t csa_arg;
1883*4882a593Smuzhiyun 			memset(&csa_arg, 0, sizeof(csa_arg));
1884*4882a593Smuzhiyun 			csa_arg.mode = 1;
1885*4882a593Smuzhiyun 			csa_arg.count = 3;
1886*4882a593Smuzhiyun 			csa_arg.chspec = wl_ext_chan_to_chanspec(cur_if->dev, &cur_if->chan_info);
1887*4882a593Smuzhiyun 			core_conflict = wl_ext_rsdb_core_conflict(apsta_params, cur_if);
1888*4882a593Smuzhiyun 			if (core_conflict) {
1889*4882a593Smuzhiyun 				WL_MSG(cur_if->ifname, "[%c] Skip CSA due to rsdb core conflict\n",
1890*4882a593Smuzhiyun 					cur_if->prefix);
1891*4882a593Smuzhiyun 			} else if (csa_arg.chspec) {
1892*4882a593Smuzhiyun 				WL_MSG(cur_if->ifname, "[%c] Trigger CSA to channel %d(0x%x)\n",
1893*4882a593Smuzhiyun 					cur_if->prefix, cur_if->chan_info.chan, csa_arg.chspec);
1894*4882a593Smuzhiyun 				wl_set_isam_status(cur_if, AP_CREATING);
1895*4882a593Smuzhiyun 				wl_ext_iovar_setbuf(cur_if->dev, "csa", &csa_arg, sizeof(csa_arg),
1896*4882a593Smuzhiyun 					iovar_buf, sizeof(iovar_buf), NULL);
1897*4882a593Smuzhiyun 				OSL_SLEEP(500);
1898*4882a593Smuzhiyun 				wl_clr_isam_status(cur_if, AP_CREATING);
1899*4882a593Smuzhiyun 				wl_ext_isam_status(cur_if->dev, NULL, 0);
1900*4882a593Smuzhiyun 			} else {
1901*4882a593Smuzhiyun 				IAPSTA_ERROR(cur_if->ifname, "fail to get chanspec\n");
1902*4882a593Smuzhiyun 			}
1903*4882a593Smuzhiyun 		}
1904*4882a593Smuzhiyun 	}
1905*4882a593Smuzhiyun 
1906*4882a593Smuzhiyun 	return 0;
1907*4882a593Smuzhiyun }
1908*4882a593Smuzhiyun 
1909*4882a593Smuzhiyun static void
wl_ext_move_cur_dfs_channel(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)1910*4882a593Smuzhiyun wl_ext_move_cur_dfs_channel(struct wl_apsta_params *apsta_params,
1911*4882a593Smuzhiyun 	struct wl_if_info *cur_if)
1912*4882a593Smuzhiyun {
1913*4882a593Smuzhiyun 	struct wl_chan_info *cur_chan_info = &cur_if->chan_info;
1914*4882a593Smuzhiyun 	uint cur_band = cur_chan_info->band;
1915*4882a593Smuzhiyun 	uint16 cur_chan = cur_chan_info->chan, auto_chan = 0;
1916*4882a593Smuzhiyun 	uint16 chan_2g = 0, chan_5g = 0;
1917*4882a593Smuzhiyun 
1918*4882a593Smuzhiyun 	if (!apsta_params->radar && wl_ext_master_if(cur_if) &&
1919*4882a593Smuzhiyun 			wl_ext_dfs_chan(cur_chan_info)) {
1920*4882a593Smuzhiyun 		wl_ext_get_default_chan(cur_if->dev, &chan_2g, &chan_5g, TRUE);
1921*4882a593Smuzhiyun 		if (!chan_2g && !chan_5g) {
1922*4882a593Smuzhiyun 			cur_chan_info->chan = 0;
1923*4882a593Smuzhiyun 			WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix);
1924*4882a593Smuzhiyun 			return;
1925*4882a593Smuzhiyun 		}
1926*4882a593Smuzhiyun 		if (apsta_params->vsdb) {
1927*4882a593Smuzhiyun 			if (chan_5g)
1928*4882a593Smuzhiyun 				wl_ext_set_chan_info(cur_if, WLC_BAND_5G, chan_5g);
1929*4882a593Smuzhiyun 			else
1930*4882a593Smuzhiyun 				wl_ext_set_chan_info(cur_if, WLC_BAND_2G, chan_2g);
1931*4882a593Smuzhiyun 			auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, TRUE);
1932*4882a593Smuzhiyun 			if (!auto_chan) {
1933*4882a593Smuzhiyun 				auto_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
1934*4882a593Smuzhiyun 					cur_chan_info->band);
1935*4882a593Smuzhiyun 				auto_chan = wf_chspec_ctlchan(auto_chan);
1936*4882a593Smuzhiyun 			}
1937*4882a593Smuzhiyun 			if (auto_chan)
1938*4882a593Smuzhiyun 				cur_chan_info->chan = auto_chan;
1939*4882a593Smuzhiyun 		}
1940*4882a593Smuzhiyun 		else if (apsta_params->rsdb) {
1941*4882a593Smuzhiyun 			if (chan_5g) {
1942*4882a593Smuzhiyun 				wl_ext_set_chan_info(cur_if, WLC_BAND_5G, chan_5g);
1943*4882a593Smuzhiyun 				auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, FALSE);
1944*4882a593Smuzhiyun 				if (auto_chan) {
1945*4882a593Smuzhiyun 					if (wl_ext_dfs_chan(cur_chan_info) && chan_2g) {
1946*4882a593Smuzhiyun 						wl_ext_set_chan_info(cur_if, WLC_BAND_2G, chan_2g);
1947*4882a593Smuzhiyun 						auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, TRUE);
1948*4882a593Smuzhiyun 					}
1949*4882a593Smuzhiyun 				}
1950*4882a593Smuzhiyun 			} else {
1951*4882a593Smuzhiyun 				wl_ext_set_chan_info(cur_if, WLC_BAND_2G, chan_2g);
1952*4882a593Smuzhiyun 				auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, TRUE);
1953*4882a593Smuzhiyun 			}
1954*4882a593Smuzhiyun 			if (!auto_chan) {
1955*4882a593Smuzhiyun 				auto_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
1956*4882a593Smuzhiyun 					cur_chan_info->band);
1957*4882a593Smuzhiyun 				auto_chan = wf_chspec_ctlchan(auto_chan);
1958*4882a593Smuzhiyun 			}
1959*4882a593Smuzhiyun 			if (auto_chan) {
1960*4882a593Smuzhiyun 				cur_chan_info->chan = auto_chan;
1961*4882a593Smuzhiyun 			}
1962*4882a593Smuzhiyun 		}
1963*4882a593Smuzhiyun 		else {
1964*4882a593Smuzhiyun 			wl_ext_set_chan_info(cur_if, WLC_BAND_5G, chan_5g);
1965*4882a593Smuzhiyun 			auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, FALSE);
1966*4882a593Smuzhiyun 			if (auto_chan) {
1967*4882a593Smuzhiyun 				cur_chan_info->chan = auto_chan;
1968*4882a593Smuzhiyun 			} else {
1969*4882a593Smuzhiyun 				auto_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
1970*4882a593Smuzhiyun 					cur_chan_info->band);
1971*4882a593Smuzhiyun 				auto_chan = wf_chspec_ctlchan(auto_chan);
1972*4882a593Smuzhiyun 				if (auto_chan) {
1973*4882a593Smuzhiyun 					cur_chan_info->chan = auto_chan;
1974*4882a593Smuzhiyun 				}
1975*4882a593Smuzhiyun 			}
1976*4882a593Smuzhiyun 		}
1977*4882a593Smuzhiyun 		WL_MSG(cur_if->ifname, "[%c] move channel %s-%d => %s-%d\n",
1978*4882a593Smuzhiyun 			cur_if->prefix, WLCBAND2STR(cur_band), cur_chan,
1979*4882a593Smuzhiyun 			WLCBAND2STR(cur_chan_info->band), cur_chan_info->chan);
1980*4882a593Smuzhiyun 	}
1981*4882a593Smuzhiyun }
1982*4882a593Smuzhiyun 
1983*4882a593Smuzhiyun static void
wl_ext_move_other_dfs_channel(struct wl_apsta_params * apsta_params,struct wl_if_info * tgt_if)1984*4882a593Smuzhiyun wl_ext_move_other_dfs_channel(struct wl_apsta_params *apsta_params,
1985*4882a593Smuzhiyun 	struct wl_if_info *tgt_if)
1986*4882a593Smuzhiyun {
1987*4882a593Smuzhiyun 	struct wl_chan_info *tgt_chan_info = &tgt_if->chan_info;
1988*4882a593Smuzhiyun 	uint cur_band = tgt_chan_info->band;
1989*4882a593Smuzhiyun 	uint16 cur_chan = tgt_chan_info->chan, auto_chan = 0;
1990*4882a593Smuzhiyun 	uint16 chan_2g = 0, chan_5g = 0;
1991*4882a593Smuzhiyun 
1992*4882a593Smuzhiyun 	if (!apsta_params->radar && wl_ext_master_if(tgt_if) &&
1993*4882a593Smuzhiyun 			wl_ext_dfs_chan(tgt_chan_info)) {
1994*4882a593Smuzhiyun 		wl_ext_get_default_chan(tgt_if->dev, &chan_2g, &chan_5g, TRUE);
1995*4882a593Smuzhiyun 		if (!chan_2g && !chan_5g) {
1996*4882a593Smuzhiyun 			tgt_chan_info->chan = 0;
1997*4882a593Smuzhiyun 			WL_MSG(tgt_if->ifname, "[%c] no valid channel\n", tgt_if->prefix);
1998*4882a593Smuzhiyun 			return;
1999*4882a593Smuzhiyun 		}
2000*4882a593Smuzhiyun 
2001*4882a593Smuzhiyun 		if (apsta_params->vsdb) {
2002*4882a593Smuzhiyun 			if (chan_5g)
2003*4882a593Smuzhiyun 				wl_ext_set_chan_info(tgt_if, WLC_BAND_5G, chan_5g);
2004*4882a593Smuzhiyun 			else
2005*4882a593Smuzhiyun 				wl_ext_set_chan_info(tgt_if, WLC_BAND_2G, chan_2g);
2006*4882a593Smuzhiyun 			auto_chan = wl_ext_get_same_band_chan(apsta_params, tgt_if, TRUE);
2007*4882a593Smuzhiyun 			if (!auto_chan) {
2008*4882a593Smuzhiyun 				auto_chan = wl_ext_autochannel(tgt_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
2009*4882a593Smuzhiyun 					tgt_chan_info->band);
2010*4882a593Smuzhiyun 				auto_chan = wf_chspec_ctlchan(auto_chan);
2011*4882a593Smuzhiyun 			}
2012*4882a593Smuzhiyun 			if (auto_chan) {
2013*4882a593Smuzhiyun 				tgt_chan_info->chan = auto_chan;
2014*4882a593Smuzhiyun 			}
2015*4882a593Smuzhiyun 		}
2016*4882a593Smuzhiyun 		else if (apsta_params->rsdb) {
2017*4882a593Smuzhiyun 			if (chan_2g) {
2018*4882a593Smuzhiyun 				wl_ext_set_chan_info(tgt_if, WLC_BAND_2G, chan_2g);
2019*4882a593Smuzhiyun 				auto_chan = wl_ext_get_same_band_chan(apsta_params, tgt_if, TRUE);
2020*4882a593Smuzhiyun 				if (!auto_chan) {
2021*4882a593Smuzhiyun 					auto_chan = wl_ext_autochannel(tgt_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
2022*4882a593Smuzhiyun 						tgt_chan_info->band);
2023*4882a593Smuzhiyun 					auto_chan = wf_chspec_ctlchan(auto_chan);
2024*4882a593Smuzhiyun 				}
2025*4882a593Smuzhiyun 			} else {
2026*4882a593Smuzhiyun 				tgt_chan_info->chan = 0;
2027*4882a593Smuzhiyun 			}
2028*4882a593Smuzhiyun 			if (auto_chan) {
2029*4882a593Smuzhiyun 				tgt_chan_info->chan = auto_chan;
2030*4882a593Smuzhiyun 			}
2031*4882a593Smuzhiyun 		} else {
2032*4882a593Smuzhiyun 			tgt_chan_info->chan = 0;
2033*4882a593Smuzhiyun 		}
2034*4882a593Smuzhiyun 		WL_MSG(tgt_if->ifname, "[%c] move channel %s-%d => %s-%d\n",
2035*4882a593Smuzhiyun 			tgt_if->prefix, WLCBAND2STR(cur_band), cur_chan,
2036*4882a593Smuzhiyun 			WLCBAND2STR(tgt_chan_info->band), tgt_chan_info->chan);
2037*4882a593Smuzhiyun 	}
2038*4882a593Smuzhiyun }
2039*4882a593Smuzhiyun 
2040*4882a593Smuzhiyun static uint16
wl_ext_move_cur_channel(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)2041*4882a593Smuzhiyun wl_ext_move_cur_channel(struct wl_apsta_params *apsta_params,
2042*4882a593Smuzhiyun 	struct wl_if_info *cur_if)
2043*4882a593Smuzhiyun {
2044*4882a593Smuzhiyun 	struct wl_if_info *tmp_if, *target_if = NULL;
2045*4882a593Smuzhiyun 	struct wl_chan_info cur_chan_info, tgt_chan_info;
2046*4882a593Smuzhiyun 	uint16 tmp_chan;
2047*4882a593Smuzhiyun 	wl_prio_t max_prio;
2048*4882a593Smuzhiyun 	int i;
2049*4882a593Smuzhiyun 
2050*4882a593Smuzhiyun 	if (apsta_params->vsdb) {
2051*4882a593Smuzhiyun 		goto exit;
2052*4882a593Smuzhiyun 	}
2053*4882a593Smuzhiyun 
2054*4882a593Smuzhiyun 	// find the max prio
2055*4882a593Smuzhiyun 	max_prio = cur_if->prio;
2056*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
2057*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
2058*4882a593Smuzhiyun 		if (cur_if != tmp_if && wl_get_isam_status(tmp_if, IF_READY) &&
2059*4882a593Smuzhiyun 				tmp_if->prio > max_prio) {
2060*4882a593Smuzhiyun 			tmp_chan = wl_ext_get_vsdb_chan(apsta_params, cur_if, tmp_if);
2061*4882a593Smuzhiyun 			if (tmp_chan) {
2062*4882a593Smuzhiyun 				target_if = tmp_if;
2063*4882a593Smuzhiyun 				max_prio = tmp_if->prio;
2064*4882a593Smuzhiyun 			}
2065*4882a593Smuzhiyun 		}
2066*4882a593Smuzhiyun 	}
2067*4882a593Smuzhiyun 
2068*4882a593Smuzhiyun 	if (target_if) {
2069*4882a593Smuzhiyun 		memset(&cur_chan_info, 0, sizeof(struct wl_chan_info));
2070*4882a593Smuzhiyun 		memset(&tgt_chan_info, 0, sizeof(struct wl_chan_info));
2071*4882a593Smuzhiyun 		wl_ext_get_chan(cur_if->dev, &cur_chan_info);
2072*4882a593Smuzhiyun 		wl_ext_get_chan(target_if->dev, &tgt_chan_info);
2073*4882a593Smuzhiyun 		if (apsta_params->rsdb && cur_chan_info.chan &&
2074*4882a593Smuzhiyun 				wl_ext_rsdb_band(cur_chan_info.band, tgt_chan_info.band)) {
2075*4882a593Smuzhiyun 			WL_MSG(cur_if->ifname, "[%c] keep on current channel %s-%d\n",
2076*4882a593Smuzhiyun 				cur_if->prefix, WLCBAND2STR(cur_chan_info.band), cur_chan_info.chan);
2077*4882a593Smuzhiyun 			cur_if->chan_info.chan = 0;
2078*4882a593Smuzhiyun 		} else {
2079*4882a593Smuzhiyun 			WL_MSG(cur_if->ifname, "[%c] channel=%s-%d => %s[%c] channel=%s-%d\n",
2080*4882a593Smuzhiyun 				cur_if->prefix,
2081*4882a593Smuzhiyun 				WLCBAND2STR(cur_if->chan_info.band), cur_if->chan_info.chan,
2082*4882a593Smuzhiyun 				target_if->ifname, target_if->prefix,
2083*4882a593Smuzhiyun 				WLCBAND2STR(tgt_chan_info.band), tgt_chan_info.chan);
2084*4882a593Smuzhiyun 			wl_ext_set_chan_info(cur_if, tgt_chan_info.band, tgt_chan_info.chan);
2085*4882a593Smuzhiyun 		}
2086*4882a593Smuzhiyun 	}
2087*4882a593Smuzhiyun 
2088*4882a593Smuzhiyun exit:
2089*4882a593Smuzhiyun 	wl_ext_move_cur_dfs_channel(apsta_params, cur_if);
2090*4882a593Smuzhiyun 
2091*4882a593Smuzhiyun 	return cur_if->chan_info.chan;
2092*4882a593Smuzhiyun }
2093*4882a593Smuzhiyun 
2094*4882a593Smuzhiyun static struct wl_if_info *
wl_ext_move_other_channel(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)2095*4882a593Smuzhiyun wl_ext_move_other_channel(struct wl_apsta_params *apsta_params,
2096*4882a593Smuzhiyun 	struct wl_if_info *cur_if)
2097*4882a593Smuzhiyun {
2098*4882a593Smuzhiyun 	struct wl_if_info *tmp_if, *target_if=NULL;
2099*4882a593Smuzhiyun 	uint16 tmp_chan, target_chan = 0;
2100*4882a593Smuzhiyun 	wl_prio_t max_prio = 0, cur_prio;
2101*4882a593Smuzhiyun 	int i;
2102*4882a593Smuzhiyun 
2103*4882a593Smuzhiyun 	if (apsta_params->vsdb || !cur_if->chan_info.chan) {
2104*4882a593Smuzhiyun 		return NULL;
2105*4882a593Smuzhiyun 	}
2106*4882a593Smuzhiyun 
2107*4882a593Smuzhiyun 	// find the max prio, but lower than cur_if
2108*4882a593Smuzhiyun 	cur_prio = cur_if->prio;
2109*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
2110*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
2111*4882a593Smuzhiyun 		if (cur_if != tmp_if && wl_get_isam_status(tmp_if, IF_READY) &&
2112*4882a593Smuzhiyun 				tmp_if->prio >= max_prio && tmp_if->prio <= cur_prio) {
2113*4882a593Smuzhiyun 			tmp_chan = wl_ext_get_vsdb_chan(apsta_params, cur_if, tmp_if);
2114*4882a593Smuzhiyun 			if (tmp_chan) {
2115*4882a593Smuzhiyun 				target_if = tmp_if;
2116*4882a593Smuzhiyun 				target_chan = tmp_chan;
2117*4882a593Smuzhiyun 				max_prio = tmp_if->prio;
2118*4882a593Smuzhiyun 			}
2119*4882a593Smuzhiyun 		}
2120*4882a593Smuzhiyun 	}
2121*4882a593Smuzhiyun 
2122*4882a593Smuzhiyun 	if (target_if) {
2123*4882a593Smuzhiyun 		WL_MSG(target_if->ifname, "channel=%s-%d => %s channel=%s-%d\n",
2124*4882a593Smuzhiyun 			WLCBAND2STR(target_if->chan_info.band), target_chan,
2125*4882a593Smuzhiyun 			cur_if->ifname, WLCBAND2STR(cur_if->chan_info.band), cur_if->chan_info.chan);
2126*4882a593Smuzhiyun 		wl_ext_set_chan_info(target_if, cur_if->chan_info.band, cur_if->chan_info.chan);
2127*4882a593Smuzhiyun 		wl_ext_move_other_dfs_channel(apsta_params, target_if);
2128*4882a593Smuzhiyun 		if (apsta_params->csa == 0) {
2129*4882a593Smuzhiyun 			wl_ext_if_down(apsta_params, target_if);
2130*4882a593Smuzhiyun 			wl_ext_move_other_channel(apsta_params, cur_if);
2131*4882a593Smuzhiyun 			if (target_if->ifmode == IMESH_MODE) {
2132*4882a593Smuzhiyun 				wl_ext_enable_iface(target_if->dev, target_if->ifname, 0, FALSE);
2133*4882a593Smuzhiyun 			} else if (target_if->ifmode == IAP_MODE) {
2134*4882a593Smuzhiyun 				wl_ext_if_up(apsta_params, target_if, FALSE, 0);
2135*4882a593Smuzhiyun 			}
2136*4882a593Smuzhiyun 		} else {
2137*4882a593Smuzhiyun 			wl_ext_trigger_csa(apsta_params, target_if);
2138*4882a593Smuzhiyun 		}
2139*4882a593Smuzhiyun 	}
2140*4882a593Smuzhiyun 
2141*4882a593Smuzhiyun 	return target_if;
2142*4882a593Smuzhiyun }
2143*4882a593Smuzhiyun 
2144*4882a593Smuzhiyun static bool
wl_ext_wait_other_enabling(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)2145*4882a593Smuzhiyun wl_ext_wait_other_enabling(struct wl_apsta_params *apsta_params,
2146*4882a593Smuzhiyun 	struct wl_if_info *cur_if)
2147*4882a593Smuzhiyun {
2148*4882a593Smuzhiyun 	struct wl_if_info *tmp_if;
2149*4882a593Smuzhiyun 	bool enabling = FALSE;
2150*4882a593Smuzhiyun 	u32 timeout = 1;
2151*4882a593Smuzhiyun 	int i;
2152*4882a593Smuzhiyun 
2153*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
2154*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
2155*4882a593Smuzhiyun 		if (tmp_if->dev && tmp_if->dev != cur_if->dev) {
2156*4882a593Smuzhiyun 			if (tmp_if->ifmode == ISTA_MODE)
2157*4882a593Smuzhiyun 				enabling = wl_get_isam_status(tmp_if, STA_CONNECTING);
2158*4882a593Smuzhiyun 			else if (tmp_if->ifmode == IAP_MODE || tmp_if->ifmode == IMESH_MODE)
2159*4882a593Smuzhiyun 				enabling = wl_get_isam_status(tmp_if, AP_CREATING);
2160*4882a593Smuzhiyun 			if (enabling)
2161*4882a593Smuzhiyun 				WL_MSG(cur_if->ifname, "waiting for %s[%c] enabling...\n",
2162*4882a593Smuzhiyun 					tmp_if->ifname, tmp_if->prefix);
2163*4882a593Smuzhiyun 			if (enabling && tmp_if->ifmode == ISTA_MODE) {
2164*4882a593Smuzhiyun 				timeout = wait_event_interruptible_timeout(
2165*4882a593Smuzhiyun 					apsta_params->netif_change_event,
2166*4882a593Smuzhiyun 					!wl_get_isam_status(tmp_if, STA_CONNECTING),
2167*4882a593Smuzhiyun 					msecs_to_jiffies(MAX_STA_LINK_WAIT_TIME));
2168*4882a593Smuzhiyun 			} else if (enabling &&
2169*4882a593Smuzhiyun 					(tmp_if->ifmode == IAP_MODE || tmp_if->ifmode == IMESH_MODE)) {
2170*4882a593Smuzhiyun 				timeout = wait_event_interruptible_timeout(
2171*4882a593Smuzhiyun 					apsta_params->netif_change_event,
2172*4882a593Smuzhiyun 					!wl_get_isam_status(tmp_if, AP_CREATING),
2173*4882a593Smuzhiyun 					msecs_to_jiffies(MAX_STA_LINK_WAIT_TIME));
2174*4882a593Smuzhiyun 			}
2175*4882a593Smuzhiyun 			if (tmp_if->ifmode == ISTA_MODE)
2176*4882a593Smuzhiyun 				enabling = wl_get_isam_status(tmp_if, STA_CONNECTING);
2177*4882a593Smuzhiyun 			else if (tmp_if->ifmode == IAP_MODE || tmp_if->ifmode == IMESH_MODE)
2178*4882a593Smuzhiyun 				enabling = wl_get_isam_status(tmp_if, AP_CREATING);
2179*4882a593Smuzhiyun 			if (timeout <= 0 || enabling) {
2180*4882a593Smuzhiyun 				WL_MSG(cur_if->ifname, "%s[%c] is still enabling...\n",
2181*4882a593Smuzhiyun 					tmp_if->ifname, tmp_if->prefix);
2182*4882a593Smuzhiyun 			}
2183*4882a593Smuzhiyun 		}
2184*4882a593Smuzhiyun 	}
2185*4882a593Smuzhiyun 
2186*4882a593Smuzhiyun 	return enabling;
2187*4882a593Smuzhiyun }
2188*4882a593Smuzhiyun 
2189*4882a593Smuzhiyun bool
wl_ext_iapsta_other_if_enabled(struct net_device * net)2190*4882a593Smuzhiyun wl_ext_iapsta_other_if_enabled(struct net_device *net)
2191*4882a593Smuzhiyun {
2192*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
2193*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2194*4882a593Smuzhiyun 	struct wl_if_info *tmp_if;
2195*4882a593Smuzhiyun 	bool enabled = FALSE;
2196*4882a593Smuzhiyun 	int i;
2197*4882a593Smuzhiyun 
2198*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
2199*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
2200*4882a593Smuzhiyun 		if (tmp_if && wl_get_isam_status(tmp_if, IF_READY)) {
2201*4882a593Smuzhiyun 			if (wl_ext_associated(tmp_if->dev)) {
2202*4882a593Smuzhiyun 				enabled = TRUE;
2203*4882a593Smuzhiyun 				break;
2204*4882a593Smuzhiyun 			}
2205*4882a593Smuzhiyun 		}
2206*4882a593Smuzhiyun 	}
2207*4882a593Smuzhiyun 
2208*4882a593Smuzhiyun 	return enabled;
2209*4882a593Smuzhiyun }
2210*4882a593Smuzhiyun 
2211*4882a593Smuzhiyun bool
wl_ext_sta_connecting(struct net_device * dev)2212*4882a593Smuzhiyun wl_ext_sta_connecting(struct net_device *dev)
2213*4882a593Smuzhiyun {
2214*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
2215*4882a593Smuzhiyun 	bool connecting = FALSE;
2216*4882a593Smuzhiyun 	int state;
2217*4882a593Smuzhiyun 
2218*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
2219*4882a593Smuzhiyun 	if (!cur_if)
2220*4882a593Smuzhiyun 		return FALSE;
2221*4882a593Smuzhiyun 
2222*4882a593Smuzhiyun 	if (cur_if->ifmode != ISTA_MODE && cur_if->ifmode != IGC_MODE)
2223*4882a593Smuzhiyun 		return FALSE;
2224*4882a593Smuzhiyun 
2225*4882a593Smuzhiyun 	state = cur_if->conn_state;
2226*4882a593Smuzhiyun 	if (state >= CONN_STATE_CONNECTING && state < CONN_STATE_CONNECTED) {
2227*4882a593Smuzhiyun 		connecting = TRUE;
2228*4882a593Smuzhiyun 		IAPSTA_TRACE(dev->name, "conn_state %d\n", state);
2229*4882a593Smuzhiyun 	}
2230*4882a593Smuzhiyun 
2231*4882a593Smuzhiyun 	return connecting;
2232*4882a593Smuzhiyun }
2233*4882a593Smuzhiyun 
2234*4882a593Smuzhiyun bool
wl_ext_sta_handshaking(struct net_device * dev)2235*4882a593Smuzhiyun wl_ext_sta_handshaking(struct net_device *dev)
2236*4882a593Smuzhiyun {
2237*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
2238*4882a593Smuzhiyun 	bool connecting = FALSE;
2239*4882a593Smuzhiyun 	int state;
2240*4882a593Smuzhiyun 
2241*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
2242*4882a593Smuzhiyun 	if (!cur_if)
2243*4882a593Smuzhiyun 		return FALSE;
2244*4882a593Smuzhiyun 
2245*4882a593Smuzhiyun 	if (cur_if->ifmode != ISTA_MODE && cur_if->ifmode != IGC_MODE)
2246*4882a593Smuzhiyun 		return FALSE;
2247*4882a593Smuzhiyun 
2248*4882a593Smuzhiyun 	state = cur_if->conn_state;
2249*4882a593Smuzhiyun 	if (state >= CONN_STATE_4WAY_M1 && state < CONN_STATE_CONNECTED) {
2250*4882a593Smuzhiyun 		connecting = TRUE;
2251*4882a593Smuzhiyun 		IAPSTA_TRACE(dev->name, "conn_state %d\n", state);
2252*4882a593Smuzhiyun 	}
2253*4882a593Smuzhiyun 
2254*4882a593Smuzhiyun 	return connecting;
2255*4882a593Smuzhiyun }
2256*4882a593Smuzhiyun 
2257*4882a593Smuzhiyun #ifdef DHD_LOSSLESS_ROAMING
2258*4882a593Smuzhiyun int
wl_ext_any_sta_handshaking(struct dhd_pub * dhd)2259*4882a593Smuzhiyun wl_ext_any_sta_handshaking(struct dhd_pub *dhd)
2260*4882a593Smuzhiyun {
2261*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2262*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
2263*4882a593Smuzhiyun 	int state = 0, i;
2264*4882a593Smuzhiyun 
2265*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
2266*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[i];
2267*4882a593Smuzhiyun 		if (cur_if->dev && cur_if->ifmode == ISTA_MODE) {
2268*4882a593Smuzhiyun 			state = cur_if->conn_state;
2269*4882a593Smuzhiyun 			if (state >= CONN_STATE_4WAY_M1 && state < CONN_STATE_CONNECTED) {
2270*4882a593Smuzhiyun 				return state;
2271*4882a593Smuzhiyun 			}
2272*4882a593Smuzhiyun 		}
2273*4882a593Smuzhiyun 	}
2274*4882a593Smuzhiyun 	return 0;
2275*4882a593Smuzhiyun }
2276*4882a593Smuzhiyun #endif /* DHD_LOSSLESS_ROAMING */
2277*4882a593Smuzhiyun 
2278*4882a593Smuzhiyun #ifdef PROPTX_MAXCOUNT
2279*4882a593Smuzhiyun int
wl_ext_get_wlfc_maxcount(struct dhd_pub * dhd,int ifidx)2280*4882a593Smuzhiyun wl_ext_get_wlfc_maxcount(struct dhd_pub *dhd, int ifidx)
2281*4882a593Smuzhiyun {
2282*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2283*4882a593Smuzhiyun 	struct wl_if_info *tmp_if, *cur_if = NULL;
2284*4882a593Smuzhiyun 	int i, maxcount = WL_TXSTATUS_FREERUNCTR_MASK;
2285*4882a593Smuzhiyun 
2286*4882a593Smuzhiyun 	if (!apsta_params->rsdb)
2287*4882a593Smuzhiyun 		return maxcount;
2288*4882a593Smuzhiyun 
2289*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
2290*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
2291*4882a593Smuzhiyun 		if (tmp_if->dev && tmp_if->ifidx == ifidx) {
2292*4882a593Smuzhiyun 			cur_if = tmp_if;
2293*4882a593Smuzhiyun 			maxcount = cur_if->transit_maxcount;
2294*4882a593Smuzhiyun 		}
2295*4882a593Smuzhiyun 	}
2296*4882a593Smuzhiyun 
2297*4882a593Smuzhiyun 	if (cur_if)
2298*4882a593Smuzhiyun 		IAPSTA_INFO(cur_if->ifname, "update maxcount %d\n", maxcount);
2299*4882a593Smuzhiyun 	else
2300*4882a593Smuzhiyun 		IAPSTA_INFO("wlan", "update maxcount %d for ifidx %d\n", maxcount, ifidx);
2301*4882a593Smuzhiyun 	return maxcount;
2302*4882a593Smuzhiyun }
2303*4882a593Smuzhiyun 
2304*4882a593Smuzhiyun static void
wl_ext_update_wlfc_maxcount(struct dhd_pub * dhd)2305*4882a593Smuzhiyun wl_ext_update_wlfc_maxcount(struct dhd_pub *dhd)
2306*4882a593Smuzhiyun {
2307*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2308*4882a593Smuzhiyun 	struct wl_if_info *tmp_if;
2309*4882a593Smuzhiyun 	struct wl_chan_info chan_info;
2310*4882a593Smuzhiyun 	bool band_5g = FALSE;
2311*4882a593Smuzhiyun 	int i, ret;
2312*4882a593Smuzhiyun 
2313*4882a593Smuzhiyun 	if (!apsta_params->rsdb)
2314*4882a593Smuzhiyun 		return;
2315*4882a593Smuzhiyun 
2316*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
2317*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
2318*4882a593Smuzhiyun 		if (tmp_if->dev) {
2319*4882a593Smuzhiyun 			memset(&chan_info, 0, sizeof(struct wl_chan_info));
2320*4882a593Smuzhiyun 			wl_ext_get_chan(tmp_if->dev, &chan_info);
2321*4882a593Smuzhiyun 			if (chan_info.band == WLC_BAND_5G || chan_info.band == WLC_BAND_6G) {
2322*4882a593Smuzhiyun 				tmp_if->transit_maxcount = dhd->conf->proptx_maxcnt_5g;
2323*4882a593Smuzhiyun 				ret = dhd_wlfc_update_maxcount(dhd, tmp_if->ifidx,
2324*4882a593Smuzhiyun 					tmp_if->transit_maxcount);
2325*4882a593Smuzhiyun 				if (ret == 0)
2326*4882a593Smuzhiyun 					IAPSTA_INFO(tmp_if->ifname, "updated maxcount %d\n",
2327*4882a593Smuzhiyun 						tmp_if->transit_maxcount);
2328*4882a593Smuzhiyun 				band_5g = TRUE;
2329*4882a593Smuzhiyun 			}
2330*4882a593Smuzhiyun 		}
2331*4882a593Smuzhiyun 	}
2332*4882a593Smuzhiyun 
2333*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
2334*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
2335*4882a593Smuzhiyun 		if (tmp_if->dev) {
2336*4882a593Smuzhiyun 			wl_ext_get_chan(tmp_if->dev, &chan_info);
2337*4882a593Smuzhiyun 			if ((chan_info.chan == 0) || (chan_info.band == WLC_BAND_2G)) {
2338*4882a593Smuzhiyun 				if (chan_info.chan == 0) {
2339*4882a593Smuzhiyun 					tmp_if->transit_maxcount = WL_TXSTATUS_FREERUNCTR_MASK;
2340*4882a593Smuzhiyun 				} else if (band_5g) {
2341*4882a593Smuzhiyun 					tmp_if->transit_maxcount = dhd->conf->proptx_maxcnt_2g;
2342*4882a593Smuzhiyun 				} else {
2343*4882a593Smuzhiyun 					tmp_if->transit_maxcount = dhd->conf->proptx_maxcnt_5g;
2344*4882a593Smuzhiyun 				}
2345*4882a593Smuzhiyun 				ret = dhd_wlfc_update_maxcount(dhd, tmp_if->ifidx,
2346*4882a593Smuzhiyun 					tmp_if->transit_maxcount);
2347*4882a593Smuzhiyun 				if (ret == 0)
2348*4882a593Smuzhiyun 					IAPSTA_INFO(tmp_if->ifname, "updated maxcount %d\n",
2349*4882a593Smuzhiyun 						tmp_if->transit_maxcount);
2350*4882a593Smuzhiyun 			}
2351*4882a593Smuzhiyun 		}
2352*4882a593Smuzhiyun 	}
2353*4882a593Smuzhiyun }
2354*4882a593Smuzhiyun #endif /* PROPTX_MAXCOUNT */
2355*4882a593Smuzhiyun 
2356*4882a593Smuzhiyun #ifdef WL_CFG80211
2357*4882a593Smuzhiyun static struct wl_if_info *
wl_ext_get_dfs_master_if(struct wl_apsta_params * apsta_params)2358*4882a593Smuzhiyun wl_ext_get_dfs_master_if(struct wl_apsta_params *apsta_params)
2359*4882a593Smuzhiyun {
2360*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
2361*4882a593Smuzhiyun 	struct wl_chan_info chan_info;
2362*4882a593Smuzhiyun 	int i;
2363*4882a593Smuzhiyun 
2364*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
2365*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[i];
2366*4882a593Smuzhiyun 		if (!cur_if->dev || !wl_ext_master_if(cur_if))
2367*4882a593Smuzhiyun 			continue;
2368*4882a593Smuzhiyun 		memset(&chan_info, 0, sizeof(struct wl_chan_info));
2369*4882a593Smuzhiyun 		wl_ext_get_chan(cur_if->dev, &chan_info);
2370*4882a593Smuzhiyun 		if (chan_info.chan && wl_ext_dfs_chan(&chan_info)) {
2371*4882a593Smuzhiyun 			return cur_if;
2372*4882a593Smuzhiyun 		}
2373*4882a593Smuzhiyun 	}
2374*4882a593Smuzhiyun 	return NULL;
2375*4882a593Smuzhiyun }
2376*4882a593Smuzhiyun 
2377*4882a593Smuzhiyun static void
wl_ext_save_master_channel(struct wl_apsta_params * apsta_params,uint16 post_channel)2378*4882a593Smuzhiyun wl_ext_save_master_channel(struct wl_apsta_params *apsta_params,
2379*4882a593Smuzhiyun 	uint16 post_channel)
2380*4882a593Smuzhiyun {
2381*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
2382*4882a593Smuzhiyun 	struct wl_chan_info chan_info;
2383*4882a593Smuzhiyun 	int i;
2384*4882a593Smuzhiyun 
2385*4882a593Smuzhiyun 	if (apsta_params->vsdb)
2386*4882a593Smuzhiyun 		return;
2387*4882a593Smuzhiyun 
2388*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
2389*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[i];
2390*4882a593Smuzhiyun 		if (!cur_if->dev || !wl_ext_master_if(cur_if))
2391*4882a593Smuzhiyun 			continue;
2392*4882a593Smuzhiyun 		memset(&chan_info, 0, sizeof(struct wl_chan_info));
2393*4882a593Smuzhiyun 		wl_ext_get_chan(cur_if->dev, &chan_info);
2394*4882a593Smuzhiyun 		if (chan_info.chan) {
2395*4882a593Smuzhiyun 			cur_if->prev_channel = chan_info.chan;
2396*4882a593Smuzhiyun 			cur_if->post_channel = post_channel;
2397*4882a593Smuzhiyun 		}
2398*4882a593Smuzhiyun 	}
2399*4882a593Smuzhiyun }
2400*4882a593Smuzhiyun 
2401*4882a593Smuzhiyun void
wl_ext_iapsta_enable_master_if(struct net_device * dev,bool post)2402*4882a593Smuzhiyun wl_ext_iapsta_enable_master_if(struct net_device *dev, bool post)
2403*4882a593Smuzhiyun {
2404*4882a593Smuzhiyun 	dhd_pub_t *dhd = dhd_get_pub(dev);
2405*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2406*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
2407*4882a593Smuzhiyun 	int i;
2408*4882a593Smuzhiyun 
2409*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
2410*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[i];
2411*4882a593Smuzhiyun 		if (cur_if && cur_if->post_channel) {
2412*4882a593Smuzhiyun 			if (post)
2413*4882a593Smuzhiyun 				cur_if->chan_info.chan = cur_if->post_channel;
2414*4882a593Smuzhiyun 			else
2415*4882a593Smuzhiyun 				cur_if->chan_info.chan = cur_if->prev_channel;
2416*4882a593Smuzhiyun 			if (wl_ext_associated(cur_if->dev))
2417*4882a593Smuzhiyun 				wl_ext_if_down(apsta_params, cur_if);
2418*4882a593Smuzhiyun 			wl_ext_if_up(apsta_params, cur_if, TRUE, 0);
2419*4882a593Smuzhiyun 			cur_if->prev_channel = 0;
2420*4882a593Smuzhiyun 			cur_if->post_channel = 0;
2421*4882a593Smuzhiyun 		}
2422*4882a593Smuzhiyun 	}
2423*4882a593Smuzhiyun }
2424*4882a593Smuzhiyun 
2425*4882a593Smuzhiyun void
wl_ext_iapsta_restart_master(struct net_device * dev)2426*4882a593Smuzhiyun wl_ext_iapsta_restart_master(struct net_device *dev)
2427*4882a593Smuzhiyun {
2428*4882a593Smuzhiyun 	dhd_pub_t *dhd = dhd_get_pub(dev);
2429*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2430*4882a593Smuzhiyun 	struct wl_if_info *ap_if = NULL;
2431*4882a593Smuzhiyun 
2432*4882a593Smuzhiyun 	if (apsta_params->radar)
2433*4882a593Smuzhiyun 		return;
2434*4882a593Smuzhiyun 
2435*4882a593Smuzhiyun 	ap_if = wl_ext_get_dfs_master_if(apsta_params);
2436*4882a593Smuzhiyun 	if (ap_if) {
2437*4882a593Smuzhiyun 		uint16 chan_2g, chan_5g;
2438*4882a593Smuzhiyun 		wl_ext_if_down(apsta_params, ap_if);
2439*4882a593Smuzhiyun 		wl_ext_iapsta_restart_master(dev);
2440*4882a593Smuzhiyun 		wl_ext_get_default_chan(ap_if->dev, &chan_2g, &chan_5g, TRUE);
2441*4882a593Smuzhiyun 		if (chan_5g)
2442*4882a593Smuzhiyun 			wl_ext_set_chan_info(ap_if, WLC_BAND_5G, chan_5g);
2443*4882a593Smuzhiyun 		else if (chan_2g)
2444*4882a593Smuzhiyun 			wl_ext_set_chan_info(ap_if, WLC_BAND_2G, chan_2g);
2445*4882a593Smuzhiyun 		else
2446*4882a593Smuzhiyun 			ap_if->chan_info.chan = 0;
2447*4882a593Smuzhiyun 		if (ap_if->chan_info.chan) {
2448*4882a593Smuzhiyun 			wl_ext_move_cur_channel(apsta_params, ap_if);
2449*4882a593Smuzhiyun 			wl_ext_if_up(apsta_params, ap_if, FALSE, 0);
2450*4882a593Smuzhiyun 		}
2451*4882a593Smuzhiyun 	}
2452*4882a593Smuzhiyun }
2453*4882a593Smuzhiyun 
2454*4882a593Smuzhiyun static void
wl_ext_if_reenabled(struct wl_apsta_params * apsta_params,ifmode_t ifmode,u32 channel)2455*4882a593Smuzhiyun wl_ext_if_reenabled(struct wl_apsta_params *apsta_params, ifmode_t ifmode, u32 channel)
2456*4882a593Smuzhiyun {
2457*4882a593Smuzhiyun 	struct wl_if_info *tmp_if;
2458*4882a593Smuzhiyun 	int i;
2459*4882a593Smuzhiyun 
2460*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
2461*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
2462*4882a593Smuzhiyun 		if (tmp_if && tmp_if->ifmode == ifmode &&
2463*4882a593Smuzhiyun 				wl_get_isam_status(tmp_if, IF_READY)) {
2464*4882a593Smuzhiyun 			if (wl_ext_get_chan(tmp_if->dev, &tmp_if->chan_info) == channel) {
2465*4882a593Smuzhiyun 			    WL_MSG(tmp_if->ifname, "re-enable channel %d\n", channel);
2466*4882a593Smuzhiyun 				if (ifmode == IAP_MODE) {
2467*4882a593Smuzhiyun 					wl_ext_if_down(apsta_params, tmp_if);
2468*4882a593Smuzhiyun 					wl_ext_if_up(apsta_params, tmp_if, FALSE, 0);
2469*4882a593Smuzhiyun 				}
2470*4882a593Smuzhiyun 				break;
2471*4882a593Smuzhiyun 			}
2472*4882a593Smuzhiyun 		}
2473*4882a593Smuzhiyun 	}
2474*4882a593Smuzhiyun 
2475*4882a593Smuzhiyun }
2476*4882a593Smuzhiyun 
2477*4882a593Smuzhiyun u32
wl_ext_iapsta_update_channel(struct net_device * dev,u32 chanspec)2478*4882a593Smuzhiyun wl_ext_iapsta_update_channel(struct net_device *dev, u32 chanspec)
2479*4882a593Smuzhiyun {
2480*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
2481*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2482*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL, *target_if = NULL;
2483*4882a593Smuzhiyun 	struct dhd_conf *conf = dhd->conf;
2484*4882a593Smuzhiyun 
2485*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
2486*4882a593Smuzhiyun 	if (cur_if) {
2487*4882a593Smuzhiyun 		struct wl_chan_info *chan_info = &cur_if->chan_info;
2488*4882a593Smuzhiyun 		mutex_lock(&apsta_params->usr_sync);
2489*4882a593Smuzhiyun 		wl_ext_isam_status(cur_if->dev, NULL, 0);
2490*4882a593Smuzhiyun 		wl_ext_set_chan_info(cur_if, CHSPEC2WLC_BAND(chanspec),
2491*4882a593Smuzhiyun 			wf_chspec_ctlchan(chanspec));
2492*4882a593Smuzhiyun 		if (wl_ext_master_if(cur_if) && apsta_params->acs) {
2493*4882a593Smuzhiyun 			chan_info->chan = wl_ext_autochannel(cur_if->dev, apsta_params->acs,
2494*4882a593Smuzhiyun 				chan_info->band);
2495*4882a593Smuzhiyun 			chan_info->chan = wf_chspec_ctlchan(chan_info->chan);
2496*4882a593Smuzhiyun 		}
2497*4882a593Smuzhiyun 		chan_info->chan = wl_ext_move_cur_channel(apsta_params, cur_if);
2498*4882a593Smuzhiyun 		if (chan_info->chan) {
2499*4882a593Smuzhiyun 			if (cur_if->ifmode == ISTA_MODE && wl_ext_dfs_chan(chan_info))
2500*4882a593Smuzhiyun 				wl_ext_save_master_channel(apsta_params, chan_info->chan);
2501*4882a593Smuzhiyun 			target_if = wl_ext_move_other_channel(apsta_params, cur_if);
2502*4882a593Smuzhiyun 			if (dhd->conf->chip == BCM4359_CHIP_ID &&
2503*4882a593Smuzhiyun 					cur_if->ifmode == ISTA_MODE && !target_if) {
2504*4882a593Smuzhiyun 				/* this is a WAR to fix 4359 fw trap issue as below procedure:
2505*4882a593Smuzhiyun 				 * step1: enable wlan1 on channel 1
2506*4882a593Smuzhiyun 				 * step2: enable wlan2 on channel 36
2507*4882a593Smuzhiyun 				 * step3: enable wlan0 to connect channel 1 AP, then it will fw trap
2508*4882a593Smuzhiyun 				*/
2509*4882a593Smuzhiyun 				wl_ext_if_reenabled(apsta_params, IAP_MODE, chan_info->chan);
2510*4882a593Smuzhiyun 			}
2511*4882a593Smuzhiyun 		}
2512*4882a593Smuzhiyun 		if (cur_if->ifmode == ISTA_MODE) {
2513*4882a593Smuzhiyun 			if (conf->war & SET_CHAN_INCONN && chan_info->chan) {
2514*4882a593Smuzhiyun 				chanspec_t fw_chspec;
2515*4882a593Smuzhiyun 			    IAPSTA_INFO(dev->name, "set channel %d\n", chan_info->chan);
2516*4882a593Smuzhiyun 			    wl_ext_set_chanspec(cur_if->dev, chan_info, &fw_chspec);
2517*4882a593Smuzhiyun 			}
2518*4882a593Smuzhiyun 			wl_set_isam_status(cur_if, STA_CONNECTING);
2519*4882a593Smuzhiyun 		}
2520*4882a593Smuzhiyun 		chanspec = wf_create_chspec_from_primary(chan_info->chan,
2521*4882a593Smuzhiyun 			CHSPEC_BW(chanspec), wl_ext_wlcband_to_chanspec_band(chan_info->band));
2522*4882a593Smuzhiyun 		mutex_unlock(&apsta_params->usr_sync);
2523*4882a593Smuzhiyun 	}
2524*4882a593Smuzhiyun 
2525*4882a593Smuzhiyun 	return chanspec;
2526*4882a593Smuzhiyun }
2527*4882a593Smuzhiyun 
2528*4882a593Smuzhiyun static int
wl_ext_iftype_to_ifmode(struct net_device * net,int wl_iftype,ifmode_t * ifmode)2529*4882a593Smuzhiyun wl_ext_iftype_to_ifmode(struct net_device *net, int wl_iftype, ifmode_t *ifmode)
2530*4882a593Smuzhiyun {
2531*4882a593Smuzhiyun 	switch (wl_iftype) {
2532*4882a593Smuzhiyun 		case WL_IF_TYPE_STA:
2533*4882a593Smuzhiyun 			*ifmode = ISTA_MODE;
2534*4882a593Smuzhiyun 			break;
2535*4882a593Smuzhiyun 		case WL_IF_TYPE_AP:
2536*4882a593Smuzhiyun 			*ifmode = IAP_MODE;
2537*4882a593Smuzhiyun 			break;
2538*4882a593Smuzhiyun 		case WL_IF_TYPE_P2P_GO:
2539*4882a593Smuzhiyun 			*ifmode = IGO_MODE;
2540*4882a593Smuzhiyun 			break;
2541*4882a593Smuzhiyun 		case WL_IF_TYPE_P2P_GC:
2542*4882a593Smuzhiyun 			*ifmode = IGC_MODE;
2543*4882a593Smuzhiyun 			break;
2544*4882a593Smuzhiyun 		default:
2545*4882a593Smuzhiyun 			IAPSTA_ERROR(net->name, "Unknown interface wl_iftype:0x%x\n", wl_iftype);
2546*4882a593Smuzhiyun 			return BCME_ERROR;
2547*4882a593Smuzhiyun 	}
2548*4882a593Smuzhiyun 	return BCME_OK;
2549*4882a593Smuzhiyun }
2550*4882a593Smuzhiyun 
2551*4882a593Smuzhiyun void
wl_ext_iapsta_update_iftype(struct net_device * net,int wl_iftype)2552*4882a593Smuzhiyun wl_ext_iapsta_update_iftype(struct net_device *net, int wl_iftype)
2553*4882a593Smuzhiyun {
2554*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
2555*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2556*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
2557*4882a593Smuzhiyun 	int ifidx = dhd_net2idx(dhd->info, net);
2558*4882a593Smuzhiyun 
2559*4882a593Smuzhiyun 	IAPSTA_TRACE(net->name, "ifidx=%d, wl_iftype=%d\n", ifidx, wl_iftype);
2560*4882a593Smuzhiyun 
2561*4882a593Smuzhiyun 	if (ifidx < MAX_IF_NUM) {
2562*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[ifidx];
2563*4882a593Smuzhiyun 	}
2564*4882a593Smuzhiyun 
2565*4882a593Smuzhiyun 	if (cur_if) {
2566*4882a593Smuzhiyun 		if (wl_iftype == WL_IF_TYPE_STA) {
2567*4882a593Smuzhiyun 			cur_if->ifmode = ISTA_MODE;
2568*4882a593Smuzhiyun 			cur_if->prio = PRIO_STA;
2569*4882a593Smuzhiyun 			cur_if->vsdb = TRUE;
2570*4882a593Smuzhiyun 			cur_if->prefix = 'S';
2571*4882a593Smuzhiyun #ifdef WL_STATIC_IF
2572*4882a593Smuzhiyun 			dhd_conf_preinit_ioctls_sta(dhd, ifidx);
2573*4882a593Smuzhiyun #endif /* WL_STATIC_IF */
2574*4882a593Smuzhiyun 		} else if (wl_iftype == WL_IF_TYPE_AP && cur_if->ifmode != IMESH_MODE) {
2575*4882a593Smuzhiyun 			cur_if->ifmode = IAP_MODE;
2576*4882a593Smuzhiyun 			cur_if->prio = PRIO_AP;
2577*4882a593Smuzhiyun 			cur_if->vsdb = FALSE;
2578*4882a593Smuzhiyun 			cur_if->prefix = 'A';
2579*4882a593Smuzhiyun 		} else if (wl_iftype == WL_IF_TYPE_P2P_GO) {
2580*4882a593Smuzhiyun 			cur_if->ifmode = IGO_MODE;
2581*4882a593Smuzhiyun 			cur_if->prio = PRIO_P2P;
2582*4882a593Smuzhiyun 			cur_if->vsdb = TRUE;
2583*4882a593Smuzhiyun 			cur_if->prefix = 'P';
2584*4882a593Smuzhiyun 		} else if (wl_iftype == WL_IF_TYPE_P2P_GC) {
2585*4882a593Smuzhiyun 			cur_if->ifmode = IGC_MODE;
2586*4882a593Smuzhiyun 			cur_if->prio = PRIO_P2P;
2587*4882a593Smuzhiyun 			cur_if->vsdb = TRUE;
2588*4882a593Smuzhiyun 			cur_if->prefix = 'P';
2589*4882a593Smuzhiyun 		} else if (wl_iftype == WL_IF_TYPE_IBSS) {
2590*4882a593Smuzhiyun 			cur_if->ifmode = IAP_MODE;
2591*4882a593Smuzhiyun 			cur_if->prio = PRIO_AP;
2592*4882a593Smuzhiyun 			cur_if->vsdb = FALSE;
2593*4882a593Smuzhiyun 			cur_if->prefix = 'H';
2594*4882a593Smuzhiyun 			wl_ext_iovar_setint(cur_if->dev, "assoc_retry_max", 3);
2595*4882a593Smuzhiyun 		}
2596*4882a593Smuzhiyun 	}
2597*4882a593Smuzhiyun }
2598*4882a593Smuzhiyun 
2599*4882a593Smuzhiyun void
wl_ext_iapsta_ifadding(struct net_device * net,int ifidx)2600*4882a593Smuzhiyun wl_ext_iapsta_ifadding(struct net_device *net, int ifidx)
2601*4882a593Smuzhiyun {
2602*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
2603*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2604*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
2605*4882a593Smuzhiyun 
2606*4882a593Smuzhiyun 	IAPSTA_TRACE(net->name, "ifidx=%d\n", ifidx);
2607*4882a593Smuzhiyun 	if (ifidx < MAX_IF_NUM) {
2608*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[ifidx];
2609*4882a593Smuzhiyun 		wl_set_isam_status(cur_if, IF_ADDING);
2610*4882a593Smuzhiyun 	}
2611*4882a593Smuzhiyun }
2612*4882a593Smuzhiyun 
2613*4882a593Smuzhiyun bool
wl_ext_iapsta_iftype_enabled(struct net_device * net,int wl_iftype)2614*4882a593Smuzhiyun wl_ext_iapsta_iftype_enabled(struct net_device *net, int wl_iftype)
2615*4882a593Smuzhiyun {
2616*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
2617*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2618*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
2619*4882a593Smuzhiyun 	ifmode_t ifmode = 0;
2620*4882a593Smuzhiyun 
2621*4882a593Smuzhiyun 	wl_ext_iftype_to_ifmode(net, wl_iftype, &ifmode);
2622*4882a593Smuzhiyun 	cur_if = wl_ext_if_enabled(apsta_params, ifmode);
2623*4882a593Smuzhiyun 	if (cur_if)
2624*4882a593Smuzhiyun 		return TRUE;
2625*4882a593Smuzhiyun 
2626*4882a593Smuzhiyun 	return FALSE;
2627*4882a593Smuzhiyun }
2628*4882a593Smuzhiyun 
2629*4882a593Smuzhiyun bool
wl_ext_iapsta_mesh_creating(struct net_device * net)2630*4882a593Smuzhiyun wl_ext_iapsta_mesh_creating(struct net_device *net)
2631*4882a593Smuzhiyun {
2632*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
2633*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2634*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
2635*4882a593Smuzhiyun 	int i;
2636*4882a593Smuzhiyun 
2637*4882a593Smuzhiyun 	if (apsta_params) {
2638*4882a593Smuzhiyun 		for (i=0; i<MAX_IF_NUM; i++) {
2639*4882a593Smuzhiyun 			cur_if = &apsta_params->if_info[i];
2640*4882a593Smuzhiyun 			if (cur_if->ifmode==IMESH_MODE && wl_get_isam_status(cur_if, IF_ADDING))
2641*4882a593Smuzhiyun 				return TRUE;
2642*4882a593Smuzhiyun 		}
2643*4882a593Smuzhiyun 	}
2644*4882a593Smuzhiyun 	return FALSE;
2645*4882a593Smuzhiyun }
2646*4882a593Smuzhiyun 
2647*4882a593Smuzhiyun void
wl_ext_fw_reinit_incsa(struct net_device * dev)2648*4882a593Smuzhiyun wl_ext_fw_reinit_incsa(struct net_device *dev)
2649*4882a593Smuzhiyun {
2650*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
2651*4882a593Smuzhiyun 	struct dhd_conf *conf = dhd->conf;
2652*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
2653*4882a593Smuzhiyun 
2654*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
2655*4882a593Smuzhiyun 	if (!cur_if)
2656*4882a593Smuzhiyun 		return;
2657*4882a593Smuzhiyun 
2658*4882a593Smuzhiyun 	if (conf->war & FW_REINIT_INCSA) {
2659*4882a593Smuzhiyun 		if (cur_if->ifmode == ISTA_MODE &&
2660*4882a593Smuzhiyun 				wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
2661*4882a593Smuzhiyun 			IAPSTA_INFO(dev->name, "wl reinit\n");
2662*4882a593Smuzhiyun 			wl_ext_ioctl(dev, WLC_INIT, NULL, 0, 1);
2663*4882a593Smuzhiyun 		}
2664*4882a593Smuzhiyun 	}
2665*4882a593Smuzhiyun }
2666*4882a593Smuzhiyun 
2667*4882a593Smuzhiyun #ifdef WL_EXT_RECONNECT
2668*4882a593Smuzhiyun static void
wl_ext_reconnect_timeout(unsigned long data)2669*4882a593Smuzhiyun wl_ext_reconnect_timeout(unsigned long data)
2670*4882a593Smuzhiyun {
2671*4882a593Smuzhiyun 	struct net_device *dev = (struct net_device *)data;
2672*4882a593Smuzhiyun 
2673*4882a593Smuzhiyun 	if (!dev) {
2674*4882a593Smuzhiyun 		IAPSTA_ERROR("wlan", "dev is not ready\n");
2675*4882a593Smuzhiyun 		return;
2676*4882a593Smuzhiyun 	}
2677*4882a593Smuzhiyun 	IAPSTA_ERROR(dev->name, "timer expired\n");
2678*4882a593Smuzhiyun 	wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WLC_E_STATUS_SUCCESS);
2679*4882a593Smuzhiyun }
2680*4882a593Smuzhiyun 
2681*4882a593Smuzhiyun #ifdef WL_EXT_DISCONNECT_RECONNECT
2682*4882a593Smuzhiyun static bool
wl_ext_disc_recon_retry(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)2683*4882a593Smuzhiyun wl_ext_disc_recon_retry(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
2684*4882a593Smuzhiyun {
2685*4882a593Smuzhiyun 	int sta_disc_recon_cnt = cur_if->sta_disc_recon_cnt;
2686*4882a593Smuzhiyun 	struct osl_timespec *sta_disc_conn_ts = &cur_if->sta_disc_conn_ts;
2687*4882a593Smuzhiyun 	struct osl_timespec cur_ts;
2688*4882a593Smuzhiyun 	uint32 diff_ms = 0;
2689*4882a593Smuzhiyun 	bool retry = FALSE;
2690*4882a593Smuzhiyun 
2691*4882a593Smuzhiyun 	if (sta_disc_recon_cnt == 0)
2692*4882a593Smuzhiyun 		osl_do_gettimeofday(sta_disc_conn_ts);
2693*4882a593Smuzhiyun 
2694*4882a593Smuzhiyun 	osl_do_gettimeofday(&cur_ts);
2695*4882a593Smuzhiyun 	diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_conn_ts)/1000;
2696*4882a593Smuzhiyun 
2697*4882a593Smuzhiyun 	IAPSTA_INFO(cur_if->ifname, "sta_disc_recon_cnt=%d, diff_ms = %dms\n",
2698*4882a593Smuzhiyun 		sta_disc_recon_cnt, diff_ms);
2699*4882a593Smuzhiyun 	if (sta_disc_recon_cnt >= STA_DISCONNECT_RECONNECT_MAX) {
2700*4882a593Smuzhiyun 		if (diff_ms >= STA_DISCONNECT_RECONNECT_TIMEOUT) {
2701*4882a593Smuzhiyun 			osl_do_gettimeofday(sta_disc_conn_ts);
2702*4882a593Smuzhiyun 			cur_if->sta_disc_recon_cnt = 0;
2703*4882a593Smuzhiyun 			retry = TRUE;
2704*4882a593Smuzhiyun 		} else {
2705*4882a593Smuzhiyun 			retry = FALSE;
2706*4882a593Smuzhiyun 		}
2707*4882a593Smuzhiyun 	} else {
2708*4882a593Smuzhiyun 		retry = TRUE;
2709*4882a593Smuzhiyun 	}
2710*4882a593Smuzhiyun 
2711*4882a593Smuzhiyun 	if (retry)
2712*4882a593Smuzhiyun 		cur_if->sta_disc_recon_cnt++;
2713*4882a593Smuzhiyun 
2714*4882a593Smuzhiyun 	return retry;
2715*4882a593Smuzhiyun }
2716*4882a593Smuzhiyun #endif /* WL_EXT_DISCONNECT_RECONNECT */
2717*4882a593Smuzhiyun 
2718*4882a593Smuzhiyun static void
wl_ext_update_assoc_info(struct net_device * dev,bool reassoc)2719*4882a593Smuzhiyun wl_ext_update_assoc_info(struct net_device *dev, bool reassoc)
2720*4882a593Smuzhiyun {
2721*4882a593Smuzhiyun #ifndef WL_REASSOC_BCAST
2722*4882a593Smuzhiyun 	dhd_pub_t *dhd = dhd_get_pub(dev);
2723*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2724*4882a593Smuzhiyun 	struct wl_chan_info chan_info;
2725*4882a593Smuzhiyun #endif
2726*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2727*4882a593Smuzhiyun 	wlcfg_assoc_info_t *assoc_info;
2728*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
2729*4882a593Smuzhiyun 
2730*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
2731*4882a593Smuzhiyun 	if (cur_if) {
2732*4882a593Smuzhiyun 		assoc_info = &cur_if->assoc_info;
2733*4882a593Smuzhiyun 		assoc_info->reassoc = reassoc;
2734*4882a593Smuzhiyun 		assoc_info->bssid_hint = false;
2735*4882a593Smuzhiyun #ifdef WL_REASSOC_BCAST
2736*4882a593Smuzhiyun 		assoc_info->chan_cnt = 0;
2737*4882a593Smuzhiyun 		assoc_info->chanspecs[0] = 0;
2738*4882a593Smuzhiyun 		memcpy(&assoc_info->bssid, &ether_bcast, ETHER_ADDR_LEN);
2739*4882a593Smuzhiyun #else
2740*4882a593Smuzhiyun 		assoc_info->chanspecs[0] = wl_ext_get_chanspec(dev, &chan_info);
2741*4882a593Smuzhiyun 		if (assoc_info->chanspecs[0] && reassoc) {
2742*4882a593Smuzhiyun 			assoc_info->chan_cnt = 1;
2743*4882a593Smuzhiyun 			wldev_ioctl(dev, WLC_GET_BSSID, &cur_if->bssid, ETHER_ADDR_LEN, 0);
2744*4882a593Smuzhiyun 			memcpy(&assoc_info->bssid, &cur_if->bssid, ETHER_ADDR_LEN);
2745*4882a593Smuzhiyun 		} else {
2746*4882a593Smuzhiyun 			assoc_info->chan_cnt = 0;
2747*4882a593Smuzhiyun 			memcpy(&assoc_info->bssid, &ether_bcast, ETHER_ADDR_LEN);
2748*4882a593Smuzhiyun 		}
2749*4882a593Smuzhiyun #endif /* WL_REASSOC_BCAST */
2750*4882a593Smuzhiyun 		if (!ETHER_ISBCAST(assoc_info->bssid))
2751*4882a593Smuzhiyun 			assoc_info->targeted_join = true;
2752*4882a593Smuzhiyun 		else
2753*4882a593Smuzhiyun 			assoc_info->targeted_join = false;
2754*4882a593Smuzhiyun 		wl_get_assoc_channels(cfg, dev, assoc_info);
2755*4882a593Smuzhiyun 	}
2756*4882a593Smuzhiyun }
2757*4882a593Smuzhiyun 
2758*4882a593Smuzhiyun static int
wl_ext_connect_retry(struct net_device * dev,wl_event_msg_t * e)2759*4882a593Smuzhiyun wl_ext_connect_retry(struct net_device *dev, wl_event_msg_t *e)
2760*4882a593Smuzhiyun {
2761*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
2762*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2763*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
2764*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2765*4882a593Smuzhiyun 	struct osl_timespec cur_ts, *sta_conn_ts;
2766*4882a593Smuzhiyun 	wlcfg_assoc_info_t *assoc_info;
2767*4882a593Smuzhiyun 	uint32 diff_ms = 0;
2768*4882a593Smuzhiyun 	int max_wait_time = 0, ret = 0;
2769*4882a593Smuzhiyun 	bool connecting, handshaking, associated;
2770*4882a593Smuzhiyun 	uint32 etype = ntoh32(e->event_type);
2771*4882a593Smuzhiyun 	uint32 status = ntoh32(e->status);
2772*4882a593Smuzhiyun 
2773*4882a593Smuzhiyun 	if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
2774*4882a593Smuzhiyun 		WL_MSG(dev->name, "skip connect retry due to disconnecting\n");
2775*4882a593Smuzhiyun 		return BCME_BADADDR;
2776*4882a593Smuzhiyun 	}
2777*4882a593Smuzhiyun 
2778*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
2779*4882a593Smuzhiyun 	if (!cur_if)
2780*4882a593Smuzhiyun 		return ret;
2781*4882a593Smuzhiyun 	sta_conn_ts = &cur_if->sta_conn_ts;
2782*4882a593Smuzhiyun 	connecting = wl_ext_sta_connecting(dev);
2783*4882a593Smuzhiyun 	handshaking = wl_ext_sta_handshaking(dev);
2784*4882a593Smuzhiyun 
2785*4882a593Smuzhiyun 	mutex_unlock(&apsta_params->in4way_sync);
2786*4882a593Smuzhiyun 	mutex_lock(&cfg->connect_sync);
2787*4882a593Smuzhiyun 
2788*4882a593Smuzhiyun 	osl_do_gettimeofday(&cur_ts);
2789*4882a593Smuzhiyun 	diff_ms = osl_do_gettimediff(&cur_ts, sta_conn_ts)/1000;
2790*4882a593Smuzhiyun 	associated = wl_ext_associated(dev);
2791*4882a593Smuzhiyun 	assoc_info = &cur_if->assoc_info;
2792*4882a593Smuzhiyun 
2793*4882a593Smuzhiyun 	if (connecting && diff_ms < STA_CONNECT_TIMEOUT &&
2794*4882a593Smuzhiyun 			!wl_get_drv_status(cfg, DISCONNECTING, dev)) {
2795*4882a593Smuzhiyun 		if (etype == WLC_E_SET_SSID && (status == WLC_E_STATUS_NO_NETWORKS ||
2796*4882a593Smuzhiyun 				status == WLC_E_STATUS_NO_ACK)) {
2797*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->reconnect_timer, 0);
2798*4882a593Smuzhiyun 			if (assoc_info->reassoc && associated && !handshaking) {
2799*4882a593Smuzhiyun 				/* There are two cases will come in to retry reassoc:
2800*4882a593Smuzhiyun 				 * 1) reconnect from wpa_supplicant
2801*4882a593Smuzhiyun 				 * 2) fw roam
2802*4882a593Smuzhiyun 				 */
2803*4882a593Smuzhiyun 				if (associated)
2804*4882a593Smuzhiyun 					bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN);
2805*4882a593Smuzhiyun 				WL_MSG(dev->name, "retry reassoc\n");
2806*4882a593Smuzhiyun 				if (wl_handle_reassoc(cfg, dev, assoc_info))
2807*4882a593Smuzhiyun 					goto exit;
2808*4882a593Smuzhiyun 				if (assoc_info->chan_cnt == 0)
2809*4882a593Smuzhiyun 					max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT;
2810*4882a593Smuzhiyun 				else
2811*4882a593Smuzhiyun 					max_wait_time = STA_RECONNECT_RETRY_TIMEOUT +
2812*4882a593Smuzhiyun 						(WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS * assoc_info->chan_cnt);
2813*4882a593Smuzhiyun 				max_wait_time = min(max_wait_time, STA_CONNECT_FULL_CHAN_TIMEOUT);
2814*4882a593Smuzhiyun 			}
2815*4882a593Smuzhiyun 			else {
2816*4882a593Smuzhiyun 				/* There is one case will come in to retry join:
2817*4882a593Smuzhiyun 				 * 1) connect from wpa_supplicant
2818*4882a593Smuzhiyun 				 */
2819*4882a593Smuzhiyun 				WL_MSG(dev->name, "retry join\n");
2820*4882a593Smuzhiyun 				if (associated) {
2821*4882a593Smuzhiyun 					bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN);
2822*4882a593Smuzhiyun 					wl_cfg80211_disassoc(dev, WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT);
2823*4882a593Smuzhiyun 				}
2824*4882a593Smuzhiyun 				if (wl_handle_join(cfg, dev, assoc_info))
2825*4882a593Smuzhiyun 					goto exit;
2826*4882a593Smuzhiyun 				if (assoc_info->chan_cnt == 0)
2827*4882a593Smuzhiyun 					max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT;
2828*4882a593Smuzhiyun 				else
2829*4882a593Smuzhiyun 					max_wait_time = STA_CONNECT_RETRY_TIMEOUT +
2830*4882a593Smuzhiyun 						(WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS * assoc_info->chan_cnt);
2831*4882a593Smuzhiyun 				max_wait_time = min(max_wait_time, STA_CONNECT_FULL_CHAN_TIMEOUT);
2832*4882a593Smuzhiyun 			}
2833*4882a593Smuzhiyun 			IAPSTA_INFO(dev->name, "reconnect %dms later\n", max_wait_time);
2834*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time);
2835*4882a593Smuzhiyun 		}
2836*4882a593Smuzhiyun 		ret = BCME_ERROR;
2837*4882a593Smuzhiyun 	}
2838*4882a593Smuzhiyun #ifdef WL_EXT_DISCONNECT_RECONNECT
2839*4882a593Smuzhiyun 	else if (cur_if->conn_state >= CONN_STATE_CONNECTED &&
2840*4882a593Smuzhiyun 			!wl_get_drv_status(cfg, DISCONNECTING, dev) &&
2841*4882a593Smuzhiyun 			wl_get_drv_status(cfg, CONNECTED, dev)) {
2842*4882a593Smuzhiyun 		if (etype == WLC_E_DISASSOC_IND || etype == WLC_E_DEAUTH_IND) {
2843*4882a593Smuzhiyun 			/* There is one case will come in to retry join:
2844*4882a593Smuzhiyun 			 * 1) receive disconnect from AP after connected
2845*4882a593Smuzhiyun 			 */
2846*4882a593Smuzhiyun 			if (wl_ext_disc_recon_retry(apsta_params, cur_if)) {
2847*4882a593Smuzhiyun 				int wpa_auth = 0;
2848*4882a593Smuzhiyun 				WL_MSG(dev->name, "retry join cnt %d\n", cur_if->sta_disc_recon_cnt);
2849*4882a593Smuzhiyun 				bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN);
2850*4882a593Smuzhiyun 				wl_ext_update_assoc_info(dev, FALSE);
2851*4882a593Smuzhiyun #ifdef DHD_LOSSLESS_ROAMING
2852*4882a593Smuzhiyun 				wl_ext_send_event_msg(dev, WLC_E_ROAM_PREP, WLC_E_STATUS_SUCCESS, WLC_E_REASON_DEAUTH);
2853*4882a593Smuzhiyun #endif
2854*4882a593Smuzhiyun 				if (wl_handle_join(cfg, dev, assoc_info))
2855*4882a593Smuzhiyun 					goto exit;
2856*4882a593Smuzhiyun 				wl_timer_mod(dhd, &cur_if->connect_timer, STA_CONNECT_TIMEOUT);
2857*4882a593Smuzhiyun 				osl_do_gettimeofday(sta_conn_ts);
2858*4882a593Smuzhiyun 				wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTING);
2859*4882a593Smuzhiyun 				wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
2860*4882a593Smuzhiyun 				if (!(wpa_auth & (WPA3_AUTH_SAE_PSK|0x20))) {
2861*4882a593Smuzhiyun 					if (assoc_info->chan_cnt == 0)
2862*4882a593Smuzhiyun 						max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT;
2863*4882a593Smuzhiyun 					else
2864*4882a593Smuzhiyun 						max_wait_time = STA_CONNECT_RETRY_TIMEOUT +
2865*4882a593Smuzhiyun 							(WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS * assoc_info->chan_cnt);
2866*4882a593Smuzhiyun 					max_wait_time = min(max_wait_time, STA_CONNECT_FULL_CHAN_TIMEOUT);
2867*4882a593Smuzhiyun 					IAPSTA_INFO(dev->name, "reconnect %dms later\n", max_wait_time);
2868*4882a593Smuzhiyun 					wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time);
2869*4882a593Smuzhiyun 				}
2870*4882a593Smuzhiyun 				ret = BCME_ERROR;
2871*4882a593Smuzhiyun 			}
2872*4882a593Smuzhiyun 			else {
2873*4882a593Smuzhiyun 				WL_MSG(dev->name, "out of retry cnt %d within %dms\n",
2874*4882a593Smuzhiyun 					cur_if->sta_disc_recon_cnt, STA_DISCONNECT_RECONNECT_TIMEOUT);
2875*4882a593Smuzhiyun 			}
2876*4882a593Smuzhiyun 		}
2877*4882a593Smuzhiyun 	}
2878*4882a593Smuzhiyun #endif /* WL_EXT_DISCONNECT_RECONNECT */
2879*4882a593Smuzhiyun 
2880*4882a593Smuzhiyun exit:
2881*4882a593Smuzhiyun 	mutex_unlock(&cfg->connect_sync);
2882*4882a593Smuzhiyun 	mutex_lock(&apsta_params->in4way_sync);
2883*4882a593Smuzhiyun 
2884*4882a593Smuzhiyun 	return ret;
2885*4882a593Smuzhiyun }
2886*4882a593Smuzhiyun 
2887*4882a593Smuzhiyun static void
wl_ext_set_connect_retry(struct net_device * dev,void * context)2888*4882a593Smuzhiyun wl_ext_set_connect_retry(struct net_device *dev, void *context)
2889*4882a593Smuzhiyun {
2890*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
2891*4882a593Smuzhiyun 	wlcfg_assoc_info_t *assoc_info = (wlcfg_assoc_info_t *)context;
2892*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
2893*4882a593Smuzhiyun 	int max_wait_time;
2894*4882a593Smuzhiyun 	int wpa_auth = 0;
2895*4882a593Smuzhiyun 
2896*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
2897*4882a593Smuzhiyun 	if (!cur_if)
2898*4882a593Smuzhiyun 		return;
2899*4882a593Smuzhiyun 
2900*4882a593Smuzhiyun 	wl_timer_mod(dhd, &cur_if->reconnect_timer, 0);
2901*4882a593Smuzhiyun 	memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t));
2902*4882a593Smuzhiyun 	wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
2903*4882a593Smuzhiyun 	if (!(wpa_auth & (WPA3_AUTH_SAE_PSK|0x20) && assoc_info)) {
2904*4882a593Smuzhiyun 		memcpy(&cur_if->bssid, assoc_info->bssid, ETHER_ADDR_LEN);
2905*4882a593Smuzhiyun 		memcpy(&cur_if->assoc_info, assoc_info, sizeof(wlcfg_assoc_info_t));
2906*4882a593Smuzhiyun 		if (assoc_info->chan_cnt == 0)
2907*4882a593Smuzhiyun 			max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT;
2908*4882a593Smuzhiyun 		else if (assoc_info->reassoc)
2909*4882a593Smuzhiyun 			max_wait_time = STA_RECONNECT_RETRY_TIMEOUT;
2910*4882a593Smuzhiyun 		else
2911*4882a593Smuzhiyun 			max_wait_time = STA_CONNECT_RETRY_TIMEOUT;
2912*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "reconnect %dms later\n", max_wait_time);
2913*4882a593Smuzhiyun 		wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time);
2914*4882a593Smuzhiyun 	}
2915*4882a593Smuzhiyun }
2916*4882a593Smuzhiyun #endif /* WL_EXT_RECONNECT */
2917*4882a593Smuzhiyun 
2918*4882a593Smuzhiyun #ifdef STA_MGMT
2919*4882a593Smuzhiyun static void
wl_ext_flush_sta_list(struct net_device * net,int ifidx)2920*4882a593Smuzhiyun wl_ext_flush_sta_list(struct net_device *net, int ifidx)
2921*4882a593Smuzhiyun {
2922*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
2923*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2924*4882a593Smuzhiyun 	wl_sta_info_t *node, *next;
2925*4882a593Smuzhiyun 
2926*4882a593Smuzhiyun 	list_for_each_entry_safe(node, next, &apsta_params->sta_list, list) {
2927*4882a593Smuzhiyun 		if (node->ifidx == ifidx || ifidx == 0xFF) {
2928*4882a593Smuzhiyun 			IAPSTA_INFO(net->name, "Del BSSID %pM\n", &node->bssid);
2929*4882a593Smuzhiyun 			list_del(&node->list);
2930*4882a593Smuzhiyun 			kfree(node);
2931*4882a593Smuzhiyun 		}
2932*4882a593Smuzhiyun 	}
2933*4882a593Smuzhiyun }
2934*4882a593Smuzhiyun 
2935*4882a593Smuzhiyun bool
wl_ext_del_sta_info(struct net_device * net,u8 * bssid)2936*4882a593Smuzhiyun wl_ext_del_sta_info(struct net_device *net, u8 *bssid)
2937*4882a593Smuzhiyun {
2938*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
2939*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2940*4882a593Smuzhiyun 	int ifidx = dhd_net2idx(dhd->info, net);
2941*4882a593Smuzhiyun 	wl_sta_info_t *node, *next;
2942*4882a593Smuzhiyun 	bool in_list = FALSE;
2943*4882a593Smuzhiyun 
2944*4882a593Smuzhiyun 	list_for_each_entry_safe(node, next, &apsta_params->sta_list, list) {
2945*4882a593Smuzhiyun 		if (node->ifidx == ifidx && !memcmp(&node->bssid, bssid, ETHER_ADDR_LEN)) {
2946*4882a593Smuzhiyun 			IAPSTA_INFO(net->name, "Del BSSID %pM\n", &node->bssid);
2947*4882a593Smuzhiyun 			in_list = TRUE;
2948*4882a593Smuzhiyun 			list_del(&node->list);
2949*4882a593Smuzhiyun 			kfree(node);
2950*4882a593Smuzhiyun 		}
2951*4882a593Smuzhiyun 	}
2952*4882a593Smuzhiyun 	return in_list;
2953*4882a593Smuzhiyun }
2954*4882a593Smuzhiyun 
2955*4882a593Smuzhiyun bool
wl_ext_add_sta_info(struct net_device * net,u8 * bssid)2956*4882a593Smuzhiyun wl_ext_add_sta_info(struct net_device *net, u8 *bssid)
2957*4882a593Smuzhiyun {
2958*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
2959*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2960*4882a593Smuzhiyun 	int ifidx = dhd_net2idx(dhd->info, net);
2961*4882a593Smuzhiyun 	wl_sta_info_t *node, *next, *leaf;
2962*4882a593Smuzhiyun 
2963*4882a593Smuzhiyun 	list_for_each_entry_safe(node, next, &apsta_params->sta_list, list) {
2964*4882a593Smuzhiyun 		if (node->ifidx == ifidx && !memcmp(&node->bssid, bssid, ETHER_ADDR_LEN)) {
2965*4882a593Smuzhiyun 			IAPSTA_INFO(net->name, "BSSID %pM already in list\n", bssid);
2966*4882a593Smuzhiyun 			return FALSE;
2967*4882a593Smuzhiyun 		}
2968*4882a593Smuzhiyun 	}
2969*4882a593Smuzhiyun 
2970*4882a593Smuzhiyun 	leaf = kmalloc(sizeof(wl_sta_info_t), GFP_KERNEL);
2971*4882a593Smuzhiyun 	if (!leaf) {
2972*4882a593Smuzhiyun 		IAPSTA_ERROR(net->name, "Memory alloc failure %d\n",
2973*4882a593Smuzhiyun 			(int)sizeof(wl_sta_info_t));
2974*4882a593Smuzhiyun 		return FALSE;
2975*4882a593Smuzhiyun 	}
2976*4882a593Smuzhiyun 	IAPSTA_INFO(net->name, "Add BSSID %pM in the leaf\n", bssid);
2977*4882a593Smuzhiyun 	leaf->ifidx = ifidx;
2978*4882a593Smuzhiyun 	memcpy(&leaf->bssid, bssid, ETHER_ADDR_LEN);
2979*4882a593Smuzhiyun 	list_add_tail(&leaf->list, &apsta_params->sta_list);
2980*4882a593Smuzhiyun 
2981*4882a593Smuzhiyun 	return TRUE;
2982*4882a593Smuzhiyun }
2983*4882a593Smuzhiyun #endif /* STA_MGMT */
2984*4882a593Smuzhiyun #endif /* WL_CFG80211 */
2985*4882a593Smuzhiyun 
2986*4882a593Smuzhiyun #ifndef WL_STATIC_IF
2987*4882a593Smuzhiyun s32
wl_ext_add_del_bss(struct net_device * ndev,s32 bsscfg_idx,int iftype,s32 del,u8 * addr)2988*4882a593Smuzhiyun wl_ext_add_del_bss(struct net_device *ndev, s32 bsscfg_idx,
2989*4882a593Smuzhiyun 	int iftype, s32 del, u8 *addr)
2990*4882a593Smuzhiyun {
2991*4882a593Smuzhiyun 	s32 ret = BCME_OK;
2992*4882a593Smuzhiyun 	s32 val = 0;
2993*4882a593Smuzhiyun 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
2994*4882a593Smuzhiyun 	struct {
2995*4882a593Smuzhiyun 		s32 cfg;
2996*4882a593Smuzhiyun 		s32 val;
2997*4882a593Smuzhiyun 		struct ether_addr ea;
2998*4882a593Smuzhiyun 	} bss_setbuf;
2999*4882a593Smuzhiyun 
3000*4882a593Smuzhiyun 	IAPSTA_TRACE(ndev->name, "wl_iftype:%d del:%d \n", iftype, del);
3001*4882a593Smuzhiyun 
3002*4882a593Smuzhiyun 	bzero(&bss_setbuf, sizeof(bss_setbuf));
3003*4882a593Smuzhiyun 
3004*4882a593Smuzhiyun 	/* AP=2, STA=3, up=1, down=0, val=-1 */
3005*4882a593Smuzhiyun 	if (del) {
3006*4882a593Smuzhiyun 		val = WLC_AP_IOV_OP_DELETE;
3007*4882a593Smuzhiyun 	} else if (iftype == WL_INTERFACE_TYPE_AP) {
3008*4882a593Smuzhiyun 		/* Add/role change to AP Interface */
3009*4882a593Smuzhiyun 		IAPSTA_TRACE(ndev->name, "Adding AP Interface\n");
3010*4882a593Smuzhiyun 		val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
3011*4882a593Smuzhiyun 	} else if (iftype == WL_INTERFACE_TYPE_STA) {
3012*4882a593Smuzhiyun 		/* Add/role change to STA Interface */
3013*4882a593Smuzhiyun 		IAPSTA_TRACE(ndev->name, "Adding STA Interface\n");
3014*4882a593Smuzhiyun 		val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
3015*4882a593Smuzhiyun 	} else {
3016*4882a593Smuzhiyun 		IAPSTA_ERROR(ndev->name, "add_del_bss NOT supported for IFACE type:0x%x", iftype);
3017*4882a593Smuzhiyun 		return -EINVAL;
3018*4882a593Smuzhiyun 	}
3019*4882a593Smuzhiyun 
3020*4882a593Smuzhiyun 	if (!del) {
3021*4882a593Smuzhiyun 		wl_ext_bss_iovar_war(ndev, &val);
3022*4882a593Smuzhiyun 	}
3023*4882a593Smuzhiyun 
3024*4882a593Smuzhiyun 	bss_setbuf.cfg = htod32(bsscfg_idx);
3025*4882a593Smuzhiyun 	bss_setbuf.val = htod32(val);
3026*4882a593Smuzhiyun 
3027*4882a593Smuzhiyun 	if (addr) {
3028*4882a593Smuzhiyun 		memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
3029*4882a593Smuzhiyun 	}
3030*4882a593Smuzhiyun 
3031*4882a593Smuzhiyun 	IAPSTA_INFO(ndev->name, "wl bss %d bssidx:%d\n", val, bsscfg_idx);
3032*4882a593Smuzhiyun 	ret = wl_ext_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
3033*4882a593Smuzhiyun 		ioctl_buf, WLC_IOCTL_SMLEN, NULL);
3034*4882a593Smuzhiyun 	if (ret != 0)
3035*4882a593Smuzhiyun 		IAPSTA_ERROR(ndev->name, "'bss %d' failed with %d\n", val, ret);
3036*4882a593Smuzhiyun 
3037*4882a593Smuzhiyun 	return ret;
3038*4882a593Smuzhiyun }
3039*4882a593Smuzhiyun 
3040*4882a593Smuzhiyun static int
wl_ext_interface_ops(struct net_device * dev,struct wl_apsta_params * apsta_params,int iftype,u8 * addr)3041*4882a593Smuzhiyun wl_ext_interface_ops(struct net_device *dev,
3042*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params, int iftype, u8 *addr)
3043*4882a593Smuzhiyun {
3044*4882a593Smuzhiyun 	s32 ret;
3045*4882a593Smuzhiyun 	struct wl_interface_create_v2 iface;
3046*4882a593Smuzhiyun 	wl_interface_create_v3_t iface_v3;
3047*4882a593Smuzhiyun 	struct wl_interface_info_v1 *info;
3048*4882a593Smuzhiyun 	wl_interface_info_v2_t *info_v2;
3049*4882a593Smuzhiyun 	uint32 ifflags = 0;
3050*4882a593Smuzhiyun 	bool use_iface_info_v2 = false;
3051*4882a593Smuzhiyun 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
3052*4882a593Smuzhiyun 	wl_wlc_version_t wlc_ver;
3053*4882a593Smuzhiyun 
3054*4882a593Smuzhiyun 	/* Interface create */
3055*4882a593Smuzhiyun 	bzero(&iface, sizeof(iface));
3056*4882a593Smuzhiyun 
3057*4882a593Smuzhiyun 	if (addr) {
3058*4882a593Smuzhiyun 		ifflags |= WL_INTERFACE_MAC_USE;
3059*4882a593Smuzhiyun 	}
3060*4882a593Smuzhiyun 
3061*4882a593Smuzhiyun 	ret = wldev_iovar_getbuf(dev, "wlc_ver", NULL, 0,
3062*4882a593Smuzhiyun 		&wlc_ver, sizeof(wl_wlc_version_t), NULL);
3063*4882a593Smuzhiyun 	if ((ret == BCME_OK) && (wlc_ver.wlc_ver_major >= 5)) {
3064*4882a593Smuzhiyun 		ret = wldev_iovar_getbuf(dev, "interface_create",
3065*4882a593Smuzhiyun 			&iface, sizeof(struct wl_interface_create_v2),
3066*4882a593Smuzhiyun 			ioctl_buf, sizeof(ioctl_buf), NULL);
3067*4882a593Smuzhiyun 		if ((ret == BCME_OK) && (*((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_3)) {
3068*4882a593Smuzhiyun 			use_iface_info_v2 = true;
3069*4882a593Smuzhiyun 			bzero(&iface_v3, sizeof(wl_interface_create_v3_t));
3070*4882a593Smuzhiyun 			iface_v3.ver = WL_INTERFACE_CREATE_VER_3;
3071*4882a593Smuzhiyun 			iface_v3.iftype = iftype;
3072*4882a593Smuzhiyun 			iface_v3.flags = ifflags;
3073*4882a593Smuzhiyun 			if (addr) {
3074*4882a593Smuzhiyun 				memcpy(&iface_v3.mac_addr.octet, addr, ETH_ALEN);
3075*4882a593Smuzhiyun 			}
3076*4882a593Smuzhiyun 			ret = wl_ext_iovar_getbuf(dev, "interface_create",
3077*4882a593Smuzhiyun 				&iface_v3, sizeof(wl_interface_create_v3_t),
3078*4882a593Smuzhiyun 				ioctl_buf, sizeof(ioctl_buf), NULL);
3079*4882a593Smuzhiyun 			if (unlikely(ret)) {
3080*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "Interface v3 create failed!! ret %d\n", ret);
3081*4882a593Smuzhiyun 				return ret;
3082*4882a593Smuzhiyun 			}
3083*4882a593Smuzhiyun 		}
3084*4882a593Smuzhiyun 	}
3085*4882a593Smuzhiyun 
3086*4882a593Smuzhiyun 	/* success case */
3087*4882a593Smuzhiyun 	if (use_iface_info_v2 == true) {
3088*4882a593Smuzhiyun 		info_v2 = (wl_interface_info_v2_t *)ioctl_buf;
3089*4882a593Smuzhiyun 		ret = info_v2->bsscfgidx;
3090*4882a593Smuzhiyun 	} else {
3091*4882a593Smuzhiyun 		/* Use v1 struct */
3092*4882a593Smuzhiyun 		iface.ver = WL_INTERFACE_CREATE_VER_2;
3093*4882a593Smuzhiyun 		iface.iftype = iftype;
3094*4882a593Smuzhiyun 		iface.flags = iftype | ifflags;
3095*4882a593Smuzhiyun 		if (addr) {
3096*4882a593Smuzhiyun 			memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
3097*4882a593Smuzhiyun 		}
3098*4882a593Smuzhiyun 		ret = wldev_iovar_getbuf(dev, "interface_create",
3099*4882a593Smuzhiyun 			&iface, sizeof(struct wl_interface_create_v2),
3100*4882a593Smuzhiyun 			ioctl_buf, sizeof(ioctl_buf), NULL);
3101*4882a593Smuzhiyun 		if (ret == BCME_OK) {
3102*4882a593Smuzhiyun 			info = (struct wl_interface_info_v1 *)ioctl_buf;
3103*4882a593Smuzhiyun 			ret = info->bsscfgidx;
3104*4882a593Smuzhiyun 		}
3105*4882a593Smuzhiyun 	}
3106*4882a593Smuzhiyun 
3107*4882a593Smuzhiyun 	IAPSTA_INFO(dev->name, "wl interface create success!! bssidx:%d \n", ret);
3108*4882a593Smuzhiyun 	return ret;
3109*4882a593Smuzhiyun }
3110*4882a593Smuzhiyun 
3111*4882a593Smuzhiyun static void
wl_ext_wait_netif_change(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)3112*4882a593Smuzhiyun wl_ext_wait_netif_change(struct wl_apsta_params *apsta_params,
3113*4882a593Smuzhiyun 	struct wl_if_info *cur_if)
3114*4882a593Smuzhiyun {
3115*4882a593Smuzhiyun 	rtnl_unlock();
3116*4882a593Smuzhiyun 	wait_event_interruptible_timeout(apsta_params->netif_change_event,
3117*4882a593Smuzhiyun 		wl_get_isam_status(cur_if, IF_READY),
3118*4882a593Smuzhiyun 		msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
3119*4882a593Smuzhiyun 	rtnl_lock();
3120*4882a593Smuzhiyun }
3121*4882a593Smuzhiyun 
3122*4882a593Smuzhiyun static void
wl_ext_interface_create(struct net_device * dev,struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if,int iftype,u8 * addr)3123*4882a593Smuzhiyun wl_ext_interface_create(struct net_device *dev, struct wl_apsta_params *apsta_params,
3124*4882a593Smuzhiyun 	struct wl_if_info *cur_if, int iftype, u8 *addr)
3125*4882a593Smuzhiyun {
3126*4882a593Smuzhiyun 	s32 ret;
3127*4882a593Smuzhiyun 
3128*4882a593Smuzhiyun 	wl_set_isam_status(cur_if, IF_ADDING);
3129*4882a593Smuzhiyun 	ret = wl_ext_interface_ops(dev, apsta_params, iftype, addr);
3130*4882a593Smuzhiyun 	if (ret == BCME_UNSUPPORTED) {
3131*4882a593Smuzhiyun 		wl_ext_add_del_bss(dev, 1, iftype, 0, addr);
3132*4882a593Smuzhiyun 	}
3133*4882a593Smuzhiyun 	wl_ext_wait_netif_change(apsta_params, cur_if);
3134*4882a593Smuzhiyun }
3135*4882a593Smuzhiyun 
3136*4882a593Smuzhiyun static void
wl_ext_iapsta_intf_add(struct net_device * dev,struct wl_apsta_params * apsta_params)3137*4882a593Smuzhiyun wl_ext_iapsta_intf_add(struct net_device *dev, struct wl_apsta_params *apsta_params)
3138*4882a593Smuzhiyun {
3139*4882a593Smuzhiyun 	struct dhd_pub *dhd;
3140*4882a593Smuzhiyun 	apstamode_t apstamode = apsta_params->apstamode;
3141*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
3142*4882a593Smuzhiyun 	s8 iovar_buf[WLC_IOCTL_SMLEN];
3143*4882a593Smuzhiyun 	wl_p2p_if_t ifreq;
3144*4882a593Smuzhiyun 	struct ether_addr mac_addr;
3145*4882a593Smuzhiyun 
3146*4882a593Smuzhiyun 	dhd = dhd_get_pub(dev);
3147*4882a593Smuzhiyun 	bzero(&mac_addr, sizeof(mac_addr));
3148*4882a593Smuzhiyun 
3149*4882a593Smuzhiyun 	if (apstamode == ISTAAP_MODE) {
3150*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[IF_VIF];
3151*4882a593Smuzhiyun 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP, NULL);
3152*4882a593Smuzhiyun 	}
3153*4882a593Smuzhiyun 	else if (apstamode == ISTAGO_MODE) {
3154*4882a593Smuzhiyun 		bzero(&ifreq, sizeof(wl_p2p_if_t));
3155*4882a593Smuzhiyun 		ifreq.type = htod32(WL_P2P_IF_GO);
3156*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[IF_VIF];
3157*4882a593Smuzhiyun 		wl_set_isam_status(cur_if, IF_ADDING);
3158*4882a593Smuzhiyun 		wl_ext_iovar_setbuf(dev, "p2p_ifadd", &ifreq, sizeof(ifreq),
3159*4882a593Smuzhiyun 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
3160*4882a593Smuzhiyun 		wl_ext_wait_netif_change(apsta_params, cur_if);
3161*4882a593Smuzhiyun 	}
3162*4882a593Smuzhiyun 	else if (apstamode == ISTASTA_MODE) {
3163*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[IF_VIF];
3164*4882a593Smuzhiyun 		memcpy(&mac_addr, dev->dev_addr, ETHER_ADDR_LEN);
3165*4882a593Smuzhiyun 		mac_addr.octet[0] |= 0x02;
3166*4882a593Smuzhiyun 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_STA,
3167*4882a593Smuzhiyun 			(u8*)&mac_addr);
3168*4882a593Smuzhiyun 	}
3169*4882a593Smuzhiyun 	else if (apstamode == IDUALAP_MODE) {
3170*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[IF_VIF];
3171*4882a593Smuzhiyun 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP, NULL);
3172*4882a593Smuzhiyun 	}
3173*4882a593Smuzhiyun 	else if (apstamode == ISTAAPAP_MODE) {
3174*4882a593Smuzhiyun 		u8 rand_bytes[2] = {0, };
3175*4882a593Smuzhiyun 		get_random_bytes(&rand_bytes, sizeof(rand_bytes));
3176*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[IF_VIF];
3177*4882a593Smuzhiyun 		memcpy(&mac_addr, dev->dev_addr, ETHER_ADDR_LEN);
3178*4882a593Smuzhiyun 		mac_addr.octet[0] |= 0x02;
3179*4882a593Smuzhiyun 		mac_addr.octet[5] += 0x01;
3180*4882a593Smuzhiyun 		memcpy(&mac_addr.octet[3], rand_bytes, sizeof(rand_bytes));
3181*4882a593Smuzhiyun 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP,
3182*4882a593Smuzhiyun 			(u8*)&mac_addr);
3183*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[IF_VIF2];
3184*4882a593Smuzhiyun 		memcpy(&mac_addr, dev->dev_addr, ETHER_ADDR_LEN);
3185*4882a593Smuzhiyun 		mac_addr.octet[0] |= 0x02;
3186*4882a593Smuzhiyun 		mac_addr.octet[5] += 0x02;
3187*4882a593Smuzhiyun 		memcpy(&mac_addr.octet[3], rand_bytes, sizeof(rand_bytes));
3188*4882a593Smuzhiyun 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP,
3189*4882a593Smuzhiyun 			(u8*)&mac_addr);
3190*4882a593Smuzhiyun 	}
3191*4882a593Smuzhiyun #ifdef WLMESH
3192*4882a593Smuzhiyun 	else if (apstamode == ISTAMESH_MODE) {
3193*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[IF_VIF];
3194*4882a593Smuzhiyun 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_STA, NULL);
3195*4882a593Smuzhiyun 	}
3196*4882a593Smuzhiyun 	else if (apstamode == IMESHAP_MODE) {
3197*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[IF_VIF];
3198*4882a593Smuzhiyun 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP, NULL);
3199*4882a593Smuzhiyun 	}
3200*4882a593Smuzhiyun 	else if (apstamode == ISTAAPMESH_MODE) {
3201*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[IF_VIF];
3202*4882a593Smuzhiyun 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP, NULL);
3203*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[IF_VIF2];
3204*4882a593Smuzhiyun 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_STA, NULL);
3205*4882a593Smuzhiyun 	}
3206*4882a593Smuzhiyun 	else if (apstamode == IMESHAPAP_MODE) {
3207*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[IF_VIF];
3208*4882a593Smuzhiyun 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP, NULL);
3209*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[IF_VIF2];
3210*4882a593Smuzhiyun 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP, NULL);
3211*4882a593Smuzhiyun 	}
3212*4882a593Smuzhiyun #endif /* WLMESH */
3213*4882a593Smuzhiyun 
3214*4882a593Smuzhiyun }
3215*4882a593Smuzhiyun #endif /* WL_STATIC_IF */
3216*4882a593Smuzhiyun 
3217*4882a593Smuzhiyun void
wl_ext_update_conn_state(dhd_pub_t * dhd,int ifidx,uint conn_state)3218*4882a593Smuzhiyun wl_ext_update_conn_state(dhd_pub_t *dhd, int ifidx, uint conn_state)
3219*4882a593Smuzhiyun {
3220*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
3221*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
3222*4882a593Smuzhiyun #ifdef EAPOL_RESEND
3223*4882a593Smuzhiyun 	unsigned long flags = 0;
3224*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
3225*4882a593Smuzhiyun 
3226*4882a593Smuzhiyun 	if (ifidx < MAX_IF_NUM) {
3227*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[ifidx];
3228*4882a593Smuzhiyun #ifdef EAPOL_RESEND
3229*4882a593Smuzhiyun 		spin_lock_irqsave(&apsta_params->eapol_lock, flags);
3230*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
3231*4882a593Smuzhiyun 		if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) {
3232*4882a593Smuzhiyun 			if (wl_ext_sta_connecting(cur_if->dev) ||
3233*4882a593Smuzhiyun 					conn_state >= CONN_STATE_CONNECTED ||
3234*4882a593Smuzhiyun 					conn_state <= CONN_STATE_CONNECTING)
3235*4882a593Smuzhiyun 				apsta_params->if_info[ifidx].conn_state = conn_state;
3236*4882a593Smuzhiyun 			else
3237*4882a593Smuzhiyun 				IAPSTA_INFO(cur_if->dev->name, "skip update %d\n", conn_state);
3238*4882a593Smuzhiyun 		} else {
3239*4882a593Smuzhiyun 			apsta_params->if_info[ifidx].conn_state = conn_state;
3240*4882a593Smuzhiyun 		}
3241*4882a593Smuzhiyun #ifdef EAPOL_RESEND
3242*4882a593Smuzhiyun 		spin_unlock_irqrestore(&apsta_params->eapol_lock, flags);
3243*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
3244*4882a593Smuzhiyun 	}
3245*4882a593Smuzhiyun }
3246*4882a593Smuzhiyun 
3247*4882a593Smuzhiyun #ifdef EAPOL_RESEND
3248*4882a593Smuzhiyun #ifdef EAPOL_DYNAMATIC_RESEND
3249*4882a593Smuzhiyun static void
wl_ext_calc_eapol_intvl(struct wl_if_info * cur_if,bool rx)3250*4882a593Smuzhiyun wl_ext_calc_eapol_intvl(struct wl_if_info *cur_if, bool rx)
3251*4882a593Smuzhiyun {
3252*4882a593Smuzhiyun 	struct osl_timespec cur_ts;
3253*4882a593Smuzhiyun 	uint32 diff_ms;
3254*4882a593Smuzhiyun 
3255*4882a593Smuzhiyun 	if (rx && cur_if->pend_eapol_pkt && !cur_if->eapol_retry) {
3256*4882a593Smuzhiyun 		osl_do_gettimeofday(&cur_ts);
3257*4882a593Smuzhiyun 		diff_ms = osl_do_gettimediff(&cur_ts, &cur_if->eapol_tx_ts)/1000;
3258*4882a593Smuzhiyun 		if (diff_ms > STA_EAPOL_TIMEOUT)
3259*4882a593Smuzhiyun 			diff_ms = STA_EAPOL_TIMEOUT;
3260*4882a593Smuzhiyun 		if (diff_ms > cur_if->eapol_max_intvl)
3261*4882a593Smuzhiyun 			cur_if->eapol_max_intvl = diff_ms;
3262*4882a593Smuzhiyun 		if (!cur_if->eapol_cnt || diff_ms < cur_if->eapol_min_intvl ||
3263*4882a593Smuzhiyun 				cur_if->eapol_min_intvl == 0)
3264*4882a593Smuzhiyun 			cur_if->eapol_min_intvl = diff_ms;
3265*4882a593Smuzhiyun 
3266*4882a593Smuzhiyun 		if (cur_if->eapol_cnt)
3267*4882a593Smuzhiyun 			cur_if->eapol_avg_intvl =
3268*4882a593Smuzhiyun 				(cur_if->eapol_avg_intvl * cur_if->eapol_cnt + diff_ms) /
3269*4882a593Smuzhiyun 				(cur_if->eapol_cnt+1);
3270*4882a593Smuzhiyun 		else
3271*4882a593Smuzhiyun 			cur_if->eapol_avg_intvl = (diff_ms + STA_EAPOL_TIMEOUT) / 2;
3272*4882a593Smuzhiyun 		cur_if->eapol_cnt++;
3273*4882a593Smuzhiyun 
3274*4882a593Smuzhiyun 		if (cur_if->eapol_avg_intvl <= (cur_if->eapol_min_intvl + 2) ||
3275*4882a593Smuzhiyun 				cur_if->eapol_avg_intvl <= 10) {
3276*4882a593Smuzhiyun 			cur_if->eapol_avg_intvl = (cur_if->eapol_max_intvl+STA_EAPOL_TIMEOUT)/2;
3277*4882a593Smuzhiyun 			cur_if->eapol_cnt = 1;
3278*4882a593Smuzhiyun 		}
3279*4882a593Smuzhiyun 	}
3280*4882a593Smuzhiyun }
3281*4882a593Smuzhiyun #endif /* EAPOL_DYNAMATIC_RESEND */
3282*4882a593Smuzhiyun 
3283*4882a593Smuzhiyun void
wl_ext_free_eapol_txpkt(struct wl_if_info * cur_if,bool rx)3284*4882a593Smuzhiyun wl_ext_free_eapol_txpkt(struct wl_if_info *cur_if, bool rx)
3285*4882a593Smuzhiyun {
3286*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
3287*4882a593Smuzhiyun 
3288*4882a593Smuzhiyun #ifdef BCMDBUS
3289*4882a593Smuzhiyun 	if (!rx)
3290*4882a593Smuzhiyun #endif /* BCMDBUS */
3291*4882a593Smuzhiyun 	wl_timer_mod(dhd, &cur_if->eapol_timer, 0);
3292*4882a593Smuzhiyun 
3293*4882a593Smuzhiyun 	if (cur_if->pend_eapol_pkt) {
3294*4882a593Smuzhiyun 		PKTCFREE(dhd->osh, cur_if->pend_eapol_pkt, TRUE);
3295*4882a593Smuzhiyun 		cur_if->pend_eapol_pkt = NULL;
3296*4882a593Smuzhiyun 		IAPSTA_TRACE(cur_if->dev->name, "release eapol pkt\n");
3297*4882a593Smuzhiyun 	}
3298*4882a593Smuzhiyun }
3299*4882a593Smuzhiyun 
3300*4882a593Smuzhiyun void
wl_ext_release_eapol_txpkt(dhd_pub_t * dhd,int ifidx,bool rx)3301*4882a593Smuzhiyun wl_ext_release_eapol_txpkt(dhd_pub_t *dhd, int ifidx, bool rx)
3302*4882a593Smuzhiyun {
3303*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
3304*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
3305*4882a593Smuzhiyun 	unsigned long flags = 0;
3306*4882a593Smuzhiyun 
3307*4882a593Smuzhiyun 	if (ifidx < MAX_IF_NUM && (dhd->conf->war & RESEND_EAPOL_PKT)) {
3308*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[ifidx];
3309*4882a593Smuzhiyun 		spin_lock_irqsave(&apsta_params->eapol_lock, flags);
3310*4882a593Smuzhiyun #ifdef EAPOL_DYNAMATIC_RESEND
3311*4882a593Smuzhiyun 		wl_ext_calc_eapol_intvl(cur_if, rx);
3312*4882a593Smuzhiyun 		if (rx)
3313*4882a593Smuzhiyun 			cur_if->eapol_retry = FALSE;
3314*4882a593Smuzhiyun #endif /* EAPOL_DYNAMATIC_RESEND */
3315*4882a593Smuzhiyun 		wl_ext_free_eapol_txpkt(cur_if, rx);
3316*4882a593Smuzhiyun 		spin_unlock_irqrestore(&apsta_params->eapol_lock, flags);
3317*4882a593Smuzhiyun 	}
3318*4882a593Smuzhiyun }
3319*4882a593Smuzhiyun 
3320*4882a593Smuzhiyun void
wl_ext_backup_eapol_txpkt(dhd_pub_t * dhd,int ifidx,void * pkt)3321*4882a593Smuzhiyun wl_ext_backup_eapol_txpkt(dhd_pub_t *dhd, int ifidx, void *pkt)
3322*4882a593Smuzhiyun {
3323*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
3324*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
3325*4882a593Smuzhiyun 	unsigned long flags = 0;
3326*4882a593Smuzhiyun 	int interval;
3327*4882a593Smuzhiyun 
3328*4882a593Smuzhiyun 	if (ifidx < MAX_IF_NUM && (dhd->conf->war & RESEND_EAPOL_PKT)) {
3329*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[ifidx];
3330*4882a593Smuzhiyun 		if (cur_if->dev && cur_if->ifmode == ISTA_MODE &&
3331*4882a593Smuzhiyun 				wl_ext_sta_connecting(cur_if->dev)) {
3332*4882a593Smuzhiyun 			spin_lock_irqsave(&apsta_params->eapol_lock, flags);
3333*4882a593Smuzhiyun 			wl_ext_free_eapol_txpkt(cur_if, TRUE);
3334*4882a593Smuzhiyun 			cur_if->pend_eapol_pkt = skb_copy(pkt, GFP_ATOMIC);
3335*4882a593Smuzhiyun 			if (cur_if->pend_eapol_pkt) {
3336*4882a593Smuzhiyun #ifdef EAPOL_DYNAMATIC_RESEND
3337*4882a593Smuzhiyun 				osl_do_gettimeofday(&cur_if->eapol_tx_ts);
3338*4882a593Smuzhiyun 				if (cur_if->eapol_retry)
3339*4882a593Smuzhiyun 					interval = cur_if->eapol_max_intvl;
3340*4882a593Smuzhiyun 				else
3341*4882a593Smuzhiyun 					interval = (cur_if->eapol_avg_intvl + cur_if->eapol_max_intvl) / 2;
3342*4882a593Smuzhiyun 				if (interval <= 20) {
3343*4882a593Smuzhiyun 					cur_if->eapol_avg_intvl = (cur_if->eapol_max_intvl+STA_EAPOL_TIMEOUT)/2;
3344*4882a593Smuzhiyun 					cur_if->eapol_cnt = 1;
3345*4882a593Smuzhiyun 				}
3346*4882a593Smuzhiyun 				cur_if->eapol_resend_intvl = interval;
3347*4882a593Smuzhiyun #else
3348*4882a593Smuzhiyun 				interval = STA_EAPOL_TIMEOUT;
3349*4882a593Smuzhiyun #endif /* EAPOL_DYNAMATIC_RESEND */
3350*4882a593Smuzhiyun 				wl_timer_mod(dhd, &cur_if->eapol_timer, interval);
3351*4882a593Smuzhiyun 				IAPSTA_TRACE(cur_if->dev->name, "backup eapol pkt\n");
3352*4882a593Smuzhiyun 			}
3353*4882a593Smuzhiyun 			spin_unlock_irqrestore(&apsta_params->eapol_lock, flags);
3354*4882a593Smuzhiyun 		}
3355*4882a593Smuzhiyun 	}
3356*4882a593Smuzhiyun }
3357*4882a593Smuzhiyun 
3358*4882a593Smuzhiyun static void
wl_resend_eapol_handler(struct wl_if_info * cur_if,const wl_event_msg_t * e,void * data)3359*4882a593Smuzhiyun wl_resend_eapol_handler(struct wl_if_info *cur_if,
3360*4882a593Smuzhiyun 	const wl_event_msg_t *e, void *data)
3361*4882a593Smuzhiyun {
3362*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
3363*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
3364*4882a593Smuzhiyun 	struct net_device *dev = cur_if->dev;
3365*4882a593Smuzhiyun 	uint32 etype = ntoh32(e->event_type);
3366*4882a593Smuzhiyun 	uint32 reason = ntoh32(e->reason);
3367*4882a593Smuzhiyun 	unsigned long flags = 0;
3368*4882a593Smuzhiyun 	bool pending = FALSE;
3369*4882a593Smuzhiyun 	void *pend_eapol_pkt = NULL;
3370*4882a593Smuzhiyun 
3371*4882a593Smuzhiyun 	if (etype == WLC_E_RESERVED && reason == ISAM_RC_EAPOL_RESEND) {
3372*4882a593Smuzhiyun 		spin_lock_irqsave(&apsta_params->eapol_lock, flags);
3373*4882a593Smuzhiyun 		if (cur_if->pend_eapol_pkt && wl_ext_sta_connecting(cur_if->dev)) {
3374*4882a593Smuzhiyun 			pend_eapol_pkt = skb_copy(cur_if->pend_eapol_pkt, GFP_ATOMIC);
3375*4882a593Smuzhiyun 			if (pend_eapol_pkt) {
3376*4882a593Smuzhiyun #ifdef EAPOL_DYNAMATIC_RESEND
3377*4882a593Smuzhiyun 				cur_if->eapol_retry = TRUE;
3378*4882a593Smuzhiyun 				IAPSTA_INFO(dev->name, "resend eapol pkt %d(%d/%d/%d/%d), cnt=%d\n",
3379*4882a593Smuzhiyun 					cur_if->eapol_resend_intvl,
3380*4882a593Smuzhiyun 					cur_if->eapol_min_intvl, cur_if->eapol_avg_intvl,
3381*4882a593Smuzhiyun 					cur_if->eapol_max_intvl, STA_EAPOL_TIMEOUT,
3382*4882a593Smuzhiyun 					cur_if->eapol_cnt);
3383*4882a593Smuzhiyun #else
3384*4882a593Smuzhiyun 				IAPSTA_INFO(dev->name, "resend eapol pkt %dms\n", STA_EAPOL_TIMEOUT);
3385*4882a593Smuzhiyun #endif /* EAPOL_DYNAMATIC_RESEND */
3386*4882a593Smuzhiyun 				pending = TRUE;
3387*4882a593Smuzhiyun 			}
3388*4882a593Smuzhiyun 		}
3389*4882a593Smuzhiyun 		spin_unlock_irqrestore(&apsta_params->eapol_lock, flags);
3390*4882a593Smuzhiyun 		if (pending) {
3391*4882a593Smuzhiyun 			dhd_sendpkt(dhd, cur_if->ifidx, pend_eapol_pkt);
3392*4882a593Smuzhiyun 		}
3393*4882a593Smuzhiyun 	}
3394*4882a593Smuzhiyun }
3395*4882a593Smuzhiyun 
3396*4882a593Smuzhiyun static void
wl_eapol_timer(unsigned long data)3397*4882a593Smuzhiyun wl_eapol_timer(unsigned long data)
3398*4882a593Smuzhiyun {
3399*4882a593Smuzhiyun 	struct net_device *dev = (struct net_device *)data;
3400*4882a593Smuzhiyun 	struct dhd_pub *dhd;
3401*4882a593Smuzhiyun 	wl_event_msg_t msg;
3402*4882a593Smuzhiyun 
3403*4882a593Smuzhiyun 	if (!dev) {
3404*4882a593Smuzhiyun 		IAPSTA_ERROR("wlan", "dev is not ready\n");
3405*4882a593Smuzhiyun 		return;
3406*4882a593Smuzhiyun 	}
3407*4882a593Smuzhiyun 
3408*4882a593Smuzhiyun 	dhd = dhd_get_pub(dev);
3409*4882a593Smuzhiyun 
3410*4882a593Smuzhiyun 	bzero(&msg, sizeof(wl_event_msg_t));
3411*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "timer expired\n");
3412*4882a593Smuzhiyun 
3413*4882a593Smuzhiyun 	msg.ifidx = dhd_net2idx(dhd->info, dev);
3414*4882a593Smuzhiyun 	msg.event_type = hton32(WLC_E_RESERVED);
3415*4882a593Smuzhiyun 	msg.reason = hton32(ISAM_RC_EAPOL_RESEND);
3416*4882a593Smuzhiyun 	wl_ext_event_send(dhd->event_params, &msg, NULL);
3417*4882a593Smuzhiyun }
3418*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
3419*4882a593Smuzhiyun 
3420*4882a593Smuzhiyun #ifdef KEY_INSTALL_CHECK
3421*4882a593Smuzhiyun static void
wl_ext_key_install_timeout(unsigned long data)3422*4882a593Smuzhiyun wl_ext_key_install_timeout(unsigned long data)
3423*4882a593Smuzhiyun {
3424*4882a593Smuzhiyun 	struct net_device *dev = (struct net_device *)data;
3425*4882a593Smuzhiyun 	struct dhd_pub *dhd;
3426*4882a593Smuzhiyun 	wl_event_msg_t msg;
3427*4882a593Smuzhiyun 
3428*4882a593Smuzhiyun 	if (!dev) {
3429*4882a593Smuzhiyun 		IAPSTA_ERROR("wlan", "dev is not ready\n");
3430*4882a593Smuzhiyun 		return;
3431*4882a593Smuzhiyun 	}
3432*4882a593Smuzhiyun 
3433*4882a593Smuzhiyun 	dhd = dhd_get_pub(dev);
3434*4882a593Smuzhiyun 
3435*4882a593Smuzhiyun 	bzero(&msg, sizeof(wl_event_msg_t));
3436*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "timer expired\n");
3437*4882a593Smuzhiyun 
3438*4882a593Smuzhiyun 	msg.ifidx = dhd_net2idx(dhd->info, dev);
3439*4882a593Smuzhiyun 	msg.event_type = hton32(WLC_E_RESERVED);
3440*4882a593Smuzhiyun 	msg.reason = hton32(ISAM_RC_KEY_INSTALL);
3441*4882a593Smuzhiyun 	wl_ext_event_send(dhd->event_params, &msg, NULL);
3442*4882a593Smuzhiyun }
3443*4882a593Smuzhiyun 
3444*4882a593Smuzhiyun static void
wl_ext_key_install_handler(struct wl_if_info * cur_if,const wl_event_msg_t * e,void * data)3445*4882a593Smuzhiyun wl_ext_key_install_handler(struct wl_if_info *cur_if,
3446*4882a593Smuzhiyun 	const wl_event_msg_t *e, void *data)
3447*4882a593Smuzhiyun {
3448*4882a593Smuzhiyun 	struct net_device *dev = cur_if->dev;
3449*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
3450*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3451*4882a593Smuzhiyun 	uint32 etype = ntoh32(e->event_type);
3452*4882a593Smuzhiyun 	uint32 reason = ntoh32(e->reason);
3453*4882a593Smuzhiyun 	int err, key_installed = 0;
3454*4882a593Smuzhiyun 
3455*4882a593Smuzhiyun 	if (etype == WLC_E_RESERVED && reason == ISAM_RC_KEY_INSTALL) {
3456*4882a593Smuzhiyun 		if (cur_if->conn_state >= CONN_STATE_4WAY_M4 &&
3457*4882a593Smuzhiyun 				!wl_get_drv_status(cfg, DISCONNECTING, dev) &&
3458*4882a593Smuzhiyun 				wl_get_drv_status(cfg, CONNECTED, dev)) {
3459*4882a593Smuzhiyun 			err = wldev_iovar_getint(dev, "buf_key_b4_m4_installed", &key_installed);
3460*4882a593Smuzhiyun 			if (!err && !key_installed) {
3461*4882a593Smuzhiyun 				cur_if->key_install_cnt++;
3462*4882a593Smuzhiyun 				if (cur_if->key_install_cnt > STA_KEY_INSTALL_MAX) {
3463*4882a593Smuzhiyun 					IAPSTA_ERROR(dev->name, "key not installed, send disconnect\n");
3464*4882a593Smuzhiyun #ifdef EAPOL_RESEND
3465*4882a593Smuzhiyun 					wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE);
3466*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
3467*4882a593Smuzhiyun 					wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED);
3468*4882a593Smuzhiyun 					wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
3469*4882a593Smuzhiyun 					wl_timer_mod(dhd, &cur_if->key_install_timer, 0);
3470*4882a593Smuzhiyun 					cur_if->key_install_cnt = 0;
3471*4882a593Smuzhiyun 				} else {
3472*4882a593Smuzhiyun 					IAPSTA_INFO(dev->name, "check key installed %dms later, cnt=%d\n",
3473*4882a593Smuzhiyun 						STA_KEY_INSTALL_INTERVAL, cur_if->key_install_cnt);
3474*4882a593Smuzhiyun 					wl_timer_mod(dhd, &cur_if->key_install_timer, STA_KEY_INSTALL_INTERVAL);
3475*4882a593Smuzhiyun 				}
3476*4882a593Smuzhiyun 			} else {
3477*4882a593Smuzhiyun #ifdef EAPOL_RESEND
3478*4882a593Smuzhiyun 				wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE);
3479*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
3480*4882a593Smuzhiyun 				IAPSTA_INFO(dev->name, "key installed\n");
3481*4882a593Smuzhiyun 				wl_timer_mod(dhd, &cur_if->connect_timer, 0);
3482*4882a593Smuzhiyun 				wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED);
3483*4882a593Smuzhiyun 				cur_if->key_install_cnt = 0;
3484*4882a593Smuzhiyun 			}
3485*4882a593Smuzhiyun 		}
3486*4882a593Smuzhiyun 	}
3487*4882a593Smuzhiyun 	return;
3488*4882a593Smuzhiyun }
3489*4882a593Smuzhiyun 
3490*4882a593Smuzhiyun static int
wl_key_installed(struct wl_if_info * cur_if)3491*4882a593Smuzhiyun wl_key_installed(struct wl_if_info *cur_if)
3492*4882a593Smuzhiyun {
3493*4882a593Smuzhiyun 	struct net_device *dev = cur_if->dev;
3494*4882a593Smuzhiyun 	dhd_pub_t *dhd = dhd_get_pub(dev);
3495*4882a593Smuzhiyun 	int err, key_installed = 0;
3496*4882a593Smuzhiyun 
3497*4882a593Smuzhiyun 	err = wldev_iovar_getint(dev, "buf_key_b4_m4_installed", &key_installed);
3498*4882a593Smuzhiyun 	if (err) {
3499*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "not supported %d\n", err);
3500*4882a593Smuzhiyun 		key_installed = 1;
3501*4882a593Smuzhiyun 	} else if (key_installed)
3502*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "key installed\n");
3503*4882a593Smuzhiyun 
3504*4882a593Smuzhiyun 	if (key_installed)
3505*4882a593Smuzhiyun 		wl_timer_mod(dhd, &cur_if->key_install_timer, 0);
3506*4882a593Smuzhiyun 	else {
3507*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "check key installed %dms later\n", STA_KEY_INSTALL_INTERVAL);
3508*4882a593Smuzhiyun 		wl_timer_mod(dhd, &cur_if->key_install_timer, STA_KEY_INSTALL_INTERVAL);
3509*4882a593Smuzhiyun 	}
3510*4882a593Smuzhiyun 
3511*4882a593Smuzhiyun 	return key_installed;
3512*4882a593Smuzhiyun }
3513*4882a593Smuzhiyun #endif /* KEY_INSTALL_CHECK */
3514*4882a593Smuzhiyun 
3515*4882a593Smuzhiyun #if defined(WL_CFG80211) && defined(SCAN_SUPPRESS)
3516*4882a593Smuzhiyun static void
wl_ext_light_scan_prep(struct net_device * dev,void * scan_params,bool scan_v2)3517*4882a593Smuzhiyun wl_ext_light_scan_prep(struct net_device *dev, void *scan_params, bool scan_v2)
3518*4882a593Smuzhiyun {
3519*4882a593Smuzhiyun 	wl_scan_params_v1_t *params = NULL;
3520*4882a593Smuzhiyun 	wl_scan_params_v2_t *params_v2 = NULL;
3521*4882a593Smuzhiyun 
3522*4882a593Smuzhiyun 	if (!scan_params) {
3523*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "NULL scan_params\n");
3524*4882a593Smuzhiyun 		return;
3525*4882a593Smuzhiyun 	}
3526*4882a593Smuzhiyun 	IAPSTA_INFO(dev->name, "Enter\n");
3527*4882a593Smuzhiyun 
3528*4882a593Smuzhiyun 	if (scan_v2) {
3529*4882a593Smuzhiyun 		params_v2 = (wl_scan_params_v2_t *)scan_params;
3530*4882a593Smuzhiyun 	} else {
3531*4882a593Smuzhiyun 		params = (wl_scan_params_v1_t *)scan_params;
3532*4882a593Smuzhiyun 	}
3533*4882a593Smuzhiyun 
3534*4882a593Smuzhiyun 	if (params_v2) {
3535*4882a593Smuzhiyun 		/* scan params ver2 */
3536*4882a593Smuzhiyun 		params_v2->nprobes = 1;
3537*4882a593Smuzhiyun 		params_v2->active_time = 20;
3538*4882a593Smuzhiyun 		params_v2->home_time = 150;
3539*4882a593Smuzhiyun 	} else {
3540*4882a593Smuzhiyun 		/* scan params ver 1 */
3541*4882a593Smuzhiyun 		if (!params) {
3542*4882a593Smuzhiyun 			ASSERT(0);
3543*4882a593Smuzhiyun 			return;
3544*4882a593Smuzhiyun 		}
3545*4882a593Smuzhiyun 		params->nprobes = 1;
3546*4882a593Smuzhiyun 		params->active_time = 20;
3547*4882a593Smuzhiyun 		params->home_time = 150;
3548*4882a593Smuzhiyun 	}
3549*4882a593Smuzhiyun 
3550*4882a593Smuzhiyun 	return;
3551*4882a593Smuzhiyun }
3552*4882a593Smuzhiyun 
3553*4882a593Smuzhiyun static uint16
wl_ext_max_tput_chan(struct wl_apsta_params * apsta_params,struct wl_chan_info * chan_info)3554*4882a593Smuzhiyun wl_ext_max_tput_chan(struct wl_apsta_params *apsta_params,
3555*4882a593Smuzhiyun 	struct wl_chan_info *chan_info)
3556*4882a593Smuzhiyun {
3557*4882a593Smuzhiyun 	struct wl_if_info *tmp_if, *max_tput_if = NULL;
3558*4882a593Smuzhiyun 	int32 tput_sum = 0;
3559*4882a593Smuzhiyun 	int i;
3560*4882a593Smuzhiyun 
3561*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
3562*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
3563*4882a593Smuzhiyun 		if (tmp_if->dev && (tmp_if->tput_info.tput_tx + tmp_if->tput_info.tput_rx) > tput_sum) {
3564*4882a593Smuzhiyun 			memset(chan_info, 0, sizeof(struct wl_chan_info));
3565*4882a593Smuzhiyun 			wl_ext_get_chan(tmp_if->dev, chan_info);
3566*4882a593Smuzhiyun 			if (chan_info->chan) {
3567*4882a593Smuzhiyun 				max_tput_if = tmp_if;
3568*4882a593Smuzhiyun 				tput_sum = tmp_if->tput_info.tput_tx + tmp_if->tput_info.tput_rx;
3569*4882a593Smuzhiyun 				break;
3570*4882a593Smuzhiyun 			}
3571*4882a593Smuzhiyun 		}
3572*4882a593Smuzhiyun 	}
3573*4882a593Smuzhiyun 
3574*4882a593Smuzhiyun 	if (max_tput_if)
3575*4882a593Smuzhiyun 		IAPSTA_INFO(max_tput_if->dev->name, "chan=%s-%d\n",
3576*4882a593Smuzhiyun 			WLCBAND2STR(chan_info->band), chan_info->chan);
3577*4882a593Smuzhiyun 
3578*4882a593Smuzhiyun 	return chan_info->chan;
3579*4882a593Smuzhiyun }
3580*4882a593Smuzhiyun 
3581*4882a593Smuzhiyun uint16
wl_ext_scan_suppress(struct net_device * dev,void * scan_params,bool scan_v2,struct wl_chan_info * chan_info)3582*4882a593Smuzhiyun wl_ext_scan_suppress(struct net_device *dev, void *scan_params, bool scan_v2,
3583*4882a593Smuzhiyun 	struct wl_chan_info *chan_info)
3584*4882a593Smuzhiyun {
3585*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
3586*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
3587*4882a593Smuzhiyun 	struct dhd_conf *conf = dhd->conf;
3588*4882a593Smuzhiyun 
3589*4882a593Smuzhiyun 	if (!(conf->scan_intput & (SCAN_CURCHAN_INTPUT|SCAN_LIGHT_INTPUT)))
3590*4882a593Smuzhiyun 		return 0;
3591*4882a593Smuzhiyun 
3592*4882a593Smuzhiyun 	memset(chan_info, 0, sizeof(struct wl_chan_info));
3593*4882a593Smuzhiyun 	if (apsta_params->tput_sum >= conf->scan_tput_thresh) {
3594*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "tput %dMbps >= %dMbps (busy cnt/thresh %d/%d)\n",
3595*4882a593Smuzhiyun 			apsta_params->tput_sum, conf->scan_tput_thresh,
3596*4882a593Smuzhiyun 			apsta_params->scan_busy_cnt, conf->scan_busy_thresh);
3597*4882a593Smuzhiyun 		if (apsta_params->scan_busy_cnt >= conf->scan_busy_thresh) {
3598*4882a593Smuzhiyun 			apsta_params->scan_busy_cnt = 0;
3599*4882a593Smuzhiyun 		} else if (conf->scan_intput & SCAN_CURCHAN_INTPUT) {
3600*4882a593Smuzhiyun 			wl_ext_max_tput_chan(apsta_params, chan_info);
3601*4882a593Smuzhiyun 		}
3602*4882a593Smuzhiyun 		if ((conf->scan_intput & SCAN_LIGHT_INTPUT) && !chan_info->chan)
3603*4882a593Smuzhiyun 			wl_ext_light_scan_prep(dev, scan_params, scan_v2);
3604*4882a593Smuzhiyun 		apsta_params->scan_busy_cnt++;
3605*4882a593Smuzhiyun 	}
3606*4882a593Smuzhiyun 	else {
3607*4882a593Smuzhiyun 		apsta_params->scan_busy_cnt = 0;
3608*4882a593Smuzhiyun 	}
3609*4882a593Smuzhiyun 
3610*4882a593Smuzhiyun 	return chan_info->chan;
3611*4882a593Smuzhiyun }
3612*4882a593Smuzhiyun 
3613*4882a593Smuzhiyun static int
wl_ext_scan_busy(dhd_pub_t * dhd,struct wl_if_info * cur_if)3614*4882a593Smuzhiyun wl_ext_scan_busy(dhd_pub_t *dhd, struct wl_if_info *cur_if)
3615*4882a593Smuzhiyun {
3616*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
3617*4882a593Smuzhiyun 	struct dhd_conf *conf = dhd->conf;
3618*4882a593Smuzhiyun 	struct osl_timespec cur_ts;
3619*4882a593Smuzhiyun 	uint32 diff_ms;
3620*4882a593Smuzhiyun 	int ret = 0;
3621*4882a593Smuzhiyun 
3622*4882a593Smuzhiyun 	if (!(conf->scan_intput & NO_SCAN_INTPUT))
3623*4882a593Smuzhiyun 		return 0;
3624*4882a593Smuzhiyun 
3625*4882a593Smuzhiyun 	if (apsta_params->tput_sum >= conf->scan_tput_thresh) {
3626*4882a593Smuzhiyun 		if (apsta_params->scan_busy_cnt) {
3627*4882a593Smuzhiyun 			osl_do_gettimeofday(&cur_ts);
3628*4882a593Smuzhiyun 			diff_ms = osl_do_gettimediff(&cur_ts, &apsta_params->scan_busy_ts)/1000;
3629*4882a593Smuzhiyun 			if ((diff_ms/1000) >= conf->scan_busy_tmo) {
3630*4882a593Smuzhiyun 				apsta_params->scan_busy_cnt = 0;
3631*4882a593Smuzhiyun 				IAPSTA_INFO(cur_if->dev->name, "reset scan_busy_cnt\n");
3632*4882a593Smuzhiyun 				goto exit;
3633*4882a593Smuzhiyun 			}
3634*4882a593Smuzhiyun 		}
3635*4882a593Smuzhiyun 		if (apsta_params->scan_busy_cnt >= conf->scan_busy_thresh) {
3636*4882a593Smuzhiyun 			apsta_params->scan_busy_cnt = 0;
3637*4882a593Smuzhiyun 		} else if (conf->scan_intput & NO_SCAN_INTPUT) {
3638*4882a593Smuzhiyun 			IAPSTA_INFO(cur_if->dev->name,
3639*4882a593Smuzhiyun 				"tput %dMbps >= %dMbps(busy cnt/thresh %d/%d)\n",
3640*4882a593Smuzhiyun 				apsta_params->tput_sum, conf->scan_tput_thresh,
3641*4882a593Smuzhiyun 				apsta_params->scan_busy_cnt, conf->scan_busy_thresh);
3642*4882a593Smuzhiyun 			apsta_params->scan_busy_cnt++;
3643*4882a593Smuzhiyun 			if (apsta_params->scan_busy_cnt == 1)
3644*4882a593Smuzhiyun 				osl_do_gettimeofday(&apsta_params->scan_busy_ts);
3645*4882a593Smuzhiyun 			ret = -EBUSY;
3646*4882a593Smuzhiyun 			goto exit;
3647*4882a593Smuzhiyun 		}
3648*4882a593Smuzhiyun 	}
3649*4882a593Smuzhiyun 	else {
3650*4882a593Smuzhiyun 		apsta_params->scan_busy_cnt = 0;
3651*4882a593Smuzhiyun 	}
3652*4882a593Smuzhiyun 
3653*4882a593Smuzhiyun exit:
3654*4882a593Smuzhiyun 	return ret;
3655*4882a593Smuzhiyun }
3656*4882a593Smuzhiyun 
3657*4882a593Smuzhiyun void
wl_ext_reset_scan_busy(dhd_pub_t * dhd)3658*4882a593Smuzhiyun wl_ext_reset_scan_busy(dhd_pub_t *dhd)
3659*4882a593Smuzhiyun {
3660*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = (struct wl_apsta_params *)dhd->iapsta_params;
3661*4882a593Smuzhiyun 	apsta_params->scan_busy_cnt = 0;
3662*4882a593Smuzhiyun }
3663*4882a593Smuzhiyun #endif /* SCAN_SUPPRESS */
3664*4882a593Smuzhiyun 
3665*4882a593Smuzhiyun #ifdef SET_CARRIER
3666*4882a593Smuzhiyun static void
wl_ext_net_setcarrier(struct wl_if_info * cur_if,bool on,bool force)3667*4882a593Smuzhiyun wl_ext_net_setcarrier(struct wl_if_info *cur_if, bool on, bool force)
3668*4882a593Smuzhiyun {
3669*4882a593Smuzhiyun 	IAPSTA_TRACE(cur_if->ifname, "carrier=%d\n", on);
3670*4882a593Smuzhiyun 	if (on) {
3671*4882a593Smuzhiyun 		if (!netif_carrier_ok(cur_if->dev) || force)
3672*4882a593Smuzhiyun 			netif_carrier_on(cur_if->dev);
3673*4882a593Smuzhiyun 	} else {
3674*4882a593Smuzhiyun 		if (netif_carrier_ok(cur_if->dev) || force)
3675*4882a593Smuzhiyun 			netif_carrier_off(cur_if->dev);
3676*4882a593Smuzhiyun 	}
3677*4882a593Smuzhiyun }
3678*4882a593Smuzhiyun #endif /* SET_CARRIER */
3679*4882a593Smuzhiyun 
3680*4882a593Smuzhiyun static void
wl_set_btc_in4way(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if,enum wl_ext_status status,bool disable)3681*4882a593Smuzhiyun wl_set_btc_in4way(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if,
3682*4882a593Smuzhiyun 	enum wl_ext_status status, bool disable)
3683*4882a593Smuzhiyun {
3684*4882a593Smuzhiyun 	struct net_device *dev = cur_if->dev;
3685*4882a593Smuzhiyun 	int err;
3686*4882a593Smuzhiyun 
3687*4882a593Smuzhiyun 	if (cur_if->ifidx == 0) {
3688*4882a593Smuzhiyun 		if (disable) {
3689*4882a593Smuzhiyun 			err = wldev_iovar_getint(dev, "btc_mode", &apsta_params->sta_btc_mode);
3690*4882a593Smuzhiyun 			if (!err && apsta_params->sta_btc_mode) {
3691*4882a593Smuzhiyun 				IAPSTA_INFO(dev->name, "status=%d, disable current btc_mode %d\n",
3692*4882a593Smuzhiyun 					status, apsta_params->sta_btc_mode);
3693*4882a593Smuzhiyun 				wldev_iovar_setint(dev, "btc_mode", 0);
3694*4882a593Smuzhiyun 			}
3695*4882a593Smuzhiyun 		} else {
3696*4882a593Smuzhiyun 			if (apsta_params->sta_btc_mode) {
3697*4882a593Smuzhiyun 				IAPSTA_INFO(dev->name, "status=%d, restore btc_mode %d\n",
3698*4882a593Smuzhiyun 					status, apsta_params->sta_btc_mode);
3699*4882a593Smuzhiyun 				wldev_iovar_setint(dev, "btc_mode", apsta_params->sta_btc_mode);
3700*4882a593Smuzhiyun 				apsta_params->sta_btc_mode = 0;
3701*4882a593Smuzhiyun 			}
3702*4882a593Smuzhiyun 		}
3703*4882a593Smuzhiyun 	}
3704*4882a593Smuzhiyun }
3705*4882a593Smuzhiyun 
3706*4882a593Smuzhiyun static void
wl_wait_disconnect(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if,enum wl_ext_status status)3707*4882a593Smuzhiyun wl_wait_disconnect(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if,
3708*4882a593Smuzhiyun 	enum wl_ext_status status)
3709*4882a593Smuzhiyun {
3710*4882a593Smuzhiyun 	struct net_device *dev = cur_if->dev;
3711*4882a593Smuzhiyun 	struct osl_timespec cur_ts, *sta_disc_ts = &cur_if->sta_disc_ts;
3712*4882a593Smuzhiyun 	int max_wait_time = 200, max_wait_cnt = 20;
3713*4882a593Smuzhiyun 	int cur_conn_state = cur_if->conn_state;
3714*4882a593Smuzhiyun 	uint32 diff_ms = 0;
3715*4882a593Smuzhiyun 
3716*4882a593Smuzhiyun 	if (cur_conn_state > CONN_STATE_IDLE)
3717*4882a593Smuzhiyun 		osl_do_gettimeofday(sta_disc_ts);
3718*4882a593Smuzhiyun 	osl_do_gettimeofday(&cur_ts);
3719*4882a593Smuzhiyun 	diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_ts)/1000;
3720*4882a593Smuzhiyun 	while (diff_ms < max_wait_time && max_wait_cnt) {
3721*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "status=%d, max_wait_cnt=%d waiting...\n",
3722*4882a593Smuzhiyun 			status, max_wait_cnt);
3723*4882a593Smuzhiyun 		mutex_unlock(&apsta_params->in4way_sync);
3724*4882a593Smuzhiyun 		OSL_SLEEP(50);
3725*4882a593Smuzhiyun 		mutex_lock(&apsta_params->in4way_sync);
3726*4882a593Smuzhiyun 		max_wait_cnt--;
3727*4882a593Smuzhiyun 		osl_do_gettimeofday(&cur_ts);
3728*4882a593Smuzhiyun 		diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_ts)/1000;
3729*4882a593Smuzhiyun 	}
3730*4882a593Smuzhiyun 
3731*4882a593Smuzhiyun }
3732*4882a593Smuzhiyun 
3733*4882a593Smuzhiyun void
wl_iapsta_wait_event_complete(struct dhd_pub * dhd)3734*4882a593Smuzhiyun wl_iapsta_wait_event_complete(struct dhd_pub *dhd)
3735*4882a593Smuzhiyun {
3736*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
3737*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
3738*4882a593Smuzhiyun 	int i;
3739*4882a593Smuzhiyun 
3740*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
3741*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[i];
3742*4882a593Smuzhiyun 		if (cur_if->dev && cur_if->ifmode == ISTA_MODE) {
3743*4882a593Smuzhiyun 			wl_ext_wait_event_complete(dhd, cur_if->ifidx);
3744*4882a593Smuzhiyun 		}
3745*4882a593Smuzhiyun 	}
3746*4882a593Smuzhiyun }
3747*4882a593Smuzhiyun 
3748*4882a593Smuzhiyun int
wl_iapsta_suspend_resume_ap(dhd_pub_t * dhd,struct wl_if_info * cur_if,int suspend)3749*4882a593Smuzhiyun wl_iapsta_suspend_resume_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if,
3750*4882a593Smuzhiyun 	int suspend)
3751*4882a593Smuzhiyun {
3752*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
3753*4882a593Smuzhiyun 	uint insuspend = 0;
3754*4882a593Smuzhiyun 
3755*4882a593Smuzhiyun 	insuspend = dhd_conf_get_insuspend(dhd, ALL_IN_SUSPEND);
3756*4882a593Smuzhiyun 	if (insuspend)
3757*4882a593Smuzhiyun 		WL_MSG(cur_if->ifname, "suspend %d\n", suspend);
3758*4882a593Smuzhiyun 
3759*4882a593Smuzhiyun 	if (suspend) {
3760*4882a593Smuzhiyun 		if (insuspend & AP_DOWN_IN_SUSPEND) {
3761*4882a593Smuzhiyun 			cur_if->chan_info.chan = wl_ext_get_chan(cur_if->dev, &cur_if->chan_info);
3762*4882a593Smuzhiyun 			if (cur_if->chan_info.chan)
3763*4882a593Smuzhiyun 				wl_ext_if_down(apsta_params, cur_if);
3764*4882a593Smuzhiyun 		}
3765*4882a593Smuzhiyun 	} else {
3766*4882a593Smuzhiyun 		if (insuspend & AP_DOWN_IN_SUSPEND) {
3767*4882a593Smuzhiyun 			if (cur_if->chan_info.chan)
3768*4882a593Smuzhiyun 				wl_ext_if_up(apsta_params, cur_if, FALSE, 0);
3769*4882a593Smuzhiyun 		}
3770*4882a593Smuzhiyun 	}
3771*4882a593Smuzhiyun 
3772*4882a593Smuzhiyun 	return 0;
3773*4882a593Smuzhiyun }
3774*4882a593Smuzhiyun 
3775*4882a593Smuzhiyun int
wl_iapsta_suspend_resume(dhd_pub_t * dhd,int suspend)3776*4882a593Smuzhiyun wl_iapsta_suspend_resume(dhd_pub_t *dhd, int suspend)
3777*4882a593Smuzhiyun {
3778*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
3779*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
3780*4882a593Smuzhiyun 	int i;
3781*4882a593Smuzhiyun 
3782*4882a593Smuzhiyun #ifdef TPUT_MONITOR
3783*4882a593Smuzhiyun 	if (suspend)
3784*4882a593Smuzhiyun 		wl_timer_mod(dhd, &apsta_params->monitor_timer, 0);
3785*4882a593Smuzhiyun #endif /* TPUT_MONITOR */
3786*4882a593Smuzhiyun 
3787*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
3788*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[i];
3789*4882a593Smuzhiyun 		if (cur_if->dev && cur_if->ifmode == ISTA_MODE) {
3790*4882a593Smuzhiyun 			if (!suspend)
3791*4882a593Smuzhiyun 				memcpy(&dhd->conf->bssid_insuspend, &cur_if->bssid, ETHER_ADDR_LEN);
3792*4882a593Smuzhiyun 			dhd_conf_suspend_resume_sta(dhd, cur_if->ifidx, suspend);
3793*4882a593Smuzhiyun 			if (suspend)
3794*4882a593Smuzhiyun 				memcpy(&cur_if->bssid, &dhd->conf->bssid_insuspend, ETHER_ADDR_LEN);
3795*4882a593Smuzhiyun 		}
3796*4882a593Smuzhiyun 		else if (cur_if->dev && cur_if->ifmode == IAP_MODE) {
3797*4882a593Smuzhiyun 			wl_iapsta_suspend_resume_ap(dhd, cur_if, suspend);
3798*4882a593Smuzhiyun 		}
3799*4882a593Smuzhiyun 	}
3800*4882a593Smuzhiyun 
3801*4882a593Smuzhiyun #ifdef TPUT_MONITOR
3802*4882a593Smuzhiyun 	if (!suspend)
3803*4882a593Smuzhiyun 		wl_timer_mod(dhd, &apsta_params->monitor_timer, dhd->conf->tput_monitor_ms);
3804*4882a593Smuzhiyun #endif /* TPUT_MONITOR */
3805*4882a593Smuzhiyun 
3806*4882a593Smuzhiyun 	return 0;
3807*4882a593Smuzhiyun }
3808*4882a593Smuzhiyun 
3809*4882a593Smuzhiyun static int
wl_ext_in4way_sync_sta(dhd_pub_t * dhd,struct wl_if_info * cur_if,uint action,enum wl_ext_status status,void * context)3810*4882a593Smuzhiyun wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if,
3811*4882a593Smuzhiyun 	uint action, enum wl_ext_status status, void *context)
3812*4882a593Smuzhiyun {
3813*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
3814*4882a593Smuzhiyun 	struct dhd_conf *conf = dhd->conf;
3815*4882a593Smuzhiyun 	struct net_device *dev = cur_if->dev;
3816*4882a593Smuzhiyun 	struct osl_timespec cur_ts, *sta_disc_ts = &cur_if->sta_disc_ts;
3817*4882a593Smuzhiyun 	struct osl_timespec *sta_conn_ts = &cur_if->sta_conn_ts;
3818*4882a593Smuzhiyun 	uint32 diff_ms = 0;
3819*4882a593Smuzhiyun 	int ret = 0, suppressed = 0, wpa_auth = 0, max_wait_time = 0, key_installed = 1;
3820*4882a593Smuzhiyun 	uint cur_conn_state, conn_state;
3821*4882a593Smuzhiyun 	bool connecting = FALSE;
3822*4882a593Smuzhiyun 	wl_event_msg_t *e = (wl_event_msg_t *)context;
3823*4882a593Smuzhiyun #ifdef WL_CFG80211
3824*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3825*4882a593Smuzhiyun #endif /* WL_CFG80211 */
3826*4882a593Smuzhiyun 
3827*4882a593Smuzhiyun 	action = action & conf->in4way;
3828*4882a593Smuzhiyun #ifdef WL_CFG80211
3829*4882a593Smuzhiyun 	if ((conf->in4way & STA_FAKE_SCAN_IN_CONNECT) && (action & STA_NO_SCAN_IN4WAY))
3830*4882a593Smuzhiyun 		action &= ~(STA_NO_SCAN_IN4WAY);
3831*4882a593Smuzhiyun #endif /* WL_CFG80211 */
3832*4882a593Smuzhiyun 	cur_conn_state = cur_if->conn_state;
3833*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "status=%d, action=0x%x, in4way=0x%x\n",
3834*4882a593Smuzhiyun 		status, action, conf->in4way);
3835*4882a593Smuzhiyun 
3836*4882a593Smuzhiyun 	connecting = wl_ext_sta_connecting(dev);
3837*4882a593Smuzhiyun 
3838*4882a593Smuzhiyun 	switch (status) {
3839*4882a593Smuzhiyun 		case WL_EXT_STATUS_SCAN:
3840*4882a593Smuzhiyun 			wldev_ioctl(dev, WLC_GET_SCANSUPPRESS, &suppressed, sizeof(int), false);
3841*4882a593Smuzhiyun 			if (suppressed) {
3842*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "scan suppressed\n");
3843*4882a593Smuzhiyun 				ret = -EBUSY;
3844*4882a593Smuzhiyun 				break;
3845*4882a593Smuzhiyun 			}
3846*4882a593Smuzhiyun #ifdef WL_ESCAN
3847*4882a593Smuzhiyun 			if (dhd->escan->escan_state == ESCAN_STATE_SCANING) {
3848*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "escan busy\n");
3849*4882a593Smuzhiyun 				ret = -EBUSY;
3850*4882a593Smuzhiyun 				break;
3851*4882a593Smuzhiyun 			}
3852*4882a593Smuzhiyun #endif /* WL_ESCAN */
3853*4882a593Smuzhiyun #ifdef WL_CFG80211
3854*4882a593Smuzhiyun 			if (wl_get_drv_status_all(cfg, SCANNING) && cfg->scan_request) {
3855*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "cfg80211 scanning\n");
3856*4882a593Smuzhiyun 				ret = -EAGAIN;
3857*4882a593Smuzhiyun 				break;
3858*4882a593Smuzhiyun 			}
3859*4882a593Smuzhiyun #endif /* WL_CFG80211 */
3860*4882a593Smuzhiyun #if defined(WL_CFG80211) && defined(SCAN_SUPPRESS)
3861*4882a593Smuzhiyun 			ret = wl_ext_scan_busy(dhd, cur_if);
3862*4882a593Smuzhiyun 			if (ret) {
3863*4882a593Smuzhiyun 				WL_MSG(dev->name, "no scan intput\n");
3864*4882a593Smuzhiyun 				break;
3865*4882a593Smuzhiyun 			}
3866*4882a593Smuzhiyun #endif /* WL_CFG80211 && SCAN_SUPPRESS */
3867*4882a593Smuzhiyun 			if (action & STA_NO_SCAN_IN4WAY) {
3868*4882a593Smuzhiyun 				osl_do_gettimeofday(&cur_ts);
3869*4882a593Smuzhiyun 				diff_ms = osl_do_gettimediff(&cur_ts, sta_conn_ts)/1000;
3870*4882a593Smuzhiyun 				if (connecting && diff_ms <= STA_CONNECT_TIMEOUT) {
3871*4882a593Smuzhiyun 					IAPSTA_ERROR(dev->name, "scan during connecting... %d\n",
3872*4882a593Smuzhiyun 						cur_conn_state);
3873*4882a593Smuzhiyun 					ret = -EBUSY;
3874*4882a593Smuzhiyun 					break;
3875*4882a593Smuzhiyun 				}
3876*4882a593Smuzhiyun 			}
3877*4882a593Smuzhiyun 			break;
3878*4882a593Smuzhiyun #ifdef WL_CFG80211
3879*4882a593Smuzhiyun 		case WL_EXT_STATUS_SCANNING:
3880*4882a593Smuzhiyun 			if (action & STA_FAKE_SCAN_IN_CONNECT) {
3881*4882a593Smuzhiyun 				osl_do_gettimeofday(&cur_ts);
3882*4882a593Smuzhiyun 				diff_ms = osl_do_gettimediff(&cur_ts, sta_conn_ts)/1000;
3883*4882a593Smuzhiyun 				if (wl_get_drv_status(cfg, CONNECTING, dev) ||
3884*4882a593Smuzhiyun 						(connecting && diff_ms <= STA_CONNECT_TIMEOUT) ||
3885*4882a593Smuzhiyun 						(cur_if->empty_scan >= STA_EMPTY_SCAN_MAX)) {
3886*4882a593Smuzhiyun 					cur_if->empty_scan = 0;
3887*4882a593Smuzhiyun 					WL_MSG(dev->name, "FAKE SCAN\n");
3888*4882a593Smuzhiyun 					ret = -EBUSY;
3889*4882a593Smuzhiyun 				}
3890*4882a593Smuzhiyun 			}
3891*4882a593Smuzhiyun 			break;
3892*4882a593Smuzhiyun 		case WL_EXT_STATUS_SCAN_COMPLETE:
3893*4882a593Smuzhiyun 			if ((conf->war & FW_REINIT_EMPTY_SCAN) &&
3894*4882a593Smuzhiyun 					cfg->bss_list->count == 0 && !p2p_scan(cfg)) {
3895*4882a593Smuzhiyun 				bool assoc;
3896*4882a593Smuzhiyun 				osl_do_gettimeofday(&cur_ts);
3897*4882a593Smuzhiyun 				diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_ts)/1000;
3898*4882a593Smuzhiyun 				assoc = wl_ext_associated(dev);
3899*4882a593Smuzhiyun 				cur_if->empty_scan++;
3900*4882a593Smuzhiyun 				if ((assoc && cur_if->empty_scan >= STA_EMPTY_SCAN_MAX) ||
3901*4882a593Smuzhiyun 						(diff_ms < STA_LINKDOWN_TIMEOUT &&
3902*4882a593Smuzhiyun 						apsta_params->linkdown_reason == WLC_E_LINK_BCN_LOSS)) {
3903*4882a593Smuzhiyun 					if (conf->chip == BCM43569_CHIP_ID) {
3904*4882a593Smuzhiyun 						if (assoc) {
3905*4882a593Smuzhiyun 							IAPSTA_INFO(dev->name, "wl disassoc for empty scan\n");
3906*4882a593Smuzhiyun 							wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
3907*4882a593Smuzhiyun 						}
3908*4882a593Smuzhiyun 					} else {
3909*4882a593Smuzhiyun 						IAPSTA_INFO(dev->name, "wl reinit for empty scan\n");
3910*4882a593Smuzhiyun 						wl_ext_ioctl(dev, WLC_INIT, NULL, 0, 1);
3911*4882a593Smuzhiyun 					}
3912*4882a593Smuzhiyun 				}
3913*4882a593Smuzhiyun 			}
3914*4882a593Smuzhiyun 			else {
3915*4882a593Smuzhiyun 				cur_if->empty_scan = 0;
3916*4882a593Smuzhiyun 			}
3917*4882a593Smuzhiyun 			break;
3918*4882a593Smuzhiyun #endif /* WL_CFG80211 */
3919*4882a593Smuzhiyun 		case WL_EXT_STATUS_PRE_DISCONNECTING:
3920*4882a593Smuzhiyun #ifdef EAPOL_RESEND
3921*4882a593Smuzhiyun 			wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE);
3922*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
3923*4882a593Smuzhiyun #ifdef KEY_INSTALL_CHECK
3924*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->key_install_timer, 0);
3925*4882a593Smuzhiyun #endif /* KEY_INSTALL_CHECK */
3926*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->connect_timer, 0);
3927*4882a593Smuzhiyun #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
3928*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->reconnect_timer, 0);
3929*4882a593Smuzhiyun 			memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t));
3930*4882a593Smuzhiyun #ifdef WL_EXT_DISCONNECT_RECONNECT
3931*4882a593Smuzhiyun 			cur_if->sta_disc_recon_cnt = 0;
3932*4882a593Smuzhiyun #endif /* WL_EXT_DISCONNECT_RECONNECT */
3933*4882a593Smuzhiyun #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
3934*4882a593Smuzhiyun #ifdef SCAN_SUPPRESS
3935*4882a593Smuzhiyun 			apsta_params->scan_busy_cnt = 0;
3936*4882a593Smuzhiyun #endif /* SCAN_SUPPRESS */
3937*4882a593Smuzhiyun 			break;
3938*4882a593Smuzhiyun 		case WL_EXT_STATUS_DISCONNECTING:
3939*4882a593Smuzhiyun 			if (connecting) {
3940*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "connect failed at %d\n", cur_conn_state);
3941*4882a593Smuzhiyun 				wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_IDLE);
3942*4882a593Smuzhiyun 			}
3943*4882a593Smuzhiyun 			if (action & STA_NO_BTC_IN4WAY) {
3944*4882a593Smuzhiyun 				wl_set_btc_in4way(apsta_params, cur_if, status, FALSE);
3945*4882a593Smuzhiyun 			}
3946*4882a593Smuzhiyun #ifdef BTC_WAR
3947*4882a593Smuzhiyun 			wl_ext_btc_config(cur_if->dev, FALSE);
3948*4882a593Smuzhiyun #endif /* BTC_WAR */
3949*4882a593Smuzhiyun 			if (action & STA_WAIT_DISCONNECTED) {
3950*4882a593Smuzhiyun 				wl_wait_disconnect(apsta_params, cur_if, status);
3951*4882a593Smuzhiyun 				wake_up_interruptible(&conf->event_complete);
3952*4882a593Smuzhiyun 			}
3953*4882a593Smuzhiyun 			break;
3954*4882a593Smuzhiyun 		case WL_EXT_STATUS_CONNECTING:
3955*4882a593Smuzhiyun #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
3956*4882a593Smuzhiyun 			if (action & STA_REASSOC_RETRY) {
3957*4882a593Smuzhiyun 				wl_ext_set_connect_retry(dev, context);
3958*4882a593Smuzhiyun 			}
3959*4882a593Smuzhiyun #ifdef WL_EXT_DISCONNECT_RECONNECT
3960*4882a593Smuzhiyun 			cur_if->sta_disc_recon_cnt = 0;
3961*4882a593Smuzhiyun #endif /* WL_EXT_DISCONNECT_RECONNECT */
3962*4882a593Smuzhiyun #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
3963*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->connect_timer, STA_CONNECT_TIMEOUT);
3964*4882a593Smuzhiyun 			osl_do_gettimeofday(sta_conn_ts);
3965*4882a593Smuzhiyun 			wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTING);
3966*4882a593Smuzhiyun 			if (action & STA_NO_BTC_IN4WAY) {
3967*4882a593Smuzhiyun 				wl_set_btc_in4way(apsta_params, cur_if, status, TRUE);
3968*4882a593Smuzhiyun 			}
3969*4882a593Smuzhiyun 			break;
3970*4882a593Smuzhiyun 		case WL_EXT_STATUS_CONNECTED:
3971*4882a593Smuzhiyun 			wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
3972*4882a593Smuzhiyun 			if ((wpa_auth < WPA_AUTH_UNSPECIFIED) || (wpa_auth & WPA2_AUTH_FT)) {
3973*4882a593Smuzhiyun 				wl_timer_mod(dhd, &cur_if->connect_timer, 0);
3974*4882a593Smuzhiyun 				wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED);
3975*4882a593Smuzhiyun #ifdef BTC_WAR
3976*4882a593Smuzhiyun 				wl_ext_btc_config(cur_if->dev, TRUE);
3977*4882a593Smuzhiyun #endif /* BTC_WAR */
3978*4882a593Smuzhiyun 				max_wait_time = 0;
3979*4882a593Smuzhiyun 			} else {
3980*4882a593Smuzhiyun 				max_wait_time = STA_4WAY_TIMEOUT;
3981*4882a593Smuzhiyun 			}
3982*4882a593Smuzhiyun #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
3983*4882a593Smuzhiyun 			wl_ext_update_assoc_info(dev, TRUE);
3984*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time);
3985*4882a593Smuzhiyun #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
3986*4882a593Smuzhiyun 			if (cur_if->ifmode == ISTA_MODE) {
3987*4882a593Smuzhiyun 				dhd_conf_set_wme(dhd, cur_if->ifidx, 0);
3988*4882a593Smuzhiyun 				wake_up_interruptible(&conf->event_complete);
3989*4882a593Smuzhiyun 			}
3990*4882a593Smuzhiyun 			else if (cur_if->ifmode == IGC_MODE) {
3991*4882a593Smuzhiyun 				dhd_conf_set_mchan_bw(dhd, WL_P2P_IF_CLIENT, -1);
3992*4882a593Smuzhiyun 			}
3993*4882a593Smuzhiyun 			break;
3994*4882a593Smuzhiyun 		case WL_EXT_STATUS_ROAMED:
3995*4882a593Smuzhiyun 			wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
3996*4882a593Smuzhiyun 			if ((wpa_auth >= WPA_AUTH_UNSPECIFIED) && !(wpa_auth & WPA2_AUTH_FT)) {
3997*4882a593Smuzhiyun 				wl_timer_mod(dhd, &cur_if->connect_timer, STA_CONNECT_TIMEOUT);
3998*4882a593Smuzhiyun 				osl_do_gettimeofday(sta_conn_ts);
3999*4882a593Smuzhiyun 				wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTING);
4000*4882a593Smuzhiyun #ifdef BTC_WAR
4001*4882a593Smuzhiyun 				wl_ext_btc_config(cur_if->dev, TRUE);
4002*4882a593Smuzhiyun #endif /* BTC_WAR */
4003*4882a593Smuzhiyun 				max_wait_time = STA_4WAY_TIMEOUT;
4004*4882a593Smuzhiyun 			} else {
4005*4882a593Smuzhiyun 				max_wait_time = 0;
4006*4882a593Smuzhiyun 			}
4007*4882a593Smuzhiyun #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
4008*4882a593Smuzhiyun 			wl_ext_update_assoc_info(dev, TRUE);
4009*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time);
4010*4882a593Smuzhiyun #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
4011*4882a593Smuzhiyun #ifdef KEY_INSTALL_CHECK
4012*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->key_install_timer, 0);
4013*4882a593Smuzhiyun #endif /* KEY_INSTALL_CHECK */
4014*4882a593Smuzhiyun 			if (cur_if->ifmode == ISTA_MODE) {
4015*4882a593Smuzhiyun 				dhd_conf_set_wme(dhd, cur_if->ifidx, 0);
4016*4882a593Smuzhiyun 				wake_up_interruptible(&conf->event_complete);
4017*4882a593Smuzhiyun 			}
4018*4882a593Smuzhiyun 			break;
4019*4882a593Smuzhiyun 		case WL_EXT_STATUS_RECONNECT:
4020*4882a593Smuzhiyun #ifdef EAPOL_RESEND
4021*4882a593Smuzhiyun 			wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE);
4022*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
4023*4882a593Smuzhiyun #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
4024*4882a593Smuzhiyun 			if (action & STA_REASSOC_RETRY) {
4025*4882a593Smuzhiyun 				ret = wl_ext_connect_retry(dev, e);
4026*4882a593Smuzhiyun 			}
4027*4882a593Smuzhiyun #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
4028*4882a593Smuzhiyun 			break;
4029*4882a593Smuzhiyun 		case WL_EXT_STATUS_DISCONNECTED:
4030*4882a593Smuzhiyun #ifdef EAPOL_RESEND
4031*4882a593Smuzhiyun 			wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE);
4032*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
4033*4882a593Smuzhiyun #ifdef KEY_INSTALL_CHECK
4034*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->key_install_timer, 0);
4035*4882a593Smuzhiyun #endif /* KEY_INSTALL_CHECK */
4036*4882a593Smuzhiyun #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
4037*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->reconnect_timer, 0);
4038*4882a593Smuzhiyun 			memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t));
4039*4882a593Smuzhiyun #ifdef WL_EXT_DISCONNECT_RECONNECT
4040*4882a593Smuzhiyun 			cur_if->sta_disc_recon_cnt = 0;
4041*4882a593Smuzhiyun #endif /* WL_EXT_DISCONNECT_RECONNECT */
4042*4882a593Smuzhiyun #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
4043*4882a593Smuzhiyun #ifdef SCAN_SUPPRESS
4044*4882a593Smuzhiyun 			apsta_params->scan_busy_cnt = 0;
4045*4882a593Smuzhiyun #endif /* SCAN_SUPPRESS */
4046*4882a593Smuzhiyun 			if (e && ntoh32(e->event_type) == WLC_E_LINK &&
4047*4882a593Smuzhiyun 					!(ntoh16(e->flags) & WLC_EVENT_MSG_LINK)) {
4048*4882a593Smuzhiyun 				apsta_params->linkdown_reason = ntoh32(e->reason);
4049*4882a593Smuzhiyun 			}
4050*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->connect_timer, 0);
4051*4882a593Smuzhiyun 			if (connecting) {
4052*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "connect failed at %d\n", cur_conn_state);
4053*4882a593Smuzhiyun 			}
4054*4882a593Smuzhiyun 			wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_IDLE);
4055*4882a593Smuzhiyun 			if (action & STA_NO_BTC_IN4WAY) {
4056*4882a593Smuzhiyun 				wl_set_btc_in4way(apsta_params, cur_if, status, FALSE);
4057*4882a593Smuzhiyun 			}
4058*4882a593Smuzhiyun #ifdef BTC_WAR
4059*4882a593Smuzhiyun 			wl_ext_btc_config(cur_if->dev, FALSE);
4060*4882a593Smuzhiyun #endif /* BTC_WAR */
4061*4882a593Smuzhiyun 			osl_do_gettimeofday(sta_disc_ts);
4062*4882a593Smuzhiyun 			wake_up_interruptible(&conf->event_complete);
4063*4882a593Smuzhiyun 			break;
4064*4882a593Smuzhiyun 		case WL_EXT_STATUS_ADD_KEY:
4065*4882a593Smuzhiyun 			conn_state = CONN_STATE_ADD_KEY;
4066*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->connect_timer, 0);
4067*4882a593Smuzhiyun #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
4068*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->reconnect_timer, 0);
4069*4882a593Smuzhiyun #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
4070*4882a593Smuzhiyun #ifdef KEY_INSTALL_CHECK
4071*4882a593Smuzhiyun 			key_installed = wl_key_installed(cur_if);
4072*4882a593Smuzhiyun #endif /* KEY_INSTALL_CHECK */
4073*4882a593Smuzhiyun 			if (key_installed)
4074*4882a593Smuzhiyun 				conn_state = CONN_STATE_CONNECTED;
4075*4882a593Smuzhiyun 			wl_ext_update_conn_state(dhd, cur_if->ifidx, conn_state);
4076*4882a593Smuzhiyun 			IAPSTA_INFO(dev->name, "WPA 4-WAY complete %d => %d\n",
4077*4882a593Smuzhiyun 				cur_conn_state, conn_state);
4078*4882a593Smuzhiyun #ifdef EAPOL_RESEND
4079*4882a593Smuzhiyun 			if (key_installed)
4080*4882a593Smuzhiyun 				wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE);
4081*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
4082*4882a593Smuzhiyun 			if (action & STA_NO_BTC_IN4WAY) {
4083*4882a593Smuzhiyun 				wl_set_btc_in4way(apsta_params, cur_if, status, FALSE);
4084*4882a593Smuzhiyun 			}
4085*4882a593Smuzhiyun #ifdef BTC_WAR
4086*4882a593Smuzhiyun 			wl_ext_btc_config(cur_if->dev, TRUE);
4087*4882a593Smuzhiyun #endif /* BTC_WAR */
4088*4882a593Smuzhiyun 			wake_up_interruptible(&conf->event_complete);
4089*4882a593Smuzhiyun 			break;
4090*4882a593Smuzhiyun 		default:
4091*4882a593Smuzhiyun 			IAPSTA_INFO(dev->name, "Unknown action=0x%x, status=%d\n", action, status);
4092*4882a593Smuzhiyun 	}
4093*4882a593Smuzhiyun 
4094*4882a593Smuzhiyun 	return ret;
4095*4882a593Smuzhiyun }
4096*4882a593Smuzhiyun 
4097*4882a593Smuzhiyun #ifdef WL_CFG80211
4098*4882a593Smuzhiyun static int
wl_ext_in4way_sync_ap(dhd_pub_t * dhd,struct wl_if_info * cur_if,uint action,enum wl_ext_status status,void * context)4099*4882a593Smuzhiyun wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if,
4100*4882a593Smuzhiyun 	uint action, enum wl_ext_status status, void *context)
4101*4882a593Smuzhiyun {
4102*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4103*4882a593Smuzhiyun 	struct net_device *dev = cur_if->dev;
4104*4882a593Smuzhiyun 	struct osl_timespec cur_ts, *ap_disc_sta_ts = &cur_if->ap_disc_sta_ts;
4105*4882a593Smuzhiyun 	u8 *ap_disc_sta_bssid = (u8*)&cur_if->ap_disc_sta_bssid;
4106*4882a593Smuzhiyun 	uint32 diff_ms = 0, timeout, max_wait_time = 300;
4107*4882a593Smuzhiyun 	int ret = 0, suppressed = 0;
4108*4882a593Smuzhiyun 	u8* mac_addr = context;
4109*4882a593Smuzhiyun 	bool wait = FALSE;
4110*4882a593Smuzhiyun 
4111*4882a593Smuzhiyun 	action = action & dhd->conf->in4way;
4112*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "status=%d, action=0x%x, in4way=0x%x\n",
4113*4882a593Smuzhiyun 		status, action, dhd->conf->in4way);
4114*4882a593Smuzhiyun 
4115*4882a593Smuzhiyun 	switch (status) {
4116*4882a593Smuzhiyun 		case WL_EXT_STATUS_SCAN:
4117*4882a593Smuzhiyun 			wldev_ioctl(dev, WLC_GET_SCANSUPPRESS, &suppressed, sizeof(int), false);
4118*4882a593Smuzhiyun 			if (suppressed) {
4119*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "scan suppressed\n");
4120*4882a593Smuzhiyun 				ret = -EBUSY;
4121*4882a593Smuzhiyun 				break;
4122*4882a593Smuzhiyun 			}
4123*4882a593Smuzhiyun 			break;
4124*4882a593Smuzhiyun 		case WL_EXT_STATUS_AP_ENABLING:
4125*4882a593Smuzhiyun #ifdef RESTART_AP_WAR
4126*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->restart_ap_timer, AP_RESTART_TIMEOUT);
4127*4882a593Smuzhiyun #endif /* RESTART_AP_WAR */
4128*4882a593Smuzhiyun 			break;
4129*4882a593Smuzhiyun 		case WL_EXT_STATUS_AP_ENABLED:
4130*4882a593Smuzhiyun #ifdef RESTART_AP_WAR
4131*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->restart_ap_timer, 0);
4132*4882a593Smuzhiyun #endif /* RESTART_AP_WAR */
4133*4882a593Smuzhiyun 			if (cur_if->ifmode == IAP_MODE)
4134*4882a593Smuzhiyun 				dhd_conf_set_wme(dhd, cur_if->ifidx, 1);
4135*4882a593Smuzhiyun 			else if (cur_if->ifmode == IGO_MODE)
4136*4882a593Smuzhiyun 				dhd_conf_set_mchan_bw(dhd, WL_P2P_IF_GO, -1);
4137*4882a593Smuzhiyun 			break;
4138*4882a593Smuzhiyun 		case WL_EXT_STATUS_AP_DISABLING:
4139*4882a593Smuzhiyun #ifdef RESTART_AP_WAR
4140*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->restart_ap_timer, 0);
4141*4882a593Smuzhiyun #endif /* RESTART_AP_WAR */
4142*4882a593Smuzhiyun 			break;
4143*4882a593Smuzhiyun 		case WL_EXT_STATUS_DELETE_STA:
4144*4882a593Smuzhiyun 			if (action & AP_WAIT_STA_RECONNECT) {
4145*4882a593Smuzhiyun 				osl_do_gettimeofday(&cur_ts);
4146*4882a593Smuzhiyun 				diff_ms = osl_do_gettimediff(&cur_ts, ap_disc_sta_ts)/1000;
4147*4882a593Smuzhiyun 				if (cur_if->ifmode == IAP_MODE &&
4148*4882a593Smuzhiyun 						mac_addr && diff_ms < max_wait_time &&
4149*4882a593Smuzhiyun 						!memcmp(ap_disc_sta_bssid, mac_addr, ETHER_ADDR_LEN)) {
4150*4882a593Smuzhiyun 					wait = TRUE;
4151*4882a593Smuzhiyun 				} else if (cur_if->ifmode == IGO_MODE &&
4152*4882a593Smuzhiyun 						cur_if->conn_state == CONN_STATE_WSC_DONE &&
4153*4882a593Smuzhiyun 						memcmp(&ether_bcast, mac_addr, ETHER_ADDR_LEN)) {
4154*4882a593Smuzhiyun 					wait = TRUE;
4155*4882a593Smuzhiyun 				}
4156*4882a593Smuzhiyun 				if (wait) {
4157*4882a593Smuzhiyun 					IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d, waiting %dms ...\n",
4158*4882a593Smuzhiyun 						status, cur_if->ap_recon_sta, max_wait_time);
4159*4882a593Smuzhiyun 					mutex_unlock(&apsta_params->in4way_sync);
4160*4882a593Smuzhiyun 					timeout = wait_event_interruptible_timeout(cur_if->ap_recon_sta_event,
4161*4882a593Smuzhiyun 						cur_if->ap_recon_sta, msecs_to_jiffies(max_wait_time));
4162*4882a593Smuzhiyun 					mutex_lock(&apsta_params->in4way_sync);
4163*4882a593Smuzhiyun 					IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d, timeout=%d\n",
4164*4882a593Smuzhiyun 						status, cur_if->ap_recon_sta, timeout);
4165*4882a593Smuzhiyun 					if (timeout > 0) {
4166*4882a593Smuzhiyun 						IAPSTA_INFO(dev->name, "skip delete STA %pM\n", mac_addr);
4167*4882a593Smuzhiyun 						ret = -1;
4168*4882a593Smuzhiyun 						break;
4169*4882a593Smuzhiyun 					}
4170*4882a593Smuzhiyun 				} else {
4171*4882a593Smuzhiyun 					IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d => 0\n",
4172*4882a593Smuzhiyun 						status, cur_if->ap_recon_sta);
4173*4882a593Smuzhiyun 					cur_if->ap_recon_sta = FALSE;
4174*4882a593Smuzhiyun 					if (cur_if->ifmode == IGO_MODE)
4175*4882a593Smuzhiyun 						wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_IDLE);
4176*4882a593Smuzhiyun 				}
4177*4882a593Smuzhiyun 			}
4178*4882a593Smuzhiyun 			break;
4179*4882a593Smuzhiyun 		case WL_EXT_STATUS_STA_DISCONNECTED:
4180*4882a593Smuzhiyun 			if (action & AP_WAIT_STA_RECONNECT) {
4181*4882a593Smuzhiyun 				IAPSTA_INFO(dev->name, "latest disc STA %pM ap_recon_sta=%d\n",
4182*4882a593Smuzhiyun 					ap_disc_sta_bssid, cur_if->ap_recon_sta);
4183*4882a593Smuzhiyun 				osl_do_gettimeofday(ap_disc_sta_ts);
4184*4882a593Smuzhiyun 				memcpy(ap_disc_sta_bssid, mac_addr, ETHER_ADDR_LEN);
4185*4882a593Smuzhiyun 				cur_if->ap_recon_sta = FALSE;
4186*4882a593Smuzhiyun 			}
4187*4882a593Smuzhiyun 			break;
4188*4882a593Smuzhiyun 		case WL_EXT_STATUS_STA_CONNECTED:
4189*4882a593Smuzhiyun 			if (action & AP_WAIT_STA_RECONNECT) {
4190*4882a593Smuzhiyun 				osl_do_gettimeofday(&cur_ts);
4191*4882a593Smuzhiyun 				diff_ms = osl_do_gettimediff(&cur_ts, ap_disc_sta_ts)/1000;
4192*4882a593Smuzhiyun 				if (diff_ms < max_wait_time &&
4193*4882a593Smuzhiyun 						!memcmp(ap_disc_sta_bssid, mac_addr, ETHER_ADDR_LEN)) {
4194*4882a593Smuzhiyun 					IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d => 1\n",
4195*4882a593Smuzhiyun 						status, cur_if->ap_recon_sta);
4196*4882a593Smuzhiyun 					cur_if->ap_recon_sta = TRUE;
4197*4882a593Smuzhiyun 					wake_up_interruptible(&cur_if->ap_recon_sta_event);
4198*4882a593Smuzhiyun 				} else {
4199*4882a593Smuzhiyun 					cur_if->ap_recon_sta = FALSE;
4200*4882a593Smuzhiyun 				}
4201*4882a593Smuzhiyun 			}
4202*4882a593Smuzhiyun 			break;
4203*4882a593Smuzhiyun 		default:
4204*4882a593Smuzhiyun 			IAPSTA_INFO(dev->name, "Unknown action=0x%x, status=%d\n", action, status);
4205*4882a593Smuzhiyun 	}
4206*4882a593Smuzhiyun 
4207*4882a593Smuzhiyun 	return ret;
4208*4882a593Smuzhiyun }
4209*4882a593Smuzhiyun 
4210*4882a593Smuzhiyun int
wl_ext_in4way_sync(struct net_device * dev,uint action,enum wl_ext_status status,void * context)4211*4882a593Smuzhiyun wl_ext_in4way_sync(struct net_device *dev, uint action,
4212*4882a593Smuzhiyun 	enum wl_ext_status status, void *context)
4213*4882a593Smuzhiyun {
4214*4882a593Smuzhiyun 	dhd_pub_t *dhd = dhd_get_pub(dev);
4215*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4216*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
4217*4882a593Smuzhiyun 	int ret = 0;
4218*4882a593Smuzhiyun 
4219*4882a593Smuzhiyun 	mutex_lock(&apsta_params->in4way_sync);
4220*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
4221*4882a593Smuzhiyun 	if (cur_if) {
4222*4882a593Smuzhiyun 		if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE)
4223*4882a593Smuzhiyun 			ret = wl_ext_in4way_sync_sta(dhd, cur_if, action, status, context);
4224*4882a593Smuzhiyun 		else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IGO_MODE)
4225*4882a593Smuzhiyun 			ret = wl_ext_in4way_sync_ap(dhd, cur_if, action, status, context);
4226*4882a593Smuzhiyun 		else
4227*4882a593Smuzhiyun 			IAPSTA_INFO(dev->name, "Unknown mode %d\n", cur_if->ifmode);
4228*4882a593Smuzhiyun 	}
4229*4882a593Smuzhiyun 	mutex_unlock(&apsta_params->in4way_sync);
4230*4882a593Smuzhiyun 
4231*4882a593Smuzhiyun 	return ret;
4232*4882a593Smuzhiyun }
4233*4882a593Smuzhiyun 
4234*4882a593Smuzhiyun void
wl_ext_update_extsae_4way(struct net_device * dev,const struct ieee80211_mgmt * mgmt,bool tx)4235*4882a593Smuzhiyun wl_ext_update_extsae_4way(struct net_device *dev,
4236*4882a593Smuzhiyun 	const struct ieee80211_mgmt *mgmt, bool tx)
4237*4882a593Smuzhiyun {
4238*4882a593Smuzhiyun 	dhd_pub_t *dhd = dhd_get_pub(dev);
4239*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
4240*4882a593Smuzhiyun 	uint32 auth_alg, auth_seq, status_code;
4241*4882a593Smuzhiyun 	uint conn_state = 0;
4242*4882a593Smuzhiyun 	char sae_type[32] = "";
4243*4882a593Smuzhiyun 
4244*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
4245*4882a593Smuzhiyun 	if (!cur_if)
4246*4882a593Smuzhiyun 		return;
4247*4882a593Smuzhiyun 
4248*4882a593Smuzhiyun 	auth_alg = mgmt->u.auth.auth_alg;
4249*4882a593Smuzhiyun 	auth_seq = mgmt->u.auth.auth_transaction;
4250*4882a593Smuzhiyun 	status_code = mgmt->u.auth.status_code;
4251*4882a593Smuzhiyun 	if (auth_alg == WLAN_AUTH_SAE) {
4252*4882a593Smuzhiyun 		if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) {
4253*4882a593Smuzhiyun 			if (auth_seq == 1) {
4254*4882a593Smuzhiyun 				if (tx)
4255*4882a593Smuzhiyun 					conn_state = CONN_STATE_AUTH_SAE_M1;
4256*4882a593Smuzhiyun 				else
4257*4882a593Smuzhiyun 					conn_state = CONN_STATE_AUTH_SAE_M2;
4258*4882a593Smuzhiyun 			} else if (auth_seq == 2) {
4259*4882a593Smuzhiyun 				if (tx)
4260*4882a593Smuzhiyun 					conn_state = CONN_STATE_AUTH_SAE_M3;
4261*4882a593Smuzhiyun 				else
4262*4882a593Smuzhiyun 					conn_state = CONN_STATE_AUTH_SAE_M4;
4263*4882a593Smuzhiyun 			}
4264*4882a593Smuzhiyun 		} else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IGO_MODE) {
4265*4882a593Smuzhiyun 			if (auth_seq == 1) {
4266*4882a593Smuzhiyun 				if (tx)
4267*4882a593Smuzhiyun 					conn_state = CONN_STATE_AUTH_SAE_M2;
4268*4882a593Smuzhiyun 				else
4269*4882a593Smuzhiyun 					conn_state = CONN_STATE_AUTH_SAE_M1;
4270*4882a593Smuzhiyun 			} else if (auth_seq == 2) {
4271*4882a593Smuzhiyun 				if (tx)
4272*4882a593Smuzhiyun 					conn_state = CONN_STATE_AUTH_SAE_M4;
4273*4882a593Smuzhiyun 				else
4274*4882a593Smuzhiyun 					conn_state = CONN_STATE_AUTH_SAE_M3;
4275*4882a593Smuzhiyun 			}
4276*4882a593Smuzhiyun 		}
4277*4882a593Smuzhiyun 		if (status_code == 76) {
4278*4882a593Smuzhiyun 			snprintf(sae_type, sizeof(sae_type), "%d(Anti-clogging)", status_code);
4279*4882a593Smuzhiyun 		} else if (status_code == 126) {
4280*4882a593Smuzhiyun 			snprintf(sae_type, sizeof(sae_type), "%d(R3-H2E)", status_code);
4281*4882a593Smuzhiyun 		} else {
4282*4882a593Smuzhiyun 			snprintf(sae_type, sizeof(sae_type), "%d", status_code);
4283*4882a593Smuzhiyun 		}
4284*4882a593Smuzhiyun 	}
4285*4882a593Smuzhiyun 	if (conn_state) {
4286*4882a593Smuzhiyun 		wl_ext_update_conn_state(dhd, cur_if->ifidx, conn_state);
4287*4882a593Smuzhiyun 		if (dump_msg_level & DUMP_EAPOL_VAL) {
4288*4882a593Smuzhiyun 			if (tx) {
4289*4882a593Smuzhiyun 				WL_MSG(dev->name, "WPA3 SAE M%d [TX] : (%pM) -> (%pM), status=%s\n",
4290*4882a593Smuzhiyun 					conn_state-CONN_STATE_AUTH_SAE_M1+1, mgmt->sa, mgmt->da, sae_type);
4291*4882a593Smuzhiyun 			} else {
4292*4882a593Smuzhiyun 				WL_MSG(dev->name, "WPA3 SAE M%d [RX] : (%pM) <- (%pM), status=%s\n",
4293*4882a593Smuzhiyun 					conn_state-CONN_STATE_AUTH_SAE_M1+1, mgmt->da, mgmt->sa, sae_type);
4294*4882a593Smuzhiyun 			}
4295*4882a593Smuzhiyun 		}
4296*4882a593Smuzhiyun 	} else {
4297*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "Unknown auth_alg=%d or auth_seq=%d\n",
4298*4882a593Smuzhiyun 			auth_alg, auth_seq);
4299*4882a593Smuzhiyun 	}
4300*4882a593Smuzhiyun 
4301*4882a593Smuzhiyun 	return;
4302*4882a593Smuzhiyun }
4303*4882a593Smuzhiyun #endif /* WL_CFG80211 */
4304*4882a593Smuzhiyun 
4305*4882a593Smuzhiyun #ifdef WL_WIRELESS_EXT
4306*4882a593Smuzhiyun int
wl_ext_in4way_sync_wext(struct net_device * dev,uint action,enum wl_ext_status status,void * context)4307*4882a593Smuzhiyun wl_ext_in4way_sync_wext(struct net_device *dev, uint action,
4308*4882a593Smuzhiyun 	enum wl_ext_status status, void *context)
4309*4882a593Smuzhiyun {
4310*4882a593Smuzhiyun 	int ret = 0;
4311*4882a593Smuzhiyun #ifndef WL_CFG80211
4312*4882a593Smuzhiyun 	dhd_pub_t *dhd = dhd_get_pub(dev);
4313*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params;
4314*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
4315*4882a593Smuzhiyun 
4316*4882a593Smuzhiyun 	if (!dhd)
4317*4882a593Smuzhiyun 		return 0;
4318*4882a593Smuzhiyun 
4319*4882a593Smuzhiyun 	apsta_params = dhd->iapsta_params;
4320*4882a593Smuzhiyun 
4321*4882a593Smuzhiyun 	mutex_lock(&apsta_params->in4way_sync);
4322*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
4323*4882a593Smuzhiyun 	if (cur_if && cur_if->ifmode == ISTA_MODE) {
4324*4882a593Smuzhiyun 		if (status == WL_EXT_STATUS_DISCONNECTING) {
4325*4882a593Smuzhiyun 			wl_ext_add_remove_pm_enable_work(dev, FALSE);
4326*4882a593Smuzhiyun 		} else if (status == WL_EXT_STATUS_CONNECTING) {
4327*4882a593Smuzhiyun 			wl_ext_add_remove_pm_enable_work(dev, TRUE);
4328*4882a593Smuzhiyun 		}
4329*4882a593Smuzhiyun 		ret = wl_ext_in4way_sync_sta(dhd, cur_if, 0, status, NULL);
4330*4882a593Smuzhiyun 	}
4331*4882a593Smuzhiyun 	mutex_unlock(&apsta_params->in4way_sync);
4332*4882a593Smuzhiyun #endif
4333*4882a593Smuzhiyun 	return ret;
4334*4882a593Smuzhiyun }
4335*4882a593Smuzhiyun #endif /* WL_WIRELESS_EXT */
4336*4882a593Smuzhiyun 
4337*4882a593Smuzhiyun #ifdef TPUT_MONITOR
4338*4882a593Smuzhiyun static void
wl_tput_monitor_timer(unsigned long data)4339*4882a593Smuzhiyun wl_tput_monitor_timer(unsigned long data)
4340*4882a593Smuzhiyun {
4341*4882a593Smuzhiyun 	struct net_device *dev = (struct net_device *)data;
4342*4882a593Smuzhiyun 	struct dhd_pub *dhd;
4343*4882a593Smuzhiyun 	wl_event_msg_t msg;
4344*4882a593Smuzhiyun 
4345*4882a593Smuzhiyun 	if (!dev) {
4346*4882a593Smuzhiyun 		IAPSTA_ERROR("wlan", "dev is not ready\n");
4347*4882a593Smuzhiyun 		return;
4348*4882a593Smuzhiyun 	}
4349*4882a593Smuzhiyun 
4350*4882a593Smuzhiyun 	dhd = dhd_get_pub(dev);
4351*4882a593Smuzhiyun 
4352*4882a593Smuzhiyun 	bzero(&msg, sizeof(wl_event_msg_t));
4353*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "timer expired\n");
4354*4882a593Smuzhiyun 
4355*4882a593Smuzhiyun 	msg.ifidx = 0;
4356*4882a593Smuzhiyun 	msg.event_type = hton32(WLC_E_RESERVED);
4357*4882a593Smuzhiyun 	msg.reason = hton32(ISAM_RC_TPUT_MONITOR);
4358*4882a593Smuzhiyun 	wl_ext_event_send(dhd->event_params, &msg, NULL);
4359*4882a593Smuzhiyun }
4360*4882a593Smuzhiyun 
4361*4882a593Smuzhiyun static int
wl_ext_assoclist_num(struct net_device * dev)4362*4882a593Smuzhiyun wl_ext_assoclist_num(struct net_device *dev)
4363*4882a593Smuzhiyun {
4364*4882a593Smuzhiyun 	int ret = 0, maxassoc = 0;
4365*4882a593Smuzhiyun 	char mac_buf[MAX_NUM_OF_ASSOCLIST *
4366*4882a593Smuzhiyun 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
4367*4882a593Smuzhiyun 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
4368*4882a593Smuzhiyun 
4369*4882a593Smuzhiyun 	assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
4370*4882a593Smuzhiyun 	ret = wl_ext_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf), 0);
4371*4882a593Smuzhiyun 	if (ret)
4372*4882a593Smuzhiyun 		return 0;
4373*4882a593Smuzhiyun 	maxassoc = dtoh32(assoc_maclist->count);
4374*4882a593Smuzhiyun 
4375*4882a593Smuzhiyun 	return maxassoc;
4376*4882a593Smuzhiyun }
4377*4882a593Smuzhiyun 
4378*4882a593Smuzhiyun static int
dev_wlc_ioctl(struct net_device * dev,int cmd,void * arg,int len)4379*4882a593Smuzhiyun dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len)
4380*4882a593Smuzhiyun {
4381*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
4382*4882a593Smuzhiyun 	dhd_ioctl_t ioc;
4383*4882a593Smuzhiyun 	int8 index;
4384*4882a593Smuzhiyun 	int ret;
4385*4882a593Smuzhiyun 
4386*4882a593Smuzhiyun 	memset(&ioc, 0, sizeof(ioc));
4387*4882a593Smuzhiyun 	ioc.cmd = cmd;
4388*4882a593Smuzhiyun 	ioc.buf = arg;
4389*4882a593Smuzhiyun 	ioc.len = len;
4390*4882a593Smuzhiyun 
4391*4882a593Smuzhiyun 	index = dhd_net2idx(dhd->info, dev);
4392*4882a593Smuzhiyun 	if (index == DHD_BAD_IF) {
4393*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "Bad ifidx from dev\n");
4394*4882a593Smuzhiyun 		return -ENODEV;
4395*4882a593Smuzhiyun 	}
4396*4882a593Smuzhiyun 	ret = dhd_ioctl_process(dhd, index, &ioc, arg);
4397*4882a593Smuzhiyun 
4398*4882a593Smuzhiyun 	return ret;
4399*4882a593Smuzhiyun }
4400*4882a593Smuzhiyun 
4401*4882a593Smuzhiyun static void
wl_ampdu_dump(struct net_device * dev)4402*4882a593Smuzhiyun wl_ampdu_dump(struct net_device *dev)
4403*4882a593Smuzhiyun {
4404*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
4405*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4406*4882a593Smuzhiyun 	char *ioctl_buf = apsta_params->ioctl_buf, *buf = NULL;
4407*4882a593Smuzhiyun 	char *tx_pch_start, *tx_pch_end, *rx_pch_start, *rx_pch_end;
4408*4882a593Smuzhiyun 	int ret = 0, max_len, tx_len, rx_len;
4409*4882a593Smuzhiyun 
4410*4882a593Smuzhiyun 	if (!(android_msg_level & ANDROID_AMPDU_LEVEL))
4411*4882a593Smuzhiyun 		return;
4412*4882a593Smuzhiyun 
4413*4882a593Smuzhiyun 	if (!ioctl_buf)
4414*4882a593Smuzhiyun 		return;
4415*4882a593Smuzhiyun 
4416*4882a593Smuzhiyun 	memset(ioctl_buf, 0, WL_DUMP_BUF_LEN);
4417*4882a593Smuzhiyun 	ret = bcm_mkiovar("dump", "ampdu", strlen("ampdu"), ioctl_buf, WL_DUMP_BUF_LEN);
4418*4882a593Smuzhiyun 	if (ret == 0) {
4419*4882a593Smuzhiyun 		goto exit;
4420*4882a593Smuzhiyun 	}
4421*4882a593Smuzhiyun 	ret = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctl_buf, WL_DUMP_BUF_LEN);
4422*4882a593Smuzhiyun 	if (ret) {
4423*4882a593Smuzhiyun 		goto exit;
4424*4882a593Smuzhiyun 	}
4425*4882a593Smuzhiyun 
4426*4882a593Smuzhiyun 	buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
4427*4882a593Smuzhiyun 	if (buf == NULL) {
4428*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_MEDLEN);
4429*4882a593Smuzhiyun 		goto exit;
4430*4882a593Smuzhiyun 	}
4431*4882a593Smuzhiyun 	memset(buf, 0, WLC_IOCTL_MEDLEN);
4432*4882a593Smuzhiyun 	ret = bcm_mkiovar("dump_clear", "ampdu", strlen("ampdu"), buf, WLC_IOCTL_MEDLEN);
4433*4882a593Smuzhiyun 	if (ret == 0) {
4434*4882a593Smuzhiyun 		goto exit;
4435*4882a593Smuzhiyun 	}
4436*4882a593Smuzhiyun 	ret = dev_wlc_ioctl(dev, WLC_SET_VAR, (void *)buf, WLC_IOCTL_MEDLEN);
4437*4882a593Smuzhiyun 	if (ret) {
4438*4882a593Smuzhiyun 		goto exit;
4439*4882a593Smuzhiyun 	}
4440*4882a593Smuzhiyun 
4441*4882a593Smuzhiyun 	tx_pch_start = strstr(ioctl_buf, "TX MCS");
4442*4882a593Smuzhiyun 	tx_pch_end = strstr(ioctl_buf, "HEMU");
4443*4882a593Smuzhiyun 	rx_pch_start = strstr(ioctl_buf, "RX MCS");
4444*4882a593Smuzhiyun 	rx_pch_end = strstr(ioctl_buf, "RX MCS SGI");
4445*4882a593Smuzhiyun 	max_len = (tx_pch_end-tx_pch_start) + (rx_pch_end-rx_pch_start);
4446*4882a593Smuzhiyun 	if (max_len > (WLC_IOCTL_MEDLEN-1))
4447*4882a593Smuzhiyun 		goto exit;
4448*4882a593Smuzhiyun 
4449*4882a593Smuzhiyun 	tx_len = tx_pch_end - tx_pch_start;
4450*4882a593Smuzhiyun 	rx_len = rx_pch_end - rx_pch_start;
4451*4882a593Smuzhiyun 
4452*4882a593Smuzhiyun 	memset(buf, 0, WLC_IOCTL_MEDLEN);
4453*4882a593Smuzhiyun 	memcpy(buf, tx_pch_start, tx_len);
4454*4882a593Smuzhiyun 	memcpy(buf+tx_len, rx_pch_start, rx_len);
4455*4882a593Smuzhiyun 	WL_MSG(dev->name,"\n%s\n", buf);
4456*4882a593Smuzhiyun 
4457*4882a593Smuzhiyun exit:
4458*4882a593Smuzhiyun 	if (buf)
4459*4882a593Smuzhiyun 		kfree(buf);
4460*4882a593Smuzhiyun }
4461*4882a593Smuzhiyun 
4462*4882a593Smuzhiyun static void
wl_btc_dump(struct net_device * dev)4463*4882a593Smuzhiyun wl_btc_dump(struct net_device *dev)
4464*4882a593Smuzhiyun {
4465*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
4466*4882a593Smuzhiyun 	int ret, val;
4467*4882a593Smuzhiyun 
4468*4882a593Smuzhiyun 	if (!(android_msg_level & ANDROID_BTC_LEVEL))
4469*4882a593Smuzhiyun 		return;
4470*4882a593Smuzhiyun 
4471*4882a593Smuzhiyun 	ret = dhd_conf_reg2args(dhd, "btc_params", FALSE, 15, &val);
4472*4882a593Smuzhiyun 	if (!ret)
4473*4882a593Smuzhiyun 		WL_MSG(dev->name,"btc_params15=%d\n", val);
4474*4882a593Smuzhiyun }
4475*4882a593Smuzhiyun 
4476*4882a593Smuzhiyun static void
wl_tvpm_dump(struct net_device * dev)4477*4882a593Smuzhiyun wl_tvpm_dump(struct net_device *dev)
4478*4882a593Smuzhiyun {
4479*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
4480*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4481*4882a593Smuzhiyun 	wl_tvpm_req_t* tvpm_req = NULL;
4482*4882a593Smuzhiyun 	size_t reqlen = sizeof(wl_tvpm_req_t) + sizeof(wl_tvpm_status_t);
4483*4882a593Smuzhiyun 	uint8 *outbuf = apsta_params->ioctl_buf;
4484*4882a593Smuzhiyun 	size_t outlen = WLC_IOCTL_MEDLEN;
4485*4882a593Smuzhiyun 	wl_tvpm_status_t* status;
4486*4882a593Smuzhiyun 	int ret, phy_temp = 0;
4487*4882a593Smuzhiyun 	bool tvpm = FALSE, sense = FALSE;
4488*4882a593Smuzhiyun 
4489*4882a593Smuzhiyun 	if (!(android_msg_level & ANDROID_TVPM_LEVEL))
4490*4882a593Smuzhiyun 		return;
4491*4882a593Smuzhiyun 
4492*4882a593Smuzhiyun 	tvpm_req = kmalloc(reqlen, GFP_KERNEL);
4493*4882a593Smuzhiyun 	if (tvpm_req == NULL) {
4494*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "MALLOC failed\n");
4495*4882a593Smuzhiyun 		goto exit;
4496*4882a593Smuzhiyun 	}
4497*4882a593Smuzhiyun 	memset(tvpm_req, 0, reqlen);
4498*4882a593Smuzhiyun 
4499*4882a593Smuzhiyun 	tvpm_req->version = TVPM_REQ_VERSION_1;
4500*4882a593Smuzhiyun 	tvpm_req->length = reqlen;
4501*4882a593Smuzhiyun 	tvpm_req->req_type = WL_TVPM_REQ_STATUS;
4502*4882a593Smuzhiyun 	ret = wldev_iovar_getbuf(dev, "tvpm", tvpm_req, reqlen, outbuf, outlen, NULL);
4503*4882a593Smuzhiyun 	status = (wl_tvpm_status_t*)outbuf;
4504*4882a593Smuzhiyun 	if (!ret && status->enable) {
4505*4882a593Smuzhiyun 		tvpm = TRUE;
4506*4882a593Smuzhiyun 	} else {
4507*4882a593Smuzhiyun 		ret = wldev_iovar_getbuf(dev, "phy_tempsense", &phy_temp, sizeof(phy_temp),
4508*4882a593Smuzhiyun 			outbuf, outlen, NULL);
4509*4882a593Smuzhiyun 		if (!ret) {
4510*4882a593Smuzhiyun 			phy_temp = dtoh32(*(int*)outbuf);
4511*4882a593Smuzhiyun 			sense = TRUE;
4512*4882a593Smuzhiyun 		}
4513*4882a593Smuzhiyun 	}
4514*4882a593Smuzhiyun 
4515*4882a593Smuzhiyun 	if (tvpm) {
4516*4882a593Smuzhiyun 		WL_MSG(dev->name,"temp=%3d, duty=%3d, pwrbko=%d, chains=%d\n",
4517*4882a593Smuzhiyun 			status->temp, status->tx_dutycycle, status->tx_power_backoff,
4518*4882a593Smuzhiyun 			status->num_active_chains);
4519*4882a593Smuzhiyun 	}
4520*4882a593Smuzhiyun 	else if (sense) {
4521*4882a593Smuzhiyun 		WL_MSG(dev->name,"phy_temp=%3d\n", phy_temp);
4522*4882a593Smuzhiyun 	}
4523*4882a593Smuzhiyun 
4524*4882a593Smuzhiyun exit:
4525*4882a593Smuzhiyun 	if (tvpm_req)
4526*4882a593Smuzhiyun 		kfree(tvpm_req);
4527*4882a593Smuzhiyun }
4528*4882a593Smuzhiyun 
4529*4882a593Smuzhiyun static void
wl_phy_rssi_ant(struct net_device * dev,struct ether_addr * mac,char * rssi_buf,int len)4530*4882a593Smuzhiyun wl_phy_rssi_ant(struct net_device *dev, struct ether_addr *mac,
4531*4882a593Smuzhiyun 	char *rssi_buf, int len)
4532*4882a593Smuzhiyun {
4533*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
4534*4882a593Smuzhiyun 	char buf[WLC_IOCTL_SMLEN];
4535*4882a593Smuzhiyun 	wl_rssi_ant_t *rssi_ant_p;
4536*4882a593Smuzhiyun 	int ret, bytes_written = 0, i;
4537*4882a593Smuzhiyun 	scb_val_t scb_val;
4538*4882a593Smuzhiyun 
4539*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
4540*4882a593Smuzhiyun 	if (!cur_if)
4541*4882a593Smuzhiyun 		return;
4542*4882a593Smuzhiyun 
4543*4882a593Smuzhiyun 	memset(buf, 0, sizeof(buf));
4544*4882a593Smuzhiyun 	ret = wldev_iovar_getbuf(dev, "phy_rssi_ant",
4545*4882a593Smuzhiyun 		mac, mac ? ETHER_ADDR_LEN : 0, buf, sizeof(buf), NULL);
4546*4882a593Smuzhiyun 	rssi_ant_p = (wl_rssi_ant_t *)buf;
4547*4882a593Smuzhiyun 	rssi_ant_p->version = dtoh32(rssi_ant_p->version);
4548*4882a593Smuzhiyun 	rssi_ant_p->count = dtoh32(rssi_ant_p->count);
4549*4882a593Smuzhiyun 	if (ret < 0 || rssi_ant_p->count == 0) {
4550*4882a593Smuzhiyun 		if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) {
4551*4882a593Smuzhiyun 			wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0);
4552*4882a593Smuzhiyun 			rssi_ant_p->count = 1;
4553*4882a593Smuzhiyun 			rssi_ant_p->rssi_ant[0] = dtoh32(scb_val.val);
4554*4882a593Smuzhiyun 		}
4555*4882a593Smuzhiyun 	}
4556*4882a593Smuzhiyun 	for (i=0; i<rssi_ant_p->count && rssi_ant_p->rssi_ant[i]; i++) {
4557*4882a593Smuzhiyun 		bytes_written += snprintf(rssi_buf+bytes_written, len,
4558*4882a593Smuzhiyun 			"[%2d]", rssi_ant_p->rssi_ant[i]);
4559*4882a593Smuzhiyun 	}
4560*4882a593Smuzhiyun }
4561*4882a593Smuzhiyun 
4562*4882a593Smuzhiyun static void
wl_tput_dump(struct wl_apsta_params * apsta_params,struct net_device * dev,wl_tput_info_t * tput_info)4563*4882a593Smuzhiyun wl_tput_dump(struct wl_apsta_params *apsta_params,
4564*4882a593Smuzhiyun 	struct net_device *dev, wl_tput_info_t *tput_info)
4565*4882a593Smuzhiyun {
4566*4882a593Smuzhiyun 	WL_MSG(dev->name,
4567*4882a593Smuzhiyun 		"tx=%3d.%d%d%d Mbps, rx=%3d.%d%d%d Mbps, tput_sum=%3d.%d%d%d Mbps\n",
4568*4882a593Smuzhiyun 		tput_info->tput_tx, (tput_info->tput_tx_kb/100)%10,
4569*4882a593Smuzhiyun 		(tput_info->tput_tx_kb/10)%10, (tput_info->tput_tx_kb)%10,
4570*4882a593Smuzhiyun 		tput_info->tput_rx, (tput_info->tput_rx_kb/100)%10,
4571*4882a593Smuzhiyun 		(tput_info->tput_rx_kb/10)%10, (tput_info->tput_rx_kb)%10,
4572*4882a593Smuzhiyun 		apsta_params->tput_sum, (apsta_params->tput_sum_kb/100)%10,
4573*4882a593Smuzhiyun 		(apsta_params->tput_sum_kb/10)%10, (apsta_params->tput_sum_kb)%10);
4574*4882a593Smuzhiyun }
4575*4882a593Smuzhiyun 
4576*4882a593Smuzhiyun static void
wl_sta_info_dump(struct net_device * dev,struct ether_addr * mac)4577*4882a593Smuzhiyun wl_sta_info_dump(struct net_device *dev, struct ether_addr *mac)
4578*4882a593Smuzhiyun {
4579*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
4580*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4581*4882a593Smuzhiyun 	void *buf = apsta_params->ioctl_buf;
4582*4882a593Smuzhiyun 	sta_info_v4_t *sta = NULL;
4583*4882a593Smuzhiyun 	char rssi_buf[16];
4584*4882a593Smuzhiyun 	int ret;
4585*4882a593Smuzhiyun 	s32 rate = 0;
4586*4882a593Smuzhiyun 
4587*4882a593Smuzhiyun 	memset(rssi_buf, 0, sizeof(rssi_buf));
4588*4882a593Smuzhiyun 	wl_phy_rssi_ant(dev, mac, rssi_buf, sizeof(rssi_buf));
4589*4882a593Smuzhiyun 	ret = wldev_iovar_getbuf(dev, "sta_info", (const void*)mac,
4590*4882a593Smuzhiyun 		ETHER_ADDR_LEN, buf, WLC_IOCTL_MEDLEN, NULL);
4591*4882a593Smuzhiyun 	if (ret == 0) {
4592*4882a593Smuzhiyun 		sta = (sta_info_v4_t *)buf;
4593*4882a593Smuzhiyun 	}
4594*4882a593Smuzhiyun 	if (sta == NULL || (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5 &&
4595*4882a593Smuzhiyun 			sta->ver != WL_STA_VER_6)) {
4596*4882a593Smuzhiyun 		wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
4597*4882a593Smuzhiyun 		rate = dtoh32(rate);
4598*4882a593Smuzhiyun 		WL_MSG(dev->name,
4599*4882a593Smuzhiyun 			"mac=%pM, rssi=%s, tx_rate:%4d%2s\n",
4600*4882a593Smuzhiyun 			mac, rssi_buf, rate/2, (rate & 1) ? ".5" : "");
4601*4882a593Smuzhiyun 	} else {
4602*4882a593Smuzhiyun 		if (dtoh32(sta->rx_rate) != -1) {
4603*4882a593Smuzhiyun 			WL_MSG(dev->name,
4604*4882a593Smuzhiyun 				"mac=%pM, rssi=%s, tx_rate:%4d.%d, rx_rate:%4d.%d\n",
4605*4882a593Smuzhiyun 				mac, rssi_buf,
4606*4882a593Smuzhiyun 				dtoh32(sta->tx_rate)/1000, ((dtoh32(sta->tx_rate)/100)%10),
4607*4882a593Smuzhiyun 				dtoh32(sta->rx_rate)/1000, ((dtoh32(sta->rx_rate)/100)%10));
4608*4882a593Smuzhiyun 		} else {
4609*4882a593Smuzhiyun 			WL_MSG(dev->name,
4610*4882a593Smuzhiyun 				"mac=%pM, rssi=%s, tx_rate:%4d.%d, rx_rate:%4d\n",
4611*4882a593Smuzhiyun 				mac, rssi_buf,
4612*4882a593Smuzhiyun 				dtoh32(sta->tx_rate)/1000, ((dtoh32(sta->tx_rate)/100)%10),
4613*4882a593Smuzhiyun 				dtoh32(sta->rx_rate));
4614*4882a593Smuzhiyun 		}
4615*4882a593Smuzhiyun 	}
4616*4882a593Smuzhiyun }
4617*4882a593Smuzhiyun 
4618*4882a593Smuzhiyun static void
wl_cur_if_tput_dump(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)4619*4882a593Smuzhiyun wl_cur_if_tput_dump(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
4620*4882a593Smuzhiyun {
4621*4882a593Smuzhiyun #ifdef WLDWDS
4622*4882a593Smuzhiyun 	struct wl_dwds_info *dwds_if;
4623*4882a593Smuzhiyun 	int i;
4624*4882a593Smuzhiyun #endif /* WLDWDS */
4625*4882a593Smuzhiyun 	struct ether_addr bssid;
4626*4882a593Smuzhiyun 	int ret = 0;
4627*4882a593Smuzhiyun 
4628*4882a593Smuzhiyun 	if (!(android_msg_level & ANDROID_TPUT_LEVEL))
4629*4882a593Smuzhiyun 		return;
4630*4882a593Smuzhiyun 
4631*4882a593Smuzhiyun 	wl_tput_dump(apsta_params, cur_if->dev, &cur_if->tput_info);
4632*4882a593Smuzhiyun 
4633*4882a593Smuzhiyun 	if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) {
4634*4882a593Smuzhiyun 		wldev_ioctl(cur_if->dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
4635*4882a593Smuzhiyun 		if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
4636*4882a593Smuzhiyun 			wl_sta_info_dump(cur_if->dev, &bssid);
4637*4882a593Smuzhiyun 		}
4638*4882a593Smuzhiyun 	}
4639*4882a593Smuzhiyun 	else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IGO_MODE) {
4640*4882a593Smuzhiyun 		int i, maxassoc = 0;
4641*4882a593Smuzhiyun 		char mac_buf[MAX_NUM_OF_ASSOCLIST *
4642*4882a593Smuzhiyun 			sizeof(struct ether_addr) + sizeof(uint)] = {0};
4643*4882a593Smuzhiyun 		struct maclist *assoc_maclist = (struct maclist *)mac_buf;
4644*4882a593Smuzhiyun 
4645*4882a593Smuzhiyun 		assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
4646*4882a593Smuzhiyun 		ret = wl_ext_ioctl(cur_if->dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf), 0);
4647*4882a593Smuzhiyun 		if (ret)
4648*4882a593Smuzhiyun 			goto exit;
4649*4882a593Smuzhiyun 		maxassoc = dtoh32(assoc_maclist->count);
4650*4882a593Smuzhiyun 		for (i=0; i<maxassoc; i++) {
4651*4882a593Smuzhiyun 			wl_sta_info_dump(cur_if->dev, &assoc_maclist->ea[i]);
4652*4882a593Smuzhiyun 		}
4653*4882a593Smuzhiyun #ifdef WLDWDS
4654*4882a593Smuzhiyun 		for (i=0; i<MAX_DWDS_IF_NUM; i++) {
4655*4882a593Smuzhiyun 			dwds_if = &apsta_params->dwds_info[i];
4656*4882a593Smuzhiyun 			if (dwds_if->dev && cur_if->bssidx == dwds_if->bssidx) {
4657*4882a593Smuzhiyun 				wl_tput_dump(apsta_params, dwds_if->dev, &dwds_if->tput_info);
4658*4882a593Smuzhiyun 			}
4659*4882a593Smuzhiyun 		}
4660*4882a593Smuzhiyun #endif /* WLDWDS */
4661*4882a593Smuzhiyun 	}
4662*4882a593Smuzhiyun 
4663*4882a593Smuzhiyun exit:
4664*4882a593Smuzhiyun 	return;
4665*4882a593Smuzhiyun }
4666*4882a593Smuzhiyun 
4667*4882a593Smuzhiyun static void
wl_tput_monitor(struct dhd_pub * dhd,int ifidx,struct wl_tput_info * tput_info)4668*4882a593Smuzhiyun wl_tput_monitor(struct dhd_pub *dhd, int ifidx, struct wl_tput_info *tput_info)
4669*4882a593Smuzhiyun {
4670*4882a593Smuzhiyun 	dhd_if_t *ifp = NULL;
4671*4882a593Smuzhiyun 
4672*4882a593Smuzhiyun 	ifp = dhd_get_ifp(dhd, ifidx);
4673*4882a593Smuzhiyun 	if (!ifp)
4674*4882a593Smuzhiyun 		return;
4675*4882a593Smuzhiyun 
4676*4882a593Smuzhiyun 	if (tput_info->tput_ts.tv_sec == 0 && tput_info->tput_ts.tv_nsec == 0) {
4677*4882a593Smuzhiyun 		osl_do_gettimeofday(&tput_info->tput_ts);
4678*4882a593Smuzhiyun 		tput_info->last_tx = ifp->stats.tx_bytes;
4679*4882a593Smuzhiyun 		tput_info->last_rx = ifp->stats.rx_bytes;
4680*4882a593Smuzhiyun 	} else {
4681*4882a593Smuzhiyun 		struct osl_timespec cur_ts;
4682*4882a593Smuzhiyun 		uint32 diff_ms;
4683*4882a593Smuzhiyun 
4684*4882a593Smuzhiyun 		osl_do_gettimeofday(&cur_ts);
4685*4882a593Smuzhiyun 		diff_ms = osl_do_gettimediff(&cur_ts, &tput_info->tput_ts)/1000;
4686*4882a593Smuzhiyun 		memcpy(&tput_info->tput_ts, &cur_ts, sizeof(struct osl_timespec));
4687*4882a593Smuzhiyun 		tput_info->tput_tx = (int32)(((ifp->stats.tx_bytes-tput_info->last_tx)/1024/1024)*8)*1000/diff_ms;
4688*4882a593Smuzhiyun 		if (tput_info->tput_tx == 0) {
4689*4882a593Smuzhiyun 			tput_info->tput_tx = (int32)((ifp->stats.tx_bytes-tput_info->last_tx)*8*1000/1024/1024)/diff_ms;
4690*4882a593Smuzhiyun 			tput_info->tput_tx_kb = (int32)((ifp->stats.tx_bytes-tput_info->last_tx)*8*1000/1024)/diff_ms;
4691*4882a593Smuzhiyun 			tput_info->tput_tx_kb = tput_info->tput_tx_kb % 1000;
4692*4882a593Smuzhiyun 		} else
4693*4882a593Smuzhiyun 			tput_info->tput_tx_kb = 0;
4694*4882a593Smuzhiyun 		tput_info->tput_rx = (int32)(((ifp->stats.rx_bytes-tput_info->last_rx)/1024/1024)*8)*1000/diff_ms;
4695*4882a593Smuzhiyun 		if (tput_info->tput_rx == 0) {
4696*4882a593Smuzhiyun 			tput_info->tput_rx = (int32)((ifp->stats.rx_bytes-tput_info->last_rx)*8*1000/1024/1024)/diff_ms;
4697*4882a593Smuzhiyun 			tput_info->tput_rx_kb = (int32)((ifp->stats.rx_bytes-tput_info->last_rx)*8*1000/1024)/diff_ms;
4698*4882a593Smuzhiyun 			tput_info->tput_rx_kb = tput_info->tput_rx_kb % 1000;
4699*4882a593Smuzhiyun 		} else
4700*4882a593Smuzhiyun 			tput_info->tput_rx_kb = 0;
4701*4882a593Smuzhiyun 		tput_info->last_tx = ifp->stats.tx_bytes;
4702*4882a593Smuzhiyun 		tput_info->last_rx = ifp->stats.rx_bytes;
4703*4882a593Smuzhiyun 	}
4704*4882a593Smuzhiyun }
4705*4882a593Smuzhiyun 
4706*4882a593Smuzhiyun static void
wl_tput_monitor_handler(struct wl_if_info * cur_if,const wl_event_msg_t * e,void * data)4707*4882a593Smuzhiyun wl_tput_monitor_handler(struct wl_if_info *cur_if,
4708*4882a593Smuzhiyun 	const wl_event_msg_t *e, void *data)
4709*4882a593Smuzhiyun {
4710*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
4711*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4712*4882a593Smuzhiyun 	wl_tput_info_t *tput_info;
4713*4882a593Smuzhiyun 	struct wl_if_info *tmp_if;
4714*4882a593Smuzhiyun #ifdef WLDWDS
4715*4882a593Smuzhiyun 	struct wl_dwds_info *dwds_if;
4716*4882a593Smuzhiyun #endif /* WLDWDS */
4717*4882a593Smuzhiyun 	uint32 etype = ntoh32(e->event_type);
4718*4882a593Smuzhiyun 	uint32 status =  ntoh32(e->status);
4719*4882a593Smuzhiyun 	uint32 reason = ntoh32(e->reason);
4720*4882a593Smuzhiyun 	uint16 flags =  ntoh16(e->flags);
4721*4882a593Smuzhiyun 	uint timeout = dhd->conf->tput_monitor_ms;
4722*4882a593Smuzhiyun 	int32 tput_sum = 0, tput_sum_kb = 0;
4723*4882a593Smuzhiyun 	bool monitor_if[MAX_IF_NUM] = {FALSE}, monitor = FALSE;
4724*4882a593Smuzhiyun 	int i;
4725*4882a593Smuzhiyun 
4726*4882a593Smuzhiyun 	if (etype == WLC_E_RESERVED && reason == ISAM_RC_TPUT_MONITOR) {
4727*4882a593Smuzhiyun 		tput_sum = 0;
4728*4882a593Smuzhiyun 		for (i=0; i<MAX_IF_NUM; i++) {
4729*4882a593Smuzhiyun 			tmp_if = &apsta_params->if_info[i];
4730*4882a593Smuzhiyun 			if (tmp_if->dev &&
4731*4882a593Smuzhiyun 					(tmp_if->ifmode == ISTA_MODE || tmp_if->ifmode == IGC_MODE) &&
4732*4882a593Smuzhiyun 					wl_ext_associated(tmp_if->dev)) {
4733*4882a593Smuzhiyun 				wl_tput_monitor(dhd, tmp_if->ifidx, &tmp_if->tput_info);
4734*4882a593Smuzhiyun 				monitor_if[i] = TRUE;
4735*4882a593Smuzhiyun 			}
4736*4882a593Smuzhiyun 			else if (tmp_if->dev &&
4737*4882a593Smuzhiyun 					(tmp_if->ifmode == IAP_MODE || tmp_if->ifmode == IGO_MODE) &&
4738*4882a593Smuzhiyun 					wl_ext_assoclist_num(tmp_if->dev)) {
4739*4882a593Smuzhiyun 				wl_tput_monitor(dhd, tmp_if->ifidx, &tmp_if->tput_info);
4740*4882a593Smuzhiyun 				monitor_if[i] = TRUE;
4741*4882a593Smuzhiyun 			}
4742*4882a593Smuzhiyun 			if (monitor_if[i] == TRUE) {
4743*4882a593Smuzhiyun 				tput_info = &tmp_if->tput_info;
4744*4882a593Smuzhiyun 				tput_sum += (tput_info->tput_tx + tput_info->tput_rx);
4745*4882a593Smuzhiyun 				tput_sum_kb += (tput_info->tput_tx_kb + tput_info->tput_rx_kb);
4746*4882a593Smuzhiyun 			}
4747*4882a593Smuzhiyun 		}
4748*4882a593Smuzhiyun #ifdef WLDWDS
4749*4882a593Smuzhiyun 		for (i=0; i<MAX_DWDS_IF_NUM; i++) {
4750*4882a593Smuzhiyun 			dwds_if = &apsta_params->dwds_info[i];
4751*4882a593Smuzhiyun 			if (dwds_if->dev) {
4752*4882a593Smuzhiyun 				wl_tput_monitor(dhd, dwds_if->ifidx, &dwds_if->tput_info);
4753*4882a593Smuzhiyun 				tput_info = &dwds_if->tput_info;
4754*4882a593Smuzhiyun 				tput_sum += (tput_info->tput_tx + tput_info->tput_rx);
4755*4882a593Smuzhiyun 				tput_sum_kb += (tput_info->tput_tx_kb + tput_info->tput_rx_kb);
4756*4882a593Smuzhiyun 			}
4757*4882a593Smuzhiyun 		}
4758*4882a593Smuzhiyun #endif /* WLDWDS */
4759*4882a593Smuzhiyun 		apsta_params->tput_sum = tput_sum + (tput_sum_kb/1000);
4760*4882a593Smuzhiyun 		apsta_params->tput_sum_kb = tput_sum_kb % 1000;
4761*4882a593Smuzhiyun 		for (i=0; i<MAX_IF_NUM; i++) {
4762*4882a593Smuzhiyun 			if (monitor_if[i]) {
4763*4882a593Smuzhiyun 				tmp_if = &apsta_params->if_info[i];
4764*4882a593Smuzhiyun 				wl_cur_if_tput_dump(apsta_params, tmp_if);
4765*4882a593Smuzhiyun 				monitor = TRUE;
4766*4882a593Smuzhiyun 			}
4767*4882a593Smuzhiyun 		}
4768*4882a593Smuzhiyun 		if (monitor) {
4769*4882a593Smuzhiyun 			wl_btc_dump(cur_if->dev);
4770*4882a593Smuzhiyun 			wl_tvpm_dump(cur_if->dev);
4771*4882a593Smuzhiyun 			wl_ampdu_dump(cur_if->dev);
4772*4882a593Smuzhiyun 			wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout);
4773*4882a593Smuzhiyun 		}
4774*4882a593Smuzhiyun #ifdef BCMSDIO
4775*4882a593Smuzhiyun 		if (apsta_params->tput_sum >= dhd->conf->doflow_tput_thresh && dhd_doflow) {
4776*4882a593Smuzhiyun 			dhd_doflow = FALSE;
4777*4882a593Smuzhiyun 			dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
4778*4882a593Smuzhiyun 			IAPSTA_INFO("wlan", "dhd_doflow=%d\n", dhd_doflow);
4779*4882a593Smuzhiyun 		}
4780*4882a593Smuzhiyun 		else if (apsta_params->tput_sum < dhd->conf->doflow_tput_thresh && !dhd_doflow) {
4781*4882a593Smuzhiyun 			dhd_doflow = TRUE;
4782*4882a593Smuzhiyun 			IAPSTA_INFO("wlan", "dhd_doflow=%d\n", dhd_doflow);
4783*4882a593Smuzhiyun 		}
4784*4882a593Smuzhiyun #endif
4785*4882a593Smuzhiyun 	}
4786*4882a593Smuzhiyun 	else if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) {
4787*4882a593Smuzhiyun 		if (etype == WLC_E_LINK) {
4788*4882a593Smuzhiyun 			if (flags & WLC_EVENT_MSG_LINK) {
4789*4882a593Smuzhiyun 				wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout);
4790*4882a593Smuzhiyun 			} else if (!wl_ext_iapsta_other_if_enabled(cur_if->dev)) {
4791*4882a593Smuzhiyun 				wl_timer_mod(dhd, &apsta_params->monitor_timer, 0);
4792*4882a593Smuzhiyun 			}
4793*4882a593Smuzhiyun 		}
4794*4882a593Smuzhiyun 	}
4795*4882a593Smuzhiyun 	else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IGO_MODE) {
4796*4882a593Smuzhiyun 		if ((etype == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
4797*4882a593Smuzhiyun 				(etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
4798*4882a593Smuzhiyun 				reason == WLC_E_REASON_INITIAL_ASSOC)) {
4799*4882a593Smuzhiyun 			wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout);
4800*4882a593Smuzhiyun 		} else if ((etype == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) ||
4801*4882a593Smuzhiyun 				(etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
4802*4882a593Smuzhiyun 				reason == WLC_E_REASON_DEAUTH)) {
4803*4882a593Smuzhiyun 			if (!wl_ext_iapsta_other_if_enabled(cur_if->dev)) {
4804*4882a593Smuzhiyun 				wl_timer_mod(dhd, &apsta_params->monitor_timer, 0);
4805*4882a593Smuzhiyun 			}
4806*4882a593Smuzhiyun 		} else if ((etype == WLC_E_ASSOC_IND || etype == WLC_E_REASSOC_IND) &&
4807*4882a593Smuzhiyun 				reason == DOT11_SC_SUCCESS) {
4808*4882a593Smuzhiyun 			wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout);
4809*4882a593Smuzhiyun 		}
4810*4882a593Smuzhiyun 	}
4811*4882a593Smuzhiyun }
4812*4882a593Smuzhiyun #endif /* TPUT_MONITOR */
4813*4882a593Smuzhiyun 
4814*4882a593Smuzhiyun #ifdef ACS_MONITOR
4815*4882a593Smuzhiyun static bool
wl_ext_max_prio_if(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)4816*4882a593Smuzhiyun wl_ext_max_prio_if(struct wl_apsta_params *apsta_params,
4817*4882a593Smuzhiyun 	struct wl_if_info *cur_if)
4818*4882a593Smuzhiyun {
4819*4882a593Smuzhiyun 	struct wl_if_info *tmp_if;
4820*4882a593Smuzhiyun 	wl_prio_t max_prio;
4821*4882a593Smuzhiyun 	int i;
4822*4882a593Smuzhiyun 
4823*4882a593Smuzhiyun 	if (apsta_params->vsdb) {
4824*4882a593Smuzhiyun 		goto exit;
4825*4882a593Smuzhiyun 	}
4826*4882a593Smuzhiyun 
4827*4882a593Smuzhiyun 	// find the max prio
4828*4882a593Smuzhiyun 	max_prio = cur_if->prio;
4829*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
4830*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
4831*4882a593Smuzhiyun 		if (cur_if != tmp_if && wl_get_isam_status(tmp_if, IF_READY) &&
4832*4882a593Smuzhiyun 				tmp_if->prio > max_prio) {
4833*4882a593Smuzhiyun 			if (wl_ext_associated(tmp_if->dev)) {
4834*4882a593Smuzhiyun 				return TRUE;
4835*4882a593Smuzhiyun 			}
4836*4882a593Smuzhiyun 		}
4837*4882a593Smuzhiyun 	}
4838*4882a593Smuzhiyun exit:
4839*4882a593Smuzhiyun 	return FALSE;
4840*4882a593Smuzhiyun }
4841*4882a593Smuzhiyun 
4842*4882a593Smuzhiyun static void
wl_ext_acs_scan(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)4843*4882a593Smuzhiyun wl_ext_acs_scan(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
4844*4882a593Smuzhiyun {
4845*4882a593Smuzhiyun 	if (apsta_params->acs & ACS_DRV_BIT) {
4846*4882a593Smuzhiyun 		if (wl_ext_associated(cur_if->dev)) {
4847*4882a593Smuzhiyun 			int ret, cur_scan_time;
4848*4882a593Smuzhiyun 			cur_if->escan->autochannel = 1;
4849*4882a593Smuzhiyun 			cur_scan_time = wl_ext_set_scan_time(cur_if->dev, 80,
4850*4882a593Smuzhiyun 				WLC_GET_SCAN_CHANNEL_TIME, WLC_SET_SCAN_CHANNEL_TIME);
4851*4882a593Smuzhiyun 			WL_MSG(cur_if->dev->name, "ACS_SCAN\n");
4852*4882a593Smuzhiyun 			wl_ext_drv_scan(cur_if->dev, WLC_BAND_AUTO, FALSE);
4853*4882a593Smuzhiyun 			if (cur_scan_time) {
4854*4882a593Smuzhiyun 				ret = wl_ext_ioctl(cur_if->dev, WLC_SET_SCAN_CHANNEL_TIME,
4855*4882a593Smuzhiyun 					&cur_scan_time, sizeof(cur_scan_time), 1);
4856*4882a593Smuzhiyun 			}
4857*4882a593Smuzhiyun 		}
4858*4882a593Smuzhiyun 	}
4859*4882a593Smuzhiyun }
4860*4882a593Smuzhiyun 
4861*4882a593Smuzhiyun static void
wl_ext_acs(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)4862*4882a593Smuzhiyun wl_ext_acs(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
4863*4882a593Smuzhiyun {
4864*4882a593Smuzhiyun 	struct wl_chan_info chan_info;
4865*4882a593Smuzhiyun 
4866*4882a593Smuzhiyun 	if (apsta_params->acs & ACS_DRV_BIT) {
4867*4882a593Smuzhiyun 		mutex_lock(&apsta_params->usr_sync);
4868*4882a593Smuzhiyun 		memset(&chan_info, 0, sizeof(struct wl_chan_info));
4869*4882a593Smuzhiyun 		wl_ext_get_chan(cur_if->dev, &chan_info);
4870*4882a593Smuzhiyun 		if (chan_info.chan) {
4871*4882a593Smuzhiyun 			if (chan_info.band == WLC_BAND_5G)
4872*4882a593Smuzhiyun 				cur_if->chan_info.chan = cur_if->escan->best_5g_ch;
4873*4882a593Smuzhiyun 			else
4874*4882a593Smuzhiyun 				cur_if->chan_info.chan = cur_if->escan->best_2g_ch;
4875*4882a593Smuzhiyun 			wl_ext_move_cur_channel(apsta_params, cur_if);
4876*4882a593Smuzhiyun 			if (!wl_ext_same_chan(&cur_if->chan_info, &chan_info)) {
4877*4882a593Smuzhiyun 				WL_MSG(cur_if->dev->name, "move channel %s-%d => %s-%d\n",
4878*4882a593Smuzhiyun 					WLCBAND2STR(chan_info.band), chan_info.chan,
4879*4882a593Smuzhiyun 					WLCBAND2STR(cur_if->chan_info.band), cur_if->chan_info.chan);
4880*4882a593Smuzhiyun 				wl_ext_if_down(apsta_params, cur_if);
4881*4882a593Smuzhiyun 				wl_ext_move_other_channel(apsta_params, cur_if);
4882*4882a593Smuzhiyun 				wl_ext_if_up(apsta_params, cur_if, FALSE, 500);
4883*4882a593Smuzhiyun 			}
4884*4882a593Smuzhiyun 		}
4885*4882a593Smuzhiyun 		mutex_unlock(&apsta_params->usr_sync);
4886*4882a593Smuzhiyun 	}
4887*4882a593Smuzhiyun }
4888*4882a593Smuzhiyun 
4889*4882a593Smuzhiyun static void
wl_acs_timer(unsigned long data)4890*4882a593Smuzhiyun wl_acs_timer(unsigned long data)
4891*4882a593Smuzhiyun {
4892*4882a593Smuzhiyun 	struct net_device *dev = (struct net_device *)data;
4893*4882a593Smuzhiyun 	struct dhd_pub *dhd;
4894*4882a593Smuzhiyun 	wl_event_msg_t msg;
4895*4882a593Smuzhiyun 
4896*4882a593Smuzhiyun 	if (!dev) {
4897*4882a593Smuzhiyun 		IAPSTA_ERROR("wlan", "dev is not ready\n");
4898*4882a593Smuzhiyun 		return;
4899*4882a593Smuzhiyun 	}
4900*4882a593Smuzhiyun 
4901*4882a593Smuzhiyun 	dhd = dhd_get_pub(dev);
4902*4882a593Smuzhiyun 
4903*4882a593Smuzhiyun 	bzero(&msg, sizeof(wl_event_msg_t));
4904*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "timer expired\n");
4905*4882a593Smuzhiyun 
4906*4882a593Smuzhiyun 	msg.ifidx = dhd_net2idx(dhd->info, dev);
4907*4882a593Smuzhiyun 	msg.event_type = hton32(WLC_E_RESERVED);
4908*4882a593Smuzhiyun 	msg.reason = hton32(ISAM_RC_AP_ACS);
4909*4882a593Smuzhiyun 	wl_ext_event_send(dhd->event_params, &msg, NULL);
4910*4882a593Smuzhiyun }
4911*4882a593Smuzhiyun 
4912*4882a593Smuzhiyun static void
wl_acs_handler(struct wl_if_info * cur_if,const wl_event_msg_t * e,void * data)4913*4882a593Smuzhiyun wl_acs_handler(struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data)
4914*4882a593Smuzhiyun {
4915*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
4916*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4917*4882a593Smuzhiyun 	uint acs_tmo = apsta_params->acs_tmo;
4918*4882a593Smuzhiyun 	uint32 etype = ntoh32(e->event_type);
4919*4882a593Smuzhiyun 	uint32 status = ntoh32(e->status);
4920*4882a593Smuzhiyun 	uint32 reason = ntoh32(e->reason);
4921*4882a593Smuzhiyun 
4922*4882a593Smuzhiyun 	if (wl_get_isam_status(cur_if, AP_CREATED)) {
4923*4882a593Smuzhiyun 		if ((etype == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
4924*4882a593Smuzhiyun 				(etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
4925*4882a593Smuzhiyun 				reason == WLC_E_REASON_INITIAL_ASSOC)) {
4926*4882a593Smuzhiyun 			// Link up
4927*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->acs_timer, acs_tmo*1000);
4928*4882a593Smuzhiyun 		}
4929*4882a593Smuzhiyun 		else if ((etype == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) ||
4930*4882a593Smuzhiyun 				(etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
4931*4882a593Smuzhiyun 				reason == WLC_E_REASON_DEAUTH)) {
4932*4882a593Smuzhiyun 			// Link down
4933*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->acs_timer, 0);
4934*4882a593Smuzhiyun 			cur_if->escan->autochannel = 0;
4935*4882a593Smuzhiyun 		}
4936*4882a593Smuzhiyun 		else if ((etype == WLC_E_ASSOC_IND || etype == WLC_E_REASSOC_IND) &&
4937*4882a593Smuzhiyun 				reason == DOT11_SC_SUCCESS) {
4938*4882a593Smuzhiyun 			// external STA connected
4939*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->acs_timer, 0);
4940*4882a593Smuzhiyun 		}
4941*4882a593Smuzhiyun 		else if (etype == WLC_E_DISASSOC_IND ||
4942*4882a593Smuzhiyun 				etype == WLC_E_DEAUTH_IND ||
4943*4882a593Smuzhiyun 				(etype == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) {
4944*4882a593Smuzhiyun 			// external STA disconnected
4945*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->acs_timer, acs_tmo*1000);
4946*4882a593Smuzhiyun 		}
4947*4882a593Smuzhiyun 		else if (etype == WLC_E_RESERVED && reason == ISAM_RC_AP_ACS) {
4948*4882a593Smuzhiyun 			// acs_tmo expired
4949*4882a593Smuzhiyun 			if (!wl_ext_assoclist_num(cur_if->dev) &&
4950*4882a593Smuzhiyun 					!wl_ext_max_prio_if(apsta_params, cur_if)) {
4951*4882a593Smuzhiyun 				wl_ext_acs_scan(apsta_params, cur_if);
4952*4882a593Smuzhiyun 				wl_timer_mod(dhd, &cur_if->acs_timer, acs_tmo*1000);
4953*4882a593Smuzhiyun 			} else {
4954*4882a593Smuzhiyun 				wl_timer_mod(dhd, &cur_if->acs_timer, 0);
4955*4882a593Smuzhiyun 			}
4956*4882a593Smuzhiyun 		}
4957*4882a593Smuzhiyun 		else if (((etype == WLC_E_ESCAN_RESULT && status == WLC_E_STATUS_SUCCESS) ||
4958*4882a593Smuzhiyun 				(etype == WLC_E_ESCAN_RESULT &&
4959*4882a593Smuzhiyun 				(status == WLC_E_STATUS_ABORT || status == WLC_E_STATUS_NEWSCAN ||
4960*4882a593Smuzhiyun 				status == WLC_E_STATUS_11HQUIET || status == WLC_E_STATUS_CS_ABORT ||
4961*4882a593Smuzhiyun 				status == WLC_E_STATUS_NEWASSOC || status == WLC_E_STATUS_TIMEOUT)))) {
4962*4882a593Smuzhiyun 			// scan complete
4963*4882a593Smuzhiyun 			cur_if->escan->autochannel = 0;
4964*4882a593Smuzhiyun 			if (!wl_ext_assoclist_num(cur_if->dev) &&
4965*4882a593Smuzhiyun 					!wl_ext_max_prio_if(apsta_params, cur_if)) {
4966*4882a593Smuzhiyun 				wl_ext_acs(apsta_params, cur_if);
4967*4882a593Smuzhiyun 			} else {
4968*4882a593Smuzhiyun 				wl_timer_mod(dhd, &cur_if->acs_timer, 0);
4969*4882a593Smuzhiyun 			}
4970*4882a593Smuzhiyun 		}
4971*4882a593Smuzhiyun 	}
4972*4882a593Smuzhiyun }
4973*4882a593Smuzhiyun 
4974*4882a593Smuzhiyun static void
wl_acs_detach(struct wl_if_info * cur_if)4975*4882a593Smuzhiyun wl_acs_detach(struct wl_if_info *cur_if)
4976*4882a593Smuzhiyun {
4977*4882a593Smuzhiyun 	IAPSTA_TRACE(cur_if->dev->name, "Enter\n");
4978*4882a593Smuzhiyun 	wl_timer_deregister(cur_if->dev, &cur_if->acs_timer);
4979*4882a593Smuzhiyun 	if (cur_if->escan) {
4980*4882a593Smuzhiyun 		cur_if->escan = NULL;
4981*4882a593Smuzhiyun 	}
4982*4882a593Smuzhiyun }
4983*4882a593Smuzhiyun 
4984*4882a593Smuzhiyun static void
wl_acs_attach(dhd_pub_t * dhd,struct wl_if_info * cur_if)4985*4882a593Smuzhiyun wl_acs_attach(dhd_pub_t *dhd, struct wl_if_info *cur_if)
4986*4882a593Smuzhiyun {
4987*4882a593Smuzhiyun 	IAPSTA_TRACE(cur_if->dev->name, "Enter\n");
4988*4882a593Smuzhiyun 	cur_if->escan = dhd->escan;
4989*4882a593Smuzhiyun 	wl_timer_register(cur_if->dev, &cur_if->acs_timer, wl_acs_timer);
4990*4882a593Smuzhiyun }
4991*4882a593Smuzhiyun #endif /* ACS_MONITOR */
4992*4882a593Smuzhiyun 
4993*4882a593Smuzhiyun #ifdef RESTART_AP_WAR
4994*4882a593Smuzhiyun static void
wl_ext_restart_ap_timeout(unsigned long data)4995*4882a593Smuzhiyun wl_ext_restart_ap_timeout(unsigned long data)
4996*4882a593Smuzhiyun {
4997*4882a593Smuzhiyun 	struct net_device *dev = (struct net_device *)data;
4998*4882a593Smuzhiyun 	struct dhd_pub *dhd;
4999*4882a593Smuzhiyun 	wl_event_msg_t msg;
5000*4882a593Smuzhiyun 
5001*4882a593Smuzhiyun 	if (!dev) {
5002*4882a593Smuzhiyun 		IAPSTA_ERROR("wlan", "dev is not ready\n");
5003*4882a593Smuzhiyun 		return;
5004*4882a593Smuzhiyun 	}
5005*4882a593Smuzhiyun 
5006*4882a593Smuzhiyun 	dhd = dhd_get_pub(dev);
5007*4882a593Smuzhiyun 
5008*4882a593Smuzhiyun 	bzero(&msg, sizeof(wl_event_msg_t));
5009*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "timer expired\n");
5010*4882a593Smuzhiyun 
5011*4882a593Smuzhiyun 	msg.ifidx = dhd_net2idx(dhd->info, dev);
5012*4882a593Smuzhiyun 	msg.event_type = hton32(WLC_E_RESERVED);
5013*4882a593Smuzhiyun 	msg.reason = hton32(ISAM_RC_AP_RESTART);
5014*4882a593Smuzhiyun 	wl_ext_event_send(dhd->event_params, &msg, NULL);
5015*4882a593Smuzhiyun }
5016*4882a593Smuzhiyun 
5017*4882a593Smuzhiyun static void
wl_ext_restart_ap_handler(struct wl_if_info * cur_if,const wl_event_msg_t * e,void * data)5018*4882a593Smuzhiyun wl_ext_restart_ap_handler(struct wl_if_info *cur_if,
5019*4882a593Smuzhiyun 	const wl_event_msg_t *e, void *data)
5020*4882a593Smuzhiyun {
5021*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
5022*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5023*4882a593Smuzhiyun 	uint32 etype = ntoh32(e->event_type);
5024*4882a593Smuzhiyun 	uint32 reason = ntoh32(e->reason);
5025*4882a593Smuzhiyun 
5026*4882a593Smuzhiyun 	if (etype == WLC_E_RESERVED && reason == ISAM_RC_AP_RESTART) {
5027*4882a593Smuzhiyun 		if (!wl_get_isam_status(cur_if, AP_CREATED)) {
5028*4882a593Smuzhiyun 			if (!wl_ext_associated(cur_if->dev)) {
5029*4882a593Smuzhiyun 				WL_MSG(cur_if->ifname, "restart AP\n");
5030*4882a593Smuzhiyun 				wl_ext_if_down(apsta_params, cur_if);
5031*4882a593Smuzhiyun 				wl_ext_if_up(apsta_params, cur_if, FALSE, 1);
5032*4882a593Smuzhiyun 				wl_timer_mod(dhd, &cur_if->restart_ap_timer, AP_RESTART_TIMEOUT);
5033*4882a593Smuzhiyun 			} else {
5034*4882a593Smuzhiyun 				WL_MSG(cur_if->ifname, "skip restart AP\n");
5035*4882a593Smuzhiyun 			}
5036*4882a593Smuzhiyun 		}
5037*4882a593Smuzhiyun 	}
5038*4882a593Smuzhiyun 	return;
5039*4882a593Smuzhiyun }
5040*4882a593Smuzhiyun #endif /* RESTART_AP_WAR */
5041*4882a593Smuzhiyun 
5042*4882a593Smuzhiyun #if defined(RESET_AP_WAR) || defined(RXF0OVFL_REINIT_WAR)
5043*4882a593Smuzhiyun static int
wl_ext_counters_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)5044*4882a593Smuzhiyun wl_ext_counters_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
5045*4882a593Smuzhiyun {
5046*4882a593Smuzhiyun 	struct wl_if_info *cur_if = ctx;
5047*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
5048*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5049*4882a593Smuzhiyun 	int res = BCME_OK;
5050*4882a593Smuzhiyun 
5051*4882a593Smuzhiyun 	switch (type) {
5052*4882a593Smuzhiyun 		case WL_CNT_XTLV_CNTV_LE10_UCODE: {
5053*4882a593Smuzhiyun 			wl_cnt_v_le10_mcst_t *cnt = (wl_cnt_v_le10_mcst_t *)data;
5054*4882a593Smuzhiyun 			if (len != sizeof(wl_cnt_v_le10_mcst_t)) {
5055*4882a593Smuzhiyun 				printf("type %d: cnt struct length mismatch! %d != %d\n",
5056*4882a593Smuzhiyun 					type, len, (int)sizeof(wl_cnt_v_le10_mcst_t));
5057*4882a593Smuzhiyun 			}
5058*4882a593Smuzhiyun #ifdef RESET_AP_WAR
5059*4882a593Smuzhiyun 			if (apsta_params->war_reason == ISAM_RC_AP_RESET)
5060*4882a593Smuzhiyun 				cur_if->txbcnfrm = dtoh32(cnt->txbcnfrm);
5061*4882a593Smuzhiyun #endif /* RESET_AP_WAR */
5062*4882a593Smuzhiyun #ifdef RXF0OVFL_REINIT_WAR
5063*4882a593Smuzhiyun 			if (apsta_params->war_reason == ISAM_RC_RXF0OVFL_REINIT) {
5064*4882a593Smuzhiyun 				apsta_params->rxbeaconmbss = dtoh32(cnt->rxbeaconmbss);
5065*4882a593Smuzhiyun 				apsta_params->rxf0ovfl = dtoh32(cnt->rxf0ovfl);
5066*4882a593Smuzhiyun 			}
5067*4882a593Smuzhiyun #endif /* RXF0OVFL_REINIT_WAR */
5068*4882a593Smuzhiyun 			break;
5069*4882a593Smuzhiyun 		}
5070*4882a593Smuzhiyun 		case WL_CNT_XTLV_GE40_UCODE_V1:
5071*4882a593Smuzhiyun 		{
5072*4882a593Smuzhiyun 			wl_cnt_ge40mcst_v1_t *cnt = (wl_cnt_ge40mcst_v1_t *)data;
5073*4882a593Smuzhiyun 			if (len != sizeof(wl_cnt_ge40mcst_v1_t)) {
5074*4882a593Smuzhiyun 				IAPSTA_ERROR(cur_if->ifname,
5075*4882a593Smuzhiyun 					"type 0x%x, cnt struct length mismatch! %d != %d\n",
5076*4882a593Smuzhiyun 					type, len, (int)sizeof(wl_cnt_ge40mcst_v1_t));
5077*4882a593Smuzhiyun 			}
5078*4882a593Smuzhiyun #ifdef RESET_AP_WAR
5079*4882a593Smuzhiyun 			if (apsta_params->war_reason == ISAM_RC_AP_RESET)
5080*4882a593Smuzhiyun 				cur_if->txbcnfrm = dtoh32(cnt->txbcnfrm);
5081*4882a593Smuzhiyun #endif /* RESET_AP_WAR */
5082*4882a593Smuzhiyun #ifdef RXF0OVFL_REINIT_WAR
5083*4882a593Smuzhiyun 			if (apsta_params->war_reason == ISAM_RC_RXF0OVFL_REINIT) {
5084*4882a593Smuzhiyun 				apsta_params->rxbeaconmbss = dtoh32(cnt->rxbeaconmbss);
5085*4882a593Smuzhiyun 				apsta_params->rxf0ovfl = dtoh32(cnt->rxf0ovfl);
5086*4882a593Smuzhiyun 			}
5087*4882a593Smuzhiyun #endif /* RXF0OVFL_REINIT_WAR */
5088*4882a593Smuzhiyun 			break;
5089*4882a593Smuzhiyun 		}
5090*4882a593Smuzhiyun 		case WL_CNT_XTLV_GE80_UCODE_V1:
5091*4882a593Smuzhiyun 		{
5092*4882a593Smuzhiyun 			wl_cnt_ge80mcst_v1_t *cnt = (wl_cnt_ge80mcst_v1_t *)data;
5093*4882a593Smuzhiyun 			if (len != sizeof(wl_cnt_ge80mcst_v1_t)) {
5094*4882a593Smuzhiyun 				IAPSTA_ERROR(cur_if->ifname,
5095*4882a593Smuzhiyun 					"type 0x%x, cnt struct length mismatch! %d != %d\n",
5096*4882a593Smuzhiyun 					type, len, (int)sizeof(wl_cnt_ge80mcst_v1_t));
5097*4882a593Smuzhiyun 			}
5098*4882a593Smuzhiyun #ifdef RESET_AP_WAR
5099*4882a593Smuzhiyun 			if (apsta_params->war_reason == ISAM_RC_AP_RESET)
5100*4882a593Smuzhiyun 				cur_if->txbcnfrm = dtoh32(cnt->txbcnfrm);
5101*4882a593Smuzhiyun #endif /* RESET_AP_WAR */
5102*4882a593Smuzhiyun #ifdef RXF0OVFL_REINIT_WAR
5103*4882a593Smuzhiyun 			if (apsta_params->war_reason == ISAM_RC_RXF0OVFL_REINIT) {
5104*4882a593Smuzhiyun 				apsta_params->rxbeaconmbss = dtoh32(cnt->rxbeaconmbss);
5105*4882a593Smuzhiyun 				apsta_params->rxf0ovfl = dtoh32(cnt->rxf0ovfl);
5106*4882a593Smuzhiyun 			}
5107*4882a593Smuzhiyun #endif /* RXF0OVFL_REINIT_WAR */
5108*4882a593Smuzhiyun 			break;
5109*4882a593Smuzhiyun 		}
5110*4882a593Smuzhiyun 		default:
5111*4882a593Smuzhiyun 			break;
5112*4882a593Smuzhiyun 	}
5113*4882a593Smuzhiyun 	return res;
5114*4882a593Smuzhiyun }
5115*4882a593Smuzhiyun 
5116*4882a593Smuzhiyun static int
wl_ext_counters_update(struct wl_if_info * cur_if,int war_reason)5117*4882a593Smuzhiyun wl_ext_counters_update(struct wl_if_info *cur_if, int war_reason)
5118*4882a593Smuzhiyun {
5119*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
5120*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5121*4882a593Smuzhiyun 	char *iovar_buf = apsta_params->ioctl_buf;
5122*4882a593Smuzhiyun 	uint32 corerev = 0;
5123*4882a593Smuzhiyun 	wl_cnt_info_t *cntinfo;
5124*4882a593Smuzhiyun 	uint16 ver;
5125*4882a593Smuzhiyun 	int ret = 0;
5126*4882a593Smuzhiyun 
5127*4882a593Smuzhiyun 	ret = wldev_iovar_getbuf(cur_if->dev, "counters", NULL, 0,
5128*4882a593Smuzhiyun 		iovar_buf, WLC_IOCTL_MEDLEN, NULL);
5129*4882a593Smuzhiyun 	if (unlikely(ret)) {
5130*4882a593Smuzhiyun 		IAPSTA_ERROR(cur_if->ifname,
5131*4882a593Smuzhiyun 			"counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t));
5132*4882a593Smuzhiyun 		goto exit;
5133*4882a593Smuzhiyun 	}
5134*4882a593Smuzhiyun 	cntinfo = (wl_cnt_info_t *)iovar_buf;
5135*4882a593Smuzhiyun 	cntinfo->version = dtoh16(cntinfo->version);
5136*4882a593Smuzhiyun 	cntinfo->datalen = dtoh16(cntinfo->datalen);
5137*4882a593Smuzhiyun 	ver = cntinfo->version;
5138*4882a593Smuzhiyun 	CHK_CNTBUF_DATALEN(iovar_buf, WLC_IOCTL_MEDLEN);
5139*4882a593Smuzhiyun 	if (ver > WL_CNT_VERSION_XTLV) {
5140*4882a593Smuzhiyun 		IAPSTA_ERROR(cur_if->ifname,
5141*4882a593Smuzhiyun 			"Incorrect version of counters struct: expected %d; got %d\n",
5142*4882a593Smuzhiyun 			WL_CNT_VERSION_XTLV, ver);
5143*4882a593Smuzhiyun 		goto exit;
5144*4882a593Smuzhiyun 	}
5145*4882a593Smuzhiyun 
5146*4882a593Smuzhiyun 	if (ver == WL_CNT_VERSION_11) {
5147*4882a593Smuzhiyun 		wlc_rev_info_t revinfo;
5148*4882a593Smuzhiyun 		memset(&revinfo, 0, sizeof(revinfo));
5149*4882a593Smuzhiyun 		ret = wl_ext_ioctl(cur_if->dev, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), 0);
5150*4882a593Smuzhiyun 		if (ret) {
5151*4882a593Smuzhiyun 			IAPSTA_ERROR(cur_if->ifname, "WLC_GET_REVINFO failed %d\n", ret);
5152*4882a593Smuzhiyun 			goto exit;
5153*4882a593Smuzhiyun 		}
5154*4882a593Smuzhiyun 		corerev = dtoh32(revinfo.corerev);
5155*4882a593Smuzhiyun 	}
5156*4882a593Smuzhiyun 	ret = wl_cntbuf_to_xtlv_format(NULL, cntinfo, WLC_IOCTL_MEDLEN, corerev);
5157*4882a593Smuzhiyun 	if (ret) {
5158*4882a593Smuzhiyun 		IAPSTA_ERROR(cur_if->ifname, "wl_cntbuf_to_xtlv_format failed %d\n", ret);
5159*4882a593Smuzhiyun 		goto exit;
5160*4882a593Smuzhiyun 	}
5161*4882a593Smuzhiyun 
5162*4882a593Smuzhiyun 	apsta_params->war_reason = war_reason;
5163*4882a593Smuzhiyun 	if ((ret = bcm_unpack_xtlv_buf(cur_if, cntinfo->data, cntinfo->datalen,
5164*4882a593Smuzhiyun 			BCM_XTLV_OPTION_ALIGN32, wl_ext_counters_cbfn))) {
5165*4882a593Smuzhiyun 		IAPSTA_ERROR(cur_if->ifname, "bcm_unpack_xtlv_buf failed %d\n", ret);
5166*4882a593Smuzhiyun 		goto exit;
5167*4882a593Smuzhiyun 	}
5168*4882a593Smuzhiyun 
5169*4882a593Smuzhiyun exit:
5170*4882a593Smuzhiyun 	return ret;
5171*4882a593Smuzhiyun }
5172*4882a593Smuzhiyun #endif /* RESET_AP_WAR | RXF0OVFL_REINIT_WAR */
5173*4882a593Smuzhiyun 
5174*4882a593Smuzhiyun #ifdef RESET_AP_WAR
5175*4882a593Smuzhiyun static void
wl_ext_reset_ap_timeout(unsigned long data)5176*4882a593Smuzhiyun wl_ext_reset_ap_timeout(unsigned long data)
5177*4882a593Smuzhiyun {
5178*4882a593Smuzhiyun 	struct net_device *dev = (struct net_device *)data;
5179*4882a593Smuzhiyun 	struct dhd_pub *dhd;
5180*4882a593Smuzhiyun 	wl_event_msg_t msg;
5181*4882a593Smuzhiyun 
5182*4882a593Smuzhiyun 	if (!dev) {
5183*4882a593Smuzhiyun 		IAPSTA_ERROR("wlan", "dev is not ready\n");
5184*4882a593Smuzhiyun 		return;
5185*4882a593Smuzhiyun 	}
5186*4882a593Smuzhiyun 
5187*4882a593Smuzhiyun 	dhd = dhd_get_pub(dev);
5188*4882a593Smuzhiyun 
5189*4882a593Smuzhiyun 	bzero(&msg, sizeof(wl_event_msg_t));
5190*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "timer expired\n");
5191*4882a593Smuzhiyun 
5192*4882a593Smuzhiyun 	msg.ifidx = dhd_net2idx(dhd->info, dev);
5193*4882a593Smuzhiyun 	msg.event_type = hton32(WLC_E_RESERVED);
5194*4882a593Smuzhiyun 	msg.reason = hton32(ISAM_RC_AP_RESET);
5195*4882a593Smuzhiyun 	wl_ext_event_send(dhd->event_params, &msg, NULL);
5196*4882a593Smuzhiyun }
5197*4882a593Smuzhiyun 
5198*4882a593Smuzhiyun static void
wl_ext_reset_ap_handler(struct wl_if_info * cur_if,const wl_event_msg_t * e,void * data)5199*4882a593Smuzhiyun wl_ext_reset_ap_handler(struct wl_if_info *cur_if,
5200*4882a593Smuzhiyun 	const wl_event_msg_t *e, void *data)
5201*4882a593Smuzhiyun {
5202*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
5203*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5204*4882a593Smuzhiyun 	uint32 etype = ntoh32(e->event_type);
5205*4882a593Smuzhiyun 	uint32 status = ntoh32(e->status);
5206*4882a593Smuzhiyun 	uint32 reason = ntoh32(e->reason);
5207*4882a593Smuzhiyun 	uint32 txbcnfrm;
5208*4882a593Smuzhiyun 	int ret = 0;
5209*4882a593Smuzhiyun 
5210*4882a593Smuzhiyun 	if (wl_get_isam_status(cur_if, AP_CREATED)) {
5211*4882a593Smuzhiyun 		if ((etype == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
5212*4882a593Smuzhiyun 				(etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
5213*4882a593Smuzhiyun 				reason == WLC_E_REASON_INITIAL_ASSOC)) {
5214*4882a593Smuzhiyun 			// Link up
5215*4882a593Smuzhiyun 			wl_ext_counters_update(cur_if, ISAM_RC_AP_RESET);
5216*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->reset_ap_timer, AP_TXBCNFRM_TIMEOUT);
5217*4882a593Smuzhiyun 		}
5218*4882a593Smuzhiyun 		else if (etype == WLC_E_RESERVED && reason == ISAM_RC_AP_RESET) {
5219*4882a593Smuzhiyun 			txbcnfrm = cur_if->txbcnfrm;
5220*4882a593Smuzhiyun 			ret = wl_ext_counters_update(cur_if, ISAM_RC_AP_RESET);
5221*4882a593Smuzhiyun 			if (ret)
5222*4882a593Smuzhiyun 				goto done;
5223*4882a593Smuzhiyun 			if ((cur_if->txbcnfrm != 0) && (txbcnfrm == cur_if->txbcnfrm)) {
5224*4882a593Smuzhiyun 				WL_MSG(cur_if->ifname, "reset AP mode\n");
5225*4882a593Smuzhiyun 				wl_ext_if_down(apsta_params, cur_if);
5226*4882a593Smuzhiyun 				wl_ext_if_up(apsta_params, cur_if, FALSE, 500);
5227*4882a593Smuzhiyun 			}
5228*4882a593Smuzhiyun done:
5229*4882a593Smuzhiyun 			wl_timer_mod(dhd, &cur_if->reset_ap_timer, AP_TXBCNFRM_TIMEOUT);
5230*4882a593Smuzhiyun 		}
5231*4882a593Smuzhiyun 	}
5232*4882a593Smuzhiyun 	return;
5233*4882a593Smuzhiyun }
5234*4882a593Smuzhiyun #endif /* RESET_AP_WAR */
5235*4882a593Smuzhiyun 
5236*4882a593Smuzhiyun #ifdef RXF0OVFL_REINIT_WAR
5237*4882a593Smuzhiyun static void
wl_ext_rxf0ovfl_reinit_timeout(unsigned long data)5238*4882a593Smuzhiyun wl_ext_rxf0ovfl_reinit_timeout(unsigned long data)
5239*4882a593Smuzhiyun {
5240*4882a593Smuzhiyun 	struct net_device *dev = (struct net_device *)data;
5241*4882a593Smuzhiyun 	struct dhd_pub *dhd;
5242*4882a593Smuzhiyun 	wl_event_msg_t msg;
5243*4882a593Smuzhiyun 
5244*4882a593Smuzhiyun 	if (!dev) {
5245*4882a593Smuzhiyun 		IAPSTA_ERROR("wlan", "dev is not ready\n");
5246*4882a593Smuzhiyun 		return;
5247*4882a593Smuzhiyun 	}
5248*4882a593Smuzhiyun 
5249*4882a593Smuzhiyun 	dhd = dhd_get_pub(dev);
5250*4882a593Smuzhiyun 
5251*4882a593Smuzhiyun 	bzero(&msg, sizeof(wl_event_msg_t));
5252*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "timer expired\n");
5253*4882a593Smuzhiyun 
5254*4882a593Smuzhiyun 	msg.ifidx = dhd_net2idx(dhd->info, dev);
5255*4882a593Smuzhiyun 	msg.event_type = hton32(WLC_E_RESERVED);
5256*4882a593Smuzhiyun 	msg.reason = hton32(ISAM_RC_RXF0OVFL_REINIT);
5257*4882a593Smuzhiyun 	wl_ext_event_send(dhd->event_params, &msg, NULL);
5258*4882a593Smuzhiyun }
5259*4882a593Smuzhiyun 
5260*4882a593Smuzhiyun static void
wl_ext_rxf0ovfl_reinit_handler(struct wl_if_info * cur_if,const wl_event_msg_t * e,void * data)5261*4882a593Smuzhiyun wl_ext_rxf0ovfl_reinit_handler(struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data)
5262*4882a593Smuzhiyun {
5263*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
5264*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5265*4882a593Smuzhiyun 	uint32 etype = ntoh32(e->event_type);
5266*4882a593Smuzhiyun 	uint32 reason = ntoh32(e->reason);
5267*4882a593Smuzhiyun 	uint32 status = ntoh32(e->status);
5268*4882a593Smuzhiyun 	uint16 flags =  ntoh16(e->flags);
5269*4882a593Smuzhiyun 	uint32 rxbeaconmbss, rxbeaconmbss_diff = 0, rxf0ovfl, rxf0ovfl_diff = 0;
5270*4882a593Smuzhiyun 	int ret = 0;
5271*4882a593Smuzhiyun 	bool reinit = FALSE;
5272*4882a593Smuzhiyun 
5273*4882a593Smuzhiyun 	if ((cur_if->ifmode == ISTA_MODE) &&
5274*4882a593Smuzhiyun 			(etype == WLC_E_LINK) && (flags & WLC_EVENT_MSG_LINK)) {
5275*4882a593Smuzhiyun 		// Link up
5276*4882a593Smuzhiyun 		wl_ext_counters_update(cur_if, ISAM_RC_RXF0OVFL_REINIT);
5277*4882a593Smuzhiyun 		wl_timer_mod(dhd, &apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT);
5278*4882a593Smuzhiyun 	}
5279*4882a593Smuzhiyun 	else if ((cur_if->ifmode == IAP_MODE) &&
5280*4882a593Smuzhiyun 			((etype == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
5281*4882a593Smuzhiyun 			(etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
5282*4882a593Smuzhiyun 			reason == WLC_E_REASON_INITIAL_ASSOC))) {
5283*4882a593Smuzhiyun 		// Link up
5284*4882a593Smuzhiyun 		wl_ext_counters_update(cur_if, ISAM_RC_RXF0OVFL_REINIT);
5285*4882a593Smuzhiyun 		wl_timer_mod(dhd, &apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT);
5286*4882a593Smuzhiyun 	}
5287*4882a593Smuzhiyun 	else if ((etype == WLC_E_RESERVED) && (reason == ISAM_RC_RXF0OVFL_REINIT) &&
5288*4882a593Smuzhiyun 			(wl_ext_iapsta_other_if_enabled(cur_if->dev))) {
5289*4882a593Smuzhiyun 		rxbeaconmbss = apsta_params->rxbeaconmbss;
5290*4882a593Smuzhiyun 		rxf0ovfl = apsta_params->rxf0ovfl;
5291*4882a593Smuzhiyun 		wl_ext_counters_update(cur_if, ISAM_RC_RXF0OVFL_REINIT);
5292*4882a593Smuzhiyun 		if (ret)
5293*4882a593Smuzhiyun 			goto done;
5294*4882a593Smuzhiyun 		rxf0ovfl_diff = apsta_params->rxf0ovfl - rxf0ovfl;
5295*4882a593Smuzhiyun 		rxbeaconmbss_diff = apsta_params->rxbeaconmbss - rxbeaconmbss;
5296*4882a593Smuzhiyun 		if (rxf0ovfl_diff > 0) {
5297*4882a593Smuzhiyun 			IAPSTA_INFO(cur_if->ifname,
5298*4882a593Smuzhiyun 				"rxf0ovfl diff = %d, rxbeaconmbss diff = %d\n",
5299*4882a593Smuzhiyun 				rxf0ovfl_diff, rxbeaconmbss_diff);
5300*4882a593Smuzhiyun 		}
5301*4882a593Smuzhiyun 		if (wl_ext_if_enabled(apsta_params, ISTA_MODE)) {
5302*4882a593Smuzhiyun 			if (rxbeaconmbss_diff < 5 && rxf0ovfl_diff > RXF0OVFL_THRESHOLD)
5303*4882a593Smuzhiyun 				reinit = TRUE;
5304*4882a593Smuzhiyun 		}
5305*4882a593Smuzhiyun 		else if (wl_ext_if_enabled(apsta_params, IAP_MODE)) {
5306*4882a593Smuzhiyun 			if (rxf0ovfl_diff > RXF0OVFL_THRESHOLD)
5307*4882a593Smuzhiyun 				reinit = TRUE;
5308*4882a593Smuzhiyun 		}
5309*4882a593Smuzhiyun 		if (reinit) {
5310*4882a593Smuzhiyun 			WL_MSG(cur_if->ifname, "wl reinit\n");
5311*4882a593Smuzhiyun 			wl_ext_ioctl(cur_if->dev, WLC_INIT, NULL, 0, 1);
5312*4882a593Smuzhiyun 		}
5313*4882a593Smuzhiyun done:
5314*4882a593Smuzhiyun 		wl_timer_mod(dhd, &apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT);
5315*4882a593Smuzhiyun 	}
5316*4882a593Smuzhiyun 
5317*4882a593Smuzhiyun 	return;
5318*4882a593Smuzhiyun }
5319*4882a593Smuzhiyun #endif /* RXF0OVFL_REINIT_WAR */
5320*4882a593Smuzhiyun 
5321*4882a593Smuzhiyun void
wl_ext_iapsta_link(struct wl_if_info * cur_if,const wl_event_msg_t * e,void * data)5322*4882a593Smuzhiyun wl_ext_iapsta_link(struct wl_if_info *cur_if,
5323*4882a593Smuzhiyun 	const wl_event_msg_t *e, void *data)
5324*4882a593Smuzhiyun {
5325*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
5326*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5327*4882a593Smuzhiyun 	uint32 event_type = ntoh32(e->event_type);
5328*4882a593Smuzhiyun 	uint32 status =  ntoh32(e->status);
5329*4882a593Smuzhiyun 	uint32 reason =  ntoh32(e->reason);
5330*4882a593Smuzhiyun 	uint16 flags =  ntoh16(e->flags);
5331*4882a593Smuzhiyun 
5332*4882a593Smuzhiyun 	if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) {
5333*4882a593Smuzhiyun 		if (event_type == WLC_E_LINK) {
5334*4882a593Smuzhiyun 			if (!(flags & WLC_EVENT_MSG_LINK)) {
5335*4882a593Smuzhiyun 				WL_MSG(cur_if->ifname,
5336*4882a593Smuzhiyun 					"[%c] Link down with %pM, %s(%d), reason %d\n",
5337*4882a593Smuzhiyun 					cur_if->prefix, &e->addr, bcmevent_get_name(event_type),
5338*4882a593Smuzhiyun 					event_type, reason);
5339*4882a593Smuzhiyun #ifdef SET_CARRIER
5340*4882a593Smuzhiyun 				wl_ext_net_setcarrier(cur_if, FALSE, FALSE);
5341*4882a593Smuzhiyun #endif /* SET_CARRIER */
5342*4882a593Smuzhiyun 				wl_clr_isam_status(cur_if, STA_CONNECTED);
5343*4882a593Smuzhiyun 			} else {
5344*4882a593Smuzhiyun 				WL_MSG(cur_if->ifname, "[%c] Link UP with %pM\n",
5345*4882a593Smuzhiyun 					cur_if->prefix, &e->addr);
5346*4882a593Smuzhiyun #ifdef SET_CARRIER
5347*4882a593Smuzhiyun 				wl_ext_net_setcarrier(cur_if, TRUE, FALSE);
5348*4882a593Smuzhiyun #endif /* SET_CARRIER */
5349*4882a593Smuzhiyun 				wl_set_isam_status(cur_if, STA_CONNECTED);
5350*4882a593Smuzhiyun 			}
5351*4882a593Smuzhiyun 			wl_clr_isam_status(cur_if, STA_CONNECTING);
5352*4882a593Smuzhiyun 			wake_up_interruptible(&apsta_params->netif_change_event);
5353*4882a593Smuzhiyun #ifdef PROPTX_MAXCOUNT
5354*4882a593Smuzhiyun 			wl_ext_update_wlfc_maxcount(dhd);
5355*4882a593Smuzhiyun #endif /* PROPTX_MAXCOUNT */
5356*4882a593Smuzhiyun 		}
5357*4882a593Smuzhiyun 		else if (event_type == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) {
5358*4882a593Smuzhiyun 			WL_MSG(cur_if->ifname,
5359*4882a593Smuzhiyun 				"connect failed event=%d, reason=%d, status=%d\n",
5360*4882a593Smuzhiyun 				event_type, reason, status);
5361*4882a593Smuzhiyun 			wl_clr_isam_status(cur_if, STA_CONNECTING);
5362*4882a593Smuzhiyun 			wake_up_interruptible(&apsta_params->netif_change_event);
5363*4882a593Smuzhiyun #ifdef PROPTX_MAXCOUNT
5364*4882a593Smuzhiyun 			wl_ext_update_wlfc_maxcount(dhd);
5365*4882a593Smuzhiyun #endif /* PROPTX_MAXCOUNT */
5366*4882a593Smuzhiyun 		}
5367*4882a593Smuzhiyun 		else if (event_type == WLC_E_DEAUTH || event_type == WLC_E_DEAUTH_IND ||
5368*4882a593Smuzhiyun 				event_type == WLC_E_DISASSOC || event_type == WLC_E_DISASSOC_IND) {
5369*4882a593Smuzhiyun 			WL_MSG(cur_if->ifname, "[%c] Link down with %pM, %s(%d), reason %d\n",
5370*4882a593Smuzhiyun 				cur_if->prefix, &e->addr, bcmevent_get_name(event_type),
5371*4882a593Smuzhiyun 				event_type, reason);
5372*4882a593Smuzhiyun #ifdef SET_CARRIER
5373*4882a593Smuzhiyun 			wl_ext_net_setcarrier(cur_if, FALSE, FALSE);
5374*4882a593Smuzhiyun #endif /* SET_CARRIER */
5375*4882a593Smuzhiyun 		}
5376*4882a593Smuzhiyun 	}
5377*4882a593Smuzhiyun 	else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IGO_MODE ||
5378*4882a593Smuzhiyun 			cur_if->ifmode == IMESH_MODE) {
5379*4882a593Smuzhiyun 		if ((event_type == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
5380*4882a593Smuzhiyun 				(event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
5381*4882a593Smuzhiyun 				reason == WLC_E_REASON_INITIAL_ASSOC)) {
5382*4882a593Smuzhiyun 			if (wl_get_isam_status(cur_if, AP_CREATING)) {
5383*4882a593Smuzhiyun 				WL_MSG(cur_if->ifname, "[%c] Link up (etype=%d)\n",
5384*4882a593Smuzhiyun 					cur_if->prefix, event_type);
5385*4882a593Smuzhiyun 				wl_set_isam_status(cur_if, AP_CREATED);
5386*4882a593Smuzhiyun 				wake_up_interruptible(&apsta_params->netif_change_event);
5387*4882a593Smuzhiyun 			} else {
5388*4882a593Smuzhiyun 				wl_set_isam_status(cur_if, AP_CREATED);
5389*4882a593Smuzhiyun 				WL_MSG(cur_if->ifname, "[%c] Link up w/o creating? (etype=%d)\n",
5390*4882a593Smuzhiyun 					cur_if->prefix, event_type);
5391*4882a593Smuzhiyun 			}
5392*4882a593Smuzhiyun #ifdef SET_CARRIER
5393*4882a593Smuzhiyun 			wl_ext_net_setcarrier(cur_if, TRUE, FALSE);
5394*4882a593Smuzhiyun #endif /* SET_CARRIER */
5395*4882a593Smuzhiyun #ifdef PROPTX_MAXCOUNT
5396*4882a593Smuzhiyun 			wl_ext_update_wlfc_maxcount(dhd);
5397*4882a593Smuzhiyun #endif /* PROPTX_MAXCOUNT */
5398*4882a593Smuzhiyun 		}
5399*4882a593Smuzhiyun 		else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) ||
5400*4882a593Smuzhiyun 				(event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
5401*4882a593Smuzhiyun 				reason == WLC_E_REASON_DEAUTH)) {
5402*4882a593Smuzhiyun 			wl_clr_isam_status(cur_if, AP_CREATED);
5403*4882a593Smuzhiyun 			WL_MSG(cur_if->ifname, "[%c] Link down, reason=%d\n",
5404*4882a593Smuzhiyun 				cur_if->prefix, reason);
5405*4882a593Smuzhiyun #ifdef SET_CARRIER
5406*4882a593Smuzhiyun 			wl_ext_net_setcarrier(cur_if, FALSE, FALSE);
5407*4882a593Smuzhiyun #endif /* SET_CARRIER */
5408*4882a593Smuzhiyun #ifdef PROPTX_MAXCOUNT
5409*4882a593Smuzhiyun 			wl_ext_update_wlfc_maxcount(dhd);
5410*4882a593Smuzhiyun #endif /* PROPTX_MAXCOUNT */
5411*4882a593Smuzhiyun 		}
5412*4882a593Smuzhiyun 		else if ((event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) &&
5413*4882a593Smuzhiyun 				reason == DOT11_SC_SUCCESS) {
5414*4882a593Smuzhiyun 			WL_MSG(cur_if->ifname, "[%c] connected device %pM\n",
5415*4882a593Smuzhiyun 				cur_if->prefix, &e->addr);
5416*4882a593Smuzhiyun 			wl_ext_isam_status(cur_if->dev, NULL, 0);
5417*4882a593Smuzhiyun 		}
5418*4882a593Smuzhiyun 		else if (event_type == WLC_E_DISASSOC_IND ||
5419*4882a593Smuzhiyun 				event_type == WLC_E_DEAUTH_IND ||
5420*4882a593Smuzhiyun 				(event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) {
5421*4882a593Smuzhiyun 			WL_MSG_RLMT(cur_if->ifname, &e->addr, ETHER_ADDR_LEN,
5422*4882a593Smuzhiyun 				"[%c] disconnected device %pM, %s(%d), reason=%d\n",
5423*4882a593Smuzhiyun 				cur_if->prefix, &e->addr, bcmevent_get_name(event_type),
5424*4882a593Smuzhiyun 				event_type, reason);
5425*4882a593Smuzhiyun 			wl_ext_isam_status(cur_if->dev, NULL, 0);
5426*4882a593Smuzhiyun 		}
5427*4882a593Smuzhiyun 	}
5428*4882a593Smuzhiyun }
5429*4882a593Smuzhiyun 
5430*4882a593Smuzhiyun void
wl_ext_iapsta_event(struct net_device * dev,void * argu,const wl_event_msg_t * e,void * data)5431*4882a593Smuzhiyun wl_ext_iapsta_event(struct net_device *dev, void *argu,
5432*4882a593Smuzhiyun 	const wl_event_msg_t *e, void *data)
5433*4882a593Smuzhiyun {
5434*4882a593Smuzhiyun #ifdef ACS_MONITOR
5435*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = (struct wl_apsta_params *)argu;
5436*4882a593Smuzhiyun #endif /* ACS_MONITOR */
5437*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
5438*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
5439*4882a593Smuzhiyun 
5440*4882a593Smuzhiyun 	cur_if = wl_get_cur_if(dev);
5441*4882a593Smuzhiyun 	if (!cur_if || !cur_if->dev) {
5442*4882a593Smuzhiyun 		IAPSTA_DBG(dev->name, "ifidx %d is not ready\n", e->ifidx);
5443*4882a593Smuzhiyun 		return;
5444*4882a593Smuzhiyun 	}
5445*4882a593Smuzhiyun 
5446*4882a593Smuzhiyun 	wl_ext_iapsta_link(cur_if, e, data);
5447*4882a593Smuzhiyun #ifdef TPUT_MONITOR
5448*4882a593Smuzhiyun 	if (dhd->conf->tput_monitor_ms)
5449*4882a593Smuzhiyun 		wl_tput_monitor_handler(cur_if, e, data);
5450*4882a593Smuzhiyun #endif /* TPUT_MONITOR */
5451*4882a593Smuzhiyun 
5452*4882a593Smuzhiyun #if defined(WLMESH) && defined(WL_ESCAN)
5453*4882a593Smuzhiyun 	wl_mesh_event_handler(cur_if, e, data);
5454*4882a593Smuzhiyun #endif /* WLMESH && WL_ESCAN */
5455*4882a593Smuzhiyun #ifdef ACS_MONITOR
5456*4882a593Smuzhiyun 	if ((apsta_params->acs & ACS_DRV_BIT) && apsta_params->acs_tmo)
5457*4882a593Smuzhiyun 		wl_acs_handler(cur_if, e, data);
5458*4882a593Smuzhiyun #endif /* ACS_MONITOR */
5459*4882a593Smuzhiyun #ifdef EAPOL_RESEND
5460*4882a593Smuzhiyun 	wl_resend_eapol_handler(cur_if, e, data);
5461*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
5462*4882a593Smuzhiyun #ifdef KEY_INSTALL_CHECK
5463*4882a593Smuzhiyun 	wl_ext_key_install_handler(cur_if, e, data);
5464*4882a593Smuzhiyun #endif /* KEY_INSTALL_CHECK */
5465*4882a593Smuzhiyun #ifdef RESTART_AP_WAR
5466*4882a593Smuzhiyun 	wl_ext_restart_ap_handler(cur_if, e, data);
5467*4882a593Smuzhiyun #endif /* RESTART_AP_WAR */
5468*4882a593Smuzhiyun #ifdef RESET_AP_WAR
5469*4882a593Smuzhiyun 	wl_ext_reset_ap_handler(cur_if, e, data);
5470*4882a593Smuzhiyun #endif /* RESET_AP_WAR */
5471*4882a593Smuzhiyun #ifdef RXF0OVFL_REINIT_WAR
5472*4882a593Smuzhiyun 	wl_ext_rxf0ovfl_reinit_handler(cur_if, e, data);
5473*4882a593Smuzhiyun #endif /* RXF0OVFL_REINIT_WAR */
5474*4882a593Smuzhiyun 
5475*4882a593Smuzhiyun 	return;
5476*4882a593Smuzhiyun }
5477*4882a593Smuzhiyun 
5478*4882a593Smuzhiyun static int
wl_ext_parse_config(struct wl_if_info * cur_if,char * command,char ** pick_next)5479*4882a593Smuzhiyun wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
5480*4882a593Smuzhiyun {
5481*4882a593Smuzhiyun 	char *pch, *pick_tmp;
5482*4882a593Smuzhiyun 	char name[20], data[100];
5483*4882a593Smuzhiyun 	int i, j, len;
5484*4882a593Smuzhiyun 	char *ifname_head = NULL;
5485*4882a593Smuzhiyun 
5486*4882a593Smuzhiyun 	typedef struct config_map_t {
5487*4882a593Smuzhiyun 		char name[20];
5488*4882a593Smuzhiyun 		char *head;
5489*4882a593Smuzhiyun 		char *tail;
5490*4882a593Smuzhiyun 	} config_map_t;
5491*4882a593Smuzhiyun 
5492*4882a593Smuzhiyun 	config_map_t config_map [] = {
5493*4882a593Smuzhiyun 		{" ifname ",	NULL, NULL},
5494*4882a593Smuzhiyun 		{" ssid ",		NULL, NULL},
5495*4882a593Smuzhiyun 		{" bssid ", 	NULL, NULL},
5496*4882a593Smuzhiyun 		{" bgnmode ",	NULL, NULL},
5497*4882a593Smuzhiyun 		{" hidden ",	NULL, NULL},
5498*4882a593Smuzhiyun 		{" maxassoc ",	NULL, NULL},
5499*4882a593Smuzhiyun 		{" band ",		NULL, NULL},
5500*4882a593Smuzhiyun 		{" chan ",		NULL, NULL},
5501*4882a593Smuzhiyun 		{" amode ", 	NULL, NULL},
5502*4882a593Smuzhiyun 		{" emode ", 	NULL, NULL},
5503*4882a593Smuzhiyun 		{" key ",		NULL, NULL},
5504*4882a593Smuzhiyun 	};
5505*4882a593Smuzhiyun 	config_map_t *row, *row_prev;
5506*4882a593Smuzhiyun 
5507*4882a593Smuzhiyun 	pick_tmp = command;
5508*4882a593Smuzhiyun 
5509*4882a593Smuzhiyun 	// reset head and tail
5510*4882a593Smuzhiyun 	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
5511*4882a593Smuzhiyun 		row = &config_map[i];
5512*4882a593Smuzhiyun 		row->head = NULL;
5513*4882a593Smuzhiyun 		row->tail = pick_tmp + strlen(pick_tmp);
5514*4882a593Smuzhiyun 	}
5515*4882a593Smuzhiyun 
5516*4882a593Smuzhiyun 	// pick head
5517*4882a593Smuzhiyun 	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
5518*4882a593Smuzhiyun 		row = &config_map[i];
5519*4882a593Smuzhiyun 		pch = strstr(pick_tmp, row->name);
5520*4882a593Smuzhiyun 		if (pch) {
5521*4882a593Smuzhiyun 			row->head = pch;
5522*4882a593Smuzhiyun 		}
5523*4882a593Smuzhiyun 	}
5524*4882a593Smuzhiyun 
5525*4882a593Smuzhiyun 	// sort by head
5526*4882a593Smuzhiyun 	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]) - 1; i++) {
5527*4882a593Smuzhiyun 		row_prev = &config_map[i];
5528*4882a593Smuzhiyun 		for (j = i+1; j < sizeof(config_map)/sizeof(config_map[0]); j++) {
5529*4882a593Smuzhiyun 			row = &config_map[j];
5530*4882a593Smuzhiyun 			if (row->head < row_prev->head) {
5531*4882a593Smuzhiyun 				strcpy(name, row_prev->name);
5532*4882a593Smuzhiyun 				strcpy(row_prev->name, row->name);
5533*4882a593Smuzhiyun 				strcpy(row->name, name);
5534*4882a593Smuzhiyun 				pch = row_prev->head;
5535*4882a593Smuzhiyun 				row_prev->head = row->head;
5536*4882a593Smuzhiyun 				row->head = pch;
5537*4882a593Smuzhiyun 			}
5538*4882a593Smuzhiyun 		}
5539*4882a593Smuzhiyun 	}
5540*4882a593Smuzhiyun 
5541*4882a593Smuzhiyun 	// pick tail
5542*4882a593Smuzhiyun 	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]) - 1; i++) {
5543*4882a593Smuzhiyun 		row_prev = &config_map[i];
5544*4882a593Smuzhiyun 		row = &config_map[i+1];
5545*4882a593Smuzhiyun 		if (row_prev->head) {
5546*4882a593Smuzhiyun 			row_prev->tail = row->head;
5547*4882a593Smuzhiyun 		}
5548*4882a593Smuzhiyun 	}
5549*4882a593Smuzhiyun 
5550*4882a593Smuzhiyun 	// remove name from head
5551*4882a593Smuzhiyun 	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
5552*4882a593Smuzhiyun 		row = &config_map[i];
5553*4882a593Smuzhiyun 		if (row->head) {
5554*4882a593Smuzhiyun 			if (!strcmp(row->name, " ifname ")) {
5555*4882a593Smuzhiyun 				ifname_head = row->head + 1;
5556*4882a593Smuzhiyun 				break;
5557*4882a593Smuzhiyun 			}
5558*4882a593Smuzhiyun 			row->head += strlen(row->name);
5559*4882a593Smuzhiyun 		}
5560*4882a593Smuzhiyun 	}
5561*4882a593Smuzhiyun 
5562*4882a593Smuzhiyun 	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
5563*4882a593Smuzhiyun 		row = &config_map[i];
5564*4882a593Smuzhiyun 		if (row->head) {
5565*4882a593Smuzhiyun 			memset(data, 0, sizeof(data));
5566*4882a593Smuzhiyun 			if (row->tail && row->tail > row->head) {
5567*4882a593Smuzhiyun 				strncpy(data, row->head, row->tail-row->head);
5568*4882a593Smuzhiyun 			} else {
5569*4882a593Smuzhiyun 				strcpy(data, row->head);
5570*4882a593Smuzhiyun 			}
5571*4882a593Smuzhiyun 			pick_tmp = data;
5572*4882a593Smuzhiyun 
5573*4882a593Smuzhiyun 			if (!strcmp(row->name, " ifname ")) {
5574*4882a593Smuzhiyun 				break;
5575*4882a593Smuzhiyun 			} else if (!strcmp(row->name, " ssid ")) {
5576*4882a593Smuzhiyun 				len = strlen(pick_tmp);
5577*4882a593Smuzhiyun 				memset(cur_if->ssid, 0, sizeof(cur_if->ssid));
5578*4882a593Smuzhiyun 				if (pick_tmp[0] == '"' && pick_tmp[len-1] == '"')
5579*4882a593Smuzhiyun 					strncpy(cur_if->ssid, &pick_tmp[1], len-2);
5580*4882a593Smuzhiyun 				else
5581*4882a593Smuzhiyun 					strcpy(cur_if->ssid, pick_tmp);
5582*4882a593Smuzhiyun 			} else if (!strcmp(row->name, " bssid ")) {
5583*4882a593Smuzhiyun 				pch = bcmstrtok(&pick_tmp, ": ", 0);
5584*4882a593Smuzhiyun 				for (j=0; j<6 && pch; j++) {
5585*4882a593Smuzhiyun 					((u8 *)&cur_if->bssid)[j] = (int)simple_strtol(pch, NULL, 16);
5586*4882a593Smuzhiyun 					pch = bcmstrtok(&pick_tmp, ": ", 0);
5587*4882a593Smuzhiyun 				}
5588*4882a593Smuzhiyun 			} else if (!strcmp(row->name, " bgnmode ")) {
5589*4882a593Smuzhiyun 				if (!strcmp(pick_tmp, "b"))
5590*4882a593Smuzhiyun 					cur_if->bgnmode = IEEE80211B;
5591*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "g"))
5592*4882a593Smuzhiyun 					cur_if->bgnmode = IEEE80211G;
5593*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "bg"))
5594*4882a593Smuzhiyun 					cur_if->bgnmode = IEEE80211BG;
5595*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "bgn"))
5596*4882a593Smuzhiyun 					cur_if->bgnmode = IEEE80211BGN;
5597*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "bgnac"))
5598*4882a593Smuzhiyun 					cur_if->bgnmode = IEEE80211BGNAC;
5599*4882a593Smuzhiyun 				else {
5600*4882a593Smuzhiyun 					IAPSTA_ERROR(cur_if->dev->name, "bgnmode [b|g|bg|bgn|bgnac]\n");
5601*4882a593Smuzhiyun 					return -1;
5602*4882a593Smuzhiyun 				}
5603*4882a593Smuzhiyun 			} else if (!strcmp(row->name, " hidden ")) {
5604*4882a593Smuzhiyun 				if (!strcmp(pick_tmp, "n"))
5605*4882a593Smuzhiyun 					cur_if->hidden = 0;
5606*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "y"))
5607*4882a593Smuzhiyun 					cur_if->hidden = 1;
5608*4882a593Smuzhiyun 				else {
5609*4882a593Smuzhiyun 					IAPSTA_ERROR(cur_if->dev->name, "hidden [y|n]\n");
5610*4882a593Smuzhiyun 					return -1;
5611*4882a593Smuzhiyun 				}
5612*4882a593Smuzhiyun 			} else if (!strcmp(row->name, " maxassoc ")) {
5613*4882a593Smuzhiyun 				cur_if->maxassoc = (int)simple_strtol(pick_tmp, NULL, 10);
5614*4882a593Smuzhiyun 			} else if (!strcmp(row->name, " band ")) {
5615*4882a593Smuzhiyun 				if (!strcmp(pick_tmp, "2g"))
5616*4882a593Smuzhiyun 					cur_if->amode = WLC_BAND_2G;
5617*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "5g"))
5618*4882a593Smuzhiyun 					cur_if->amode = WLC_BAND_5G;
5619*4882a593Smuzhiyun #ifdef WL_6G_BAND
5620*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "6g"))
5621*4882a593Smuzhiyun 					cur_if->amode = WLC_BAND_6G;
5622*4882a593Smuzhiyun #endif /* WL_6G_BAND */
5623*4882a593Smuzhiyun 				else {
5624*4882a593Smuzhiyun 					IAPSTA_ERROR(cur_if->dev->name, "band [2g|5g|6g]\n");
5625*4882a593Smuzhiyun 					return -1;
5626*4882a593Smuzhiyun 				}
5627*4882a593Smuzhiyun 			} else if (!strcmp(row->name, " chan ")) {
5628*4882a593Smuzhiyun 				cur_if->chan_info.chan = (int)simple_strtol(pick_tmp, NULL, 10);
5629*4882a593Smuzhiyun 				if (!cur_if->chan_info.band)
5630*4882a593Smuzhiyun 					cur_if->chan_info.band = WL_GET_BAND(cur_if->chan_info.chan);
5631*4882a593Smuzhiyun 			} else if (!strcmp(row->name, " amode ")) {
5632*4882a593Smuzhiyun 				if (!strcmp(pick_tmp, "open"))
5633*4882a593Smuzhiyun 					cur_if->amode = AUTH_OPEN;
5634*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "shared"))
5635*4882a593Smuzhiyun 					cur_if->amode = AUTH_SHARED;
5636*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "wpapsk"))
5637*4882a593Smuzhiyun 					cur_if->amode = AUTH_WPAPSK;
5638*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "wpa2psk"))
5639*4882a593Smuzhiyun 					cur_if->amode = AUTH_WPA2PSK;
5640*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "wpawpa2psk"))
5641*4882a593Smuzhiyun 					cur_if->amode = AUTH_WPAWPA2PSK;
5642*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "sae"))
5643*4882a593Smuzhiyun 					cur_if->amode = AUTH_SAE;
5644*4882a593Smuzhiyun 				else {
5645*4882a593Smuzhiyun 					IAPSTA_ERROR(cur_if->dev->name, "amode [open|shared|wpapsk|wpa2psk|wpawpa2psk]\n");
5646*4882a593Smuzhiyun 					return -1;
5647*4882a593Smuzhiyun 				}
5648*4882a593Smuzhiyun 			} else if (!strcmp(row->name, " emode ")) {
5649*4882a593Smuzhiyun 				if (!strcmp(pick_tmp, "none"))
5650*4882a593Smuzhiyun 					cur_if->emode = ENC_NONE;
5651*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "wep"))
5652*4882a593Smuzhiyun 					cur_if->emode = ENC_WEP;
5653*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "tkip"))
5654*4882a593Smuzhiyun 					cur_if->emode = ENC_TKIP;
5655*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "aes"))
5656*4882a593Smuzhiyun 					cur_if->emode = ENC_AES;
5657*4882a593Smuzhiyun 				else if (!strcmp(pick_tmp, "tkipaes"))
5658*4882a593Smuzhiyun 					cur_if->emode = ENC_TKIPAES;
5659*4882a593Smuzhiyun 				else {
5660*4882a593Smuzhiyun 					IAPSTA_ERROR(cur_if->dev->name, "emode [none|wep|tkip|aes|tkipaes]\n");
5661*4882a593Smuzhiyun 					return -1;
5662*4882a593Smuzhiyun 				}
5663*4882a593Smuzhiyun 			} else if (!strcmp(row->name, " key ")) {
5664*4882a593Smuzhiyun 				len = strlen(pick_tmp);
5665*4882a593Smuzhiyun 				memset(cur_if->key, 0, sizeof(cur_if->key));
5666*4882a593Smuzhiyun 				if (pick_tmp[0] == '"' && pick_tmp[len-1] == '"')
5667*4882a593Smuzhiyun 					strncpy(cur_if->key, &pick_tmp[1], len-2);
5668*4882a593Smuzhiyun 				else
5669*4882a593Smuzhiyun 					strcpy(cur_if->key, pick_tmp);
5670*4882a593Smuzhiyun 			}
5671*4882a593Smuzhiyun 		}
5672*4882a593Smuzhiyun 	}
5673*4882a593Smuzhiyun 
5674*4882a593Smuzhiyun 	*pick_next = ifname_head;
5675*4882a593Smuzhiyun 	return 0;
5676*4882a593Smuzhiyun }
5677*4882a593Smuzhiyun 
5678*4882a593Smuzhiyun static void
wl_ext_iapsta_preinit(struct net_device * dev,struct wl_apsta_params * apsta_params)5679*4882a593Smuzhiyun wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_params)
5680*4882a593Smuzhiyun {
5681*4882a593Smuzhiyun 	struct dhd_pub *dhd;
5682*4882a593Smuzhiyun 	apstamode_t apstamode = apsta_params->apstamode;
5683*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
5684*4882a593Smuzhiyun 	s8 iovar_buf[WLC_IOCTL_SMLEN];
5685*4882a593Smuzhiyun 	s32 val = 0;
5686*4882a593Smuzhiyun 	int i;
5687*4882a593Smuzhiyun 
5688*4882a593Smuzhiyun 	dhd = dhd_get_pub(dev);
5689*4882a593Smuzhiyun 
5690*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
5691*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[i];
5692*4882a593Smuzhiyun 		if (i >= 1 && !strlen(cur_if->ifname))
5693*4882a593Smuzhiyun 			snprintf(cur_if->ifname, IFNAMSIZ, "wlan%d", i);
5694*4882a593Smuzhiyun 		if (cur_if->ifmode == ISTA_MODE) {
5695*4882a593Smuzhiyun 			wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 0);
5696*4882a593Smuzhiyun 			cur_if->maxassoc = -1;
5697*4882a593Smuzhiyun 			cur_if->prio = PRIO_STA;
5698*4882a593Smuzhiyun 			cur_if->vsdb = TRUE;
5699*4882a593Smuzhiyun 			cur_if->prefix = 'S';
5700*4882a593Smuzhiyun 			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta");
5701*4882a593Smuzhiyun 		} else if (cur_if->ifmode == IAP_MODE) {
5702*4882a593Smuzhiyun 			wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1);
5703*4882a593Smuzhiyun 			cur_if->maxassoc = -1;
5704*4882a593Smuzhiyun 			cur_if->prio = PRIO_AP;
5705*4882a593Smuzhiyun 			cur_if->vsdb = FALSE;
5706*4882a593Smuzhiyun 			cur_if->prefix = 'A';
5707*4882a593Smuzhiyun 			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap");
5708*4882a593Smuzhiyun #ifdef WLMESH
5709*4882a593Smuzhiyun 		} else if (cur_if->ifmode == IMESH_MODE) {
5710*4882a593Smuzhiyun 			wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1);
5711*4882a593Smuzhiyun 			cur_if->maxassoc = -1;
5712*4882a593Smuzhiyun 			cur_if->prio = PRIO_MESH;
5713*4882a593Smuzhiyun 			cur_if->vsdb = FALSE;
5714*4882a593Smuzhiyun 			cur_if->prefix = 'M';
5715*4882a593Smuzhiyun 			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh");
5716*4882a593Smuzhiyun #endif /* WLMESH */
5717*4882a593Smuzhiyun 		}
5718*4882a593Smuzhiyun 	}
5719*4882a593Smuzhiyun 
5720*4882a593Smuzhiyun 	if (FW_SUPPORTED(dhd, rsdb)) {
5721*4882a593Smuzhiyun 		if (apstamode == IDUALAP_MODE)
5722*4882a593Smuzhiyun 			apsta_params->rsdb = -1;
5723*4882a593Smuzhiyun 		else if (apstamode == ISTAAPAP_MODE)
5724*4882a593Smuzhiyun 			apsta_params->rsdb = 0;
5725*4882a593Smuzhiyun 		if (apstamode == ISTAAPAP_MODE || apstamode == IDUALAP_MODE ||
5726*4882a593Smuzhiyun 				apstamode == IMESHONLY_MODE || apstamode == ISTAMESH_MODE ||
5727*4882a593Smuzhiyun 				apstamode == IMESHAP_MODE || apstamode == ISTAAPMESH_MODE ||
5728*4882a593Smuzhiyun 				apstamode == IMESHAPAP_MODE) {
5729*4882a593Smuzhiyun 			wl_config_t rsdb_mode_cfg = {0, 0};
5730*4882a593Smuzhiyun 			rsdb_mode_cfg.config = apsta_params->rsdb;
5731*4882a593Smuzhiyun 			IAPSTA_INFO(dev->name, "set rsdb_mode %d\n", rsdb_mode_cfg.config);
5732*4882a593Smuzhiyun 			wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
5733*4882a593Smuzhiyun 			wl_ext_iovar_setbuf(dev, "rsdb_mode", &rsdb_mode_cfg,
5734*4882a593Smuzhiyun 				sizeof(rsdb_mode_cfg), iovar_buf, sizeof(iovar_buf), NULL);
5735*4882a593Smuzhiyun 			wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
5736*4882a593Smuzhiyun 		}
5737*4882a593Smuzhiyun 	} else {
5738*4882a593Smuzhiyun 		apsta_params->rsdb = 0;
5739*4882a593Smuzhiyun 	}
5740*4882a593Smuzhiyun 
5741*4882a593Smuzhiyun 	if (apstamode == ISTAONLY_MODE) {
5742*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
5743*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
5744*4882a593Smuzhiyun 		// don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
5745*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
5746*4882a593Smuzhiyun 	} else if (apstamode == IAPONLY_MODE) {
5747*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
5748*4882a593Smuzhiyun #ifdef ARP_OFFLOAD_SUPPORT
5749*4882a593Smuzhiyun 		/* IF SoftAP is enabled, disable arpoe */
5750*4882a593Smuzhiyun 		dhd_arp_offload_set(dhd, 0);
5751*4882a593Smuzhiyun 		dhd_arp_offload_enable(dhd, FALSE);
5752*4882a593Smuzhiyun #endif /* ARP_OFFLOAD_SUPPORT */
5753*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "mpc", 0);
5754*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "apsta", 0);
5755*4882a593Smuzhiyun 		val = 1;
5756*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1);
5757*4882a593Smuzhiyun #ifdef PROP_TXSTATUS_VSDB
5758*4882a593Smuzhiyun #if defined(BCMSDIO)
5759*4882a593Smuzhiyun 		if (!(FW_SUPPORTED(dhd, rsdb)) && !disable_proptx) {
5760*4882a593Smuzhiyun 			bool enabled;
5761*4882a593Smuzhiyun 			dhd_wlfc_get_enable(dhd, &enabled);
5762*4882a593Smuzhiyun 			if (!enabled) {
5763*4882a593Smuzhiyun 				dhd_wlfc_init(dhd);
5764*4882a593Smuzhiyun 				wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
5765*4882a593Smuzhiyun 			}
5766*4882a593Smuzhiyun 		}
5767*4882a593Smuzhiyun #endif /* BCMSDIO */
5768*4882a593Smuzhiyun #endif /* PROP_TXSTATUS_VSDB */
5769*4882a593Smuzhiyun 	}
5770*4882a593Smuzhiyun 	else if (apstamode == ISTAAP_MODE) {
5771*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
5772*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "mpc", 0);
5773*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "apsta", 1);
5774*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
5775*4882a593Smuzhiyun 	}
5776*4882a593Smuzhiyun 	else if (apstamode == ISTAGO_MODE) {
5777*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
5778*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "apsta", 1);
5779*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
5780*4882a593Smuzhiyun 	}
5781*4882a593Smuzhiyun 	else if (apstamode == ISTASTA_MODE) {
5782*4882a593Smuzhiyun 	}
5783*4882a593Smuzhiyun 	else if (apstamode == IDUALAP_MODE) {
5784*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
5785*4882a593Smuzhiyun 		/* IF SoftAP is enabled, disable arpoe or wlan1 will ping fail */
5786*4882a593Smuzhiyun #ifdef ARP_OFFLOAD_SUPPORT
5787*4882a593Smuzhiyun 		/* IF SoftAP is enabled, disable arpoe */
5788*4882a593Smuzhiyun 		dhd_arp_offload_set(dhd, 0);
5789*4882a593Smuzhiyun 		dhd_arp_offload_enable(dhd, FALSE);
5790*4882a593Smuzhiyun #endif /* ARP_OFFLOAD_SUPPORT */
5791*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "mpc", 0);
5792*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "mbcn", 1);
5793*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "apsta", 0);
5794*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
5795*4882a593Smuzhiyun 		val = 1;
5796*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1);
5797*4882a593Smuzhiyun 	}
5798*4882a593Smuzhiyun 	else if (apstamode == ISTAAPAP_MODE) {
5799*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
5800*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "mpc", 0);
5801*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "mbss", 1);
5802*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
5803*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
5804*4882a593Smuzhiyun 		// don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
5805*4882a593Smuzhiyun 	}
5806*4882a593Smuzhiyun #ifdef WLMESH
5807*4882a593Smuzhiyun 	else if (apstamode == IMESHONLY_MODE || apstamode == ISTAMESH_MODE ||
5808*4882a593Smuzhiyun 			apstamode == IMESHAP_MODE || apstamode == ISTAAPMESH_MODE ||
5809*4882a593Smuzhiyun 			apstamode == IMESHAPAP_MODE) {
5810*4882a593Smuzhiyun 		int pm = 0;
5811*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
5812*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "mpc", 0);
5813*4882a593Smuzhiyun 		if (apstamode == IMESHONLY_MODE)
5814*4882a593Smuzhiyun 			wl_ext_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), 1);
5815*4882a593Smuzhiyun 		else
5816*4882a593Smuzhiyun 			wl_ext_iovar_setint(dev, "mbcn", 1);
5817*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
5818*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
5819*4882a593Smuzhiyun 		// don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
5820*4882a593Smuzhiyun 	}
5821*4882a593Smuzhiyun #endif /* WLMESH */
5822*4882a593Smuzhiyun 
5823*4882a593Smuzhiyun 	apsta_params->init = TRUE;
5824*4882a593Smuzhiyun 
5825*4882a593Smuzhiyun 	WL_MSG(dev->name, "apstamode=%d\n", apstamode);
5826*4882a593Smuzhiyun }
5827*4882a593Smuzhiyun 
5828*4882a593Smuzhiyun static int
wl_ext_disable_iface(struct net_device * dev,char * ifname)5829*4882a593Smuzhiyun wl_ext_disable_iface(struct net_device *dev, char *ifname)
5830*4882a593Smuzhiyun {
5831*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
5832*4882a593Smuzhiyun 	int i;
5833*4882a593Smuzhiyun 	s8 iovar_buf[WLC_IOCTL_SMLEN];
5834*4882a593Smuzhiyun 	wlc_ssid_t ssid = { 0, {0} };
5835*4882a593Smuzhiyun 	scb_val_t scbval;
5836*4882a593Smuzhiyun 	struct {
5837*4882a593Smuzhiyun 		s32 cfg;
5838*4882a593Smuzhiyun 		s32 val;
5839*4882a593Smuzhiyun 	} bss_setbuf;
5840*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5841*4882a593Smuzhiyun 	apstamode_t apstamode = apsta_params->apstamode;
5842*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL, *tmp_if = NULL;
5843*4882a593Smuzhiyun 
5844*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
5845*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
5846*4882a593Smuzhiyun 		if (tmp_if->dev && !strcmp(tmp_if->dev->name, ifname)) {
5847*4882a593Smuzhiyun 			cur_if = tmp_if;
5848*4882a593Smuzhiyun 			break;
5849*4882a593Smuzhiyun 		}
5850*4882a593Smuzhiyun 	}
5851*4882a593Smuzhiyun 	if (!cur_if) {
5852*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "wrong ifname=%s or dev not ready\n", ifname);
5853*4882a593Smuzhiyun 		return -1;
5854*4882a593Smuzhiyun 	}
5855*4882a593Smuzhiyun 
5856*4882a593Smuzhiyun 	mutex_lock(&apsta_params->usr_sync);
5857*4882a593Smuzhiyun 	WL_MSG(ifname, "[%c] Disabling...\n", cur_if->prefix);
5858*4882a593Smuzhiyun 
5859*4882a593Smuzhiyun 	if (cur_if->ifmode == ISTA_MODE) {
5860*4882a593Smuzhiyun 		wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
5861*4882a593Smuzhiyun 		wl_ext_add_remove_pm_enable_work(dev, FALSE);
5862*4882a593Smuzhiyun 	} else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
5863*4882a593Smuzhiyun 		// deauthenticate all STA first
5864*4882a593Smuzhiyun 		memcpy(scbval.ea.octet, &ether_bcast, ETHER_ADDR_LEN);
5865*4882a593Smuzhiyun 		wl_ext_ioctl(cur_if->dev, WLC_SCB_DEAUTHENTICATE, &scbval.ea, ETHER_ADDR_LEN, 1);
5866*4882a593Smuzhiyun 	}
5867*4882a593Smuzhiyun 
5868*4882a593Smuzhiyun 	if (apstamode == IAPONLY_MODE || apstamode == IMESHONLY_MODE) {
5869*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
5870*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); // reset ssid
5871*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "mpc", 1);
5872*4882a593Smuzhiyun 	} else if ((apstamode==ISTAAP_MODE || apstamode==ISTAGO_MODE) &&
5873*4882a593Smuzhiyun 			cur_if->ifmode == IAP_MODE) {
5874*4882a593Smuzhiyun 		bss_setbuf.cfg = 0xffffffff;
5875*4882a593Smuzhiyun 		bss_setbuf.val = htod32(0);
5876*4882a593Smuzhiyun 		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
5877*4882a593Smuzhiyun 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
5878*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "mpc", 1);
5879*4882a593Smuzhiyun #ifdef ARP_OFFLOAD_SUPPORT
5880*4882a593Smuzhiyun 		/* IF SoftAP is disabled, enable arpoe back for STA mode. */
5881*4882a593Smuzhiyun 		dhd_arp_offload_set(dhd, dhd_arp_mode);
5882*4882a593Smuzhiyun 		dhd_arp_offload_enable(dhd, TRUE);
5883*4882a593Smuzhiyun #endif /* ARP_OFFLOAD_SUPPORT */
5884*4882a593Smuzhiyun #ifdef PROP_TXSTATUS_VSDB
5885*4882a593Smuzhiyun #if defined(BCMSDIO)
5886*4882a593Smuzhiyun 		if (dhd->conf->disable_proptx!=0) {
5887*4882a593Smuzhiyun 			bool enabled;
5888*4882a593Smuzhiyun 			dhd_wlfc_get_enable(dhd, &enabled);
5889*4882a593Smuzhiyun 			if (enabled) {
5890*4882a593Smuzhiyun 				dhd_wlfc_deinit(dhd);
5891*4882a593Smuzhiyun 			}
5892*4882a593Smuzhiyun 		}
5893*4882a593Smuzhiyun #endif /* BCMSDIO */
5894*4882a593Smuzhiyun #endif /* PROP_TXSTATUS_VSDB */
5895*4882a593Smuzhiyun 	}
5896*4882a593Smuzhiyun 	else if (apstamode == IDUALAP_MODE || apstamode == ISTAAPAP_MODE) {
5897*4882a593Smuzhiyun 		bss_setbuf.cfg = 0xffffffff;
5898*4882a593Smuzhiyun 		bss_setbuf.val = htod32(0);
5899*4882a593Smuzhiyun 		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
5900*4882a593Smuzhiyun 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
5901*4882a593Smuzhiyun #ifdef WLMESH
5902*4882a593Smuzhiyun 	} else if (apstamode == ISTAMESH_MODE || apstamode == IMESHAP_MODE ||
5903*4882a593Smuzhiyun 			apstamode == ISTAAPMESH_MODE || apstamode == IMESHAPAP_MODE) {
5904*4882a593Smuzhiyun 		bss_setbuf.cfg = 0xffffffff;
5905*4882a593Smuzhiyun 		bss_setbuf.val = htod32(0);
5906*4882a593Smuzhiyun 		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
5907*4882a593Smuzhiyun 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
5908*4882a593Smuzhiyun 		if (cur_if->ifmode == IMESH_MODE) {
5909*4882a593Smuzhiyun 			int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME;
5910*4882a593Smuzhiyun 			for (i=0; i<MAX_IF_NUM; i++) {
5911*4882a593Smuzhiyun 				tmp_if = &apsta_params->if_info[i];
5912*4882a593Smuzhiyun 				if (tmp_if->dev && tmp_if->ifmode == ISTA_MODE) {
5913*4882a593Smuzhiyun 					wl_ext_ioctl(tmp_if->dev, WLC_SET_SCAN_CHANNEL_TIME,
5914*4882a593Smuzhiyun 						&scan_assoc_time, sizeof(scan_assoc_time), 1);
5915*4882a593Smuzhiyun 				}
5916*4882a593Smuzhiyun 			}
5917*4882a593Smuzhiyun 		}
5918*4882a593Smuzhiyun #endif /* WLMESH */
5919*4882a593Smuzhiyun 	}
5920*4882a593Smuzhiyun 
5921*4882a593Smuzhiyun 	wl_clr_isam_status(cur_if, AP_CREATED);
5922*4882a593Smuzhiyun 
5923*4882a593Smuzhiyun 	WL_MSG(ifname, "[%c] Exit\n", cur_if->prefix);
5924*4882a593Smuzhiyun 	mutex_unlock(&apsta_params->usr_sync);
5925*4882a593Smuzhiyun 	return 0;
5926*4882a593Smuzhiyun }
5927*4882a593Smuzhiyun 
5928*4882a593Smuzhiyun static int
wl_ext_enable_iface(struct net_device * dev,char * ifname,int wait_up,bool lock)5929*4882a593Smuzhiyun wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock)
5930*4882a593Smuzhiyun {
5931*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
5932*4882a593Smuzhiyun 	int i, ret = 0;
5933*4882a593Smuzhiyun 	s8 iovar_buf[WLC_IOCTL_SMLEN];
5934*4882a593Smuzhiyun 	wlc_ssid_t ssid = { 0, {0} };
5935*4882a593Smuzhiyun 	chanspec_t fw_chspec;
5936*4882a593Smuzhiyun 	struct {
5937*4882a593Smuzhiyun 		s32 cfg;
5938*4882a593Smuzhiyun 		s32 val;
5939*4882a593Smuzhiyun 	} bss_setbuf;
5940*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5941*4882a593Smuzhiyun 	apstamode_t apstamode = apsta_params->apstamode;
5942*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL, *tmp_if = NULL;
5943*4882a593Smuzhiyun 	struct wl_chan_info chan_info;
5944*4882a593Smuzhiyun 	struct wl_conn_info conn_info;
5945*4882a593Smuzhiyun 	u32 timeout;
5946*4882a593Smuzhiyun 
5947*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
5948*4882a593Smuzhiyun 		tmp_if = &apsta_params->if_info[i];
5949*4882a593Smuzhiyun 		if (tmp_if->dev && !strcmp(tmp_if->dev->name, ifname)) {
5950*4882a593Smuzhiyun 			cur_if = tmp_if;
5951*4882a593Smuzhiyun 			break;
5952*4882a593Smuzhiyun 		}
5953*4882a593Smuzhiyun 	}
5954*4882a593Smuzhiyun 	if (!cur_if) {
5955*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "wrong ifname=%s or dev not ready\n", ifname);
5956*4882a593Smuzhiyun 		return -1;
5957*4882a593Smuzhiyun 	}
5958*4882a593Smuzhiyun 
5959*4882a593Smuzhiyun 	if (lock)
5960*4882a593Smuzhiyun 		mutex_lock(&apsta_params->usr_sync);
5961*4882a593Smuzhiyun 
5962*4882a593Smuzhiyun 	if (cur_if->ifmode == ISTA_MODE) {
5963*4882a593Smuzhiyun 		wl_set_isam_status(cur_if, STA_CONNECTING);
5964*4882a593Smuzhiyun 	} else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
5965*4882a593Smuzhiyun 		wl_set_isam_status(cur_if, AP_CREATING);
5966*4882a593Smuzhiyun 	}
5967*4882a593Smuzhiyun 
5968*4882a593Smuzhiyun 	wl_ext_isam_status(cur_if->dev, NULL, 0);
5969*4882a593Smuzhiyun 	WL_MSG(ifname, "[%c] Enabling...\n", cur_if->prefix);
5970*4882a593Smuzhiyun 
5971*4882a593Smuzhiyun 	wl_ext_wait_other_enabling(apsta_params, cur_if);
5972*4882a593Smuzhiyun 
5973*4882a593Smuzhiyun 	if (wl_ext_master_if(cur_if) && apsta_params->acs) {
5974*4882a593Smuzhiyun 		uint16 chan_2g, chan_5g;
5975*4882a593Smuzhiyun 		wl_ext_get_default_chan(cur_if->dev, &chan_2g, &chan_5g, TRUE);
5976*4882a593Smuzhiyun 		if ((chan_2g && cur_if->chan_info.band == WLC_BAND_2G) ||
5977*4882a593Smuzhiyun 				(chan_5g && cur_if->chan_info.band == WLC_BAND_5G)) {
5978*4882a593Smuzhiyun 			cur_if->chan_info.chan = wl_ext_autochannel(cur_if->dev, apsta_params->acs,
5979*4882a593Smuzhiyun 				cur_if->chan_info.band);
5980*4882a593Smuzhiyun 			cur_if->chan_info.chan = wf_chspec_ctlchan(cur_if->chan_info.chan);
5981*4882a593Smuzhiyun 		} else {
5982*4882a593Smuzhiyun 			IAPSTA_ERROR(ifname, "invalid channel\n");
5983*4882a593Smuzhiyun 			ret = -1;
5984*4882a593Smuzhiyun 			goto exit;
5985*4882a593Smuzhiyun 		}
5986*4882a593Smuzhiyun 	}
5987*4882a593Smuzhiyun 
5988*4882a593Smuzhiyun 	wl_ext_move_cur_channel(apsta_params, cur_if);
5989*4882a593Smuzhiyun 
5990*4882a593Smuzhiyun 	if (wl_ext_master_if(cur_if) && !cur_if->chan_info.chan) {
5991*4882a593Smuzhiyun 		IAPSTA_ERROR(ifname, "skip channel 0\n");
5992*4882a593Smuzhiyun 		ret = -1;
5993*4882a593Smuzhiyun 		goto exit;
5994*4882a593Smuzhiyun 	}
5995*4882a593Smuzhiyun 
5996*4882a593Smuzhiyun 	memset(&chan_info, 0, sizeof(struct wl_chan_info));
5997*4882a593Smuzhiyun 	wl_ext_get_chan(cur_if->dev, &chan_info);
5998*4882a593Smuzhiyun 	if (chan_info.chan) {
5999*4882a593Smuzhiyun 		IAPSTA_INFO(cur_if->ifname, "Associated\n");
6000*4882a593Smuzhiyun 		if (!wl_ext_same_chan(&cur_if->chan_info, &chan_info)) {
6001*4882a593Smuzhiyun 			wl_ext_trigger_csa(apsta_params, cur_if);
6002*4882a593Smuzhiyun 		}
6003*4882a593Smuzhiyun 		goto exit;
6004*4882a593Smuzhiyun 	}
6005*4882a593Smuzhiyun 	if (cur_if->ifmode == ISTA_MODE) {
6006*4882a593Smuzhiyun 		wl_clr_isam_status(cur_if, STA_CONNECTED);
6007*4882a593Smuzhiyun 	} else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
6008*4882a593Smuzhiyun 		wl_clr_isam_status(cur_if, AP_CREATED);
6009*4882a593Smuzhiyun 	}
6010*4882a593Smuzhiyun 
6011*4882a593Smuzhiyun 	wl_ext_move_other_channel(apsta_params, cur_if);
6012*4882a593Smuzhiyun 
6013*4882a593Smuzhiyun 	if (cur_if->ifidx > 0) {
6014*4882a593Smuzhiyun 		wl_ext_iovar_setbuf(cur_if->dev, "cur_etheraddr", (u8 *)cur_if->dev->dev_addr,
6015*4882a593Smuzhiyun 			ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL);
6016*4882a593Smuzhiyun 	}
6017*4882a593Smuzhiyun 
6018*4882a593Smuzhiyun 	// set ssid for AP
6019*4882a593Smuzhiyun 	ssid.SSID_len = strlen(cur_if->ssid);
6020*4882a593Smuzhiyun 	memcpy(ssid.SSID, cur_if->ssid, ssid.SSID_len);
6021*4882a593Smuzhiyun 	if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
6022*4882a593Smuzhiyun 		wl_ext_iovar_setint(dev, "mpc", 0);
6023*4882a593Smuzhiyun 		if (apstamode == IAPONLY_MODE || apstamode == IMESHONLY_MODE) {
6024*4882a593Smuzhiyun 			wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
6025*4882a593Smuzhiyun 		} else if (apstamode==ISTAAP_MODE || apstamode==ISTAGO_MODE) {
6026*4882a593Smuzhiyun 			wl_ext_iovar_setbuf_bsscfg(cur_if->dev, "ssid", &ssid, sizeof(ssid),
6027*4882a593Smuzhiyun 				iovar_buf, WLC_IOCTL_SMLEN, cur_if->bssidx, NULL);
6028*4882a593Smuzhiyun 		}
6029*4882a593Smuzhiyun 	}
6030*4882a593Smuzhiyun 
6031*4882a593Smuzhiyun 	if (wl_ext_master_if(cur_if)) {
6032*4882a593Smuzhiyun 		wl_ext_set_bgnmode(cur_if);
6033*4882a593Smuzhiyun 		if (!cur_if->chan_info.chan) {
6034*4882a593Smuzhiyun 			wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1);
6035*4882a593Smuzhiyun 		}
6036*4882a593Smuzhiyun 		ret = wl_ext_set_chanspec(cur_if->dev, &cur_if->chan_info, &fw_chspec);
6037*4882a593Smuzhiyun 		if (ret)
6038*4882a593Smuzhiyun 			goto exit;
6039*4882a593Smuzhiyun 	}
6040*4882a593Smuzhiyun 
6041*4882a593Smuzhiyun 	wl_ext_set_amode(cur_if);
6042*4882a593Smuzhiyun 	wl_ext_set_emode(cur_if);
6043*4882a593Smuzhiyun 
6044*4882a593Smuzhiyun 	if (cur_if->ifmode == ISTA_MODE) {
6045*4882a593Smuzhiyun 		conn_info.bssidx = cur_if->bssidx;
6046*4882a593Smuzhiyun 		conn_info.channel = cur_if->chan_info.chan;
6047*4882a593Smuzhiyun 		memcpy(conn_info.ssid.SSID, cur_if->ssid, strlen(cur_if->ssid));
6048*4882a593Smuzhiyun 		conn_info.ssid.SSID_len = strlen(cur_if->ssid);
6049*4882a593Smuzhiyun 		memcpy(&conn_info.bssid, &cur_if->bssid, ETHER_ADDR_LEN);
6050*4882a593Smuzhiyun 	}
6051*4882a593Smuzhiyun 	if (cur_if->ifmode == IAP_MODE) {
6052*4882a593Smuzhiyun 		if (cur_if->maxassoc >= 0)
6053*4882a593Smuzhiyun 			wl_ext_iovar_setint(dev, "maxassoc", cur_if->maxassoc);
6054*4882a593Smuzhiyun 		// terence: fix me, hidden does not work in dualAP mode
6055*4882a593Smuzhiyun 		if (cur_if->hidden > 0) {
6056*4882a593Smuzhiyun 			wl_ext_ioctl(cur_if->dev, WLC_SET_CLOSED, &cur_if->hidden,
6057*4882a593Smuzhiyun 				sizeof(cur_if->hidden), 1);
6058*4882a593Smuzhiyun 			WL_MSG(ifname, "[%c] Broadcast SSID: %s\n",
6059*4882a593Smuzhiyun 				cur_if->prefix, cur_if->hidden ? "OFF":"ON");
6060*4882a593Smuzhiyun 		}
6061*4882a593Smuzhiyun 	}
6062*4882a593Smuzhiyun 
6063*4882a593Smuzhiyun 	if (apstamode == ISTAONLY_MODE) {
6064*4882a593Smuzhiyun 		wl_ext_connect(cur_if->dev, &conn_info);
6065*4882a593Smuzhiyun 	} else if (apstamode == IAPONLY_MODE) {
6066*4882a593Smuzhiyun 		wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
6067*4882a593Smuzhiyun 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
6068*4882a593Smuzhiyun 	} else if (apstamode == ISTAAP_MODE || apstamode == ISTAGO_MODE) {
6069*4882a593Smuzhiyun 		if (cur_if->ifmode == ISTA_MODE) {
6070*4882a593Smuzhiyun 			wl_ext_connect(cur_if->dev, &conn_info);
6071*4882a593Smuzhiyun 		} else {
6072*4882a593Smuzhiyun 			if (FW_SUPPORTED(dhd, rsdb)) {
6073*4882a593Smuzhiyun 				wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
6074*4882a593Smuzhiyun 			} else {
6075*4882a593Smuzhiyun 				bss_setbuf.cfg = htod32(cur_if->bssidx);
6076*4882a593Smuzhiyun 				bss_setbuf.val = htod32(1);
6077*4882a593Smuzhiyun 				wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf,
6078*4882a593Smuzhiyun 					sizeof(bss_setbuf), iovar_buf, WLC_IOCTL_SMLEN, NULL);
6079*4882a593Smuzhiyun 			}
6080*4882a593Smuzhiyun #ifdef ARP_OFFLOAD_SUPPORT
6081*4882a593Smuzhiyun 			/* IF SoftAP is enabled, disable arpoe */
6082*4882a593Smuzhiyun 			dhd_arp_offload_set(dhd, 0);
6083*4882a593Smuzhiyun 			dhd_arp_offload_enable(dhd, FALSE);
6084*4882a593Smuzhiyun #endif /* ARP_OFFLOAD_SUPPORT */
6085*4882a593Smuzhiyun #ifdef PROP_TXSTATUS_VSDB
6086*4882a593Smuzhiyun #if defined(BCMSDIO)
6087*4882a593Smuzhiyun 			if (!(FW_SUPPORTED(dhd, rsdb)) && !disable_proptx) {
6088*4882a593Smuzhiyun 				bool enabled;
6089*4882a593Smuzhiyun 				dhd_wlfc_get_enable(dhd, &enabled);
6090*4882a593Smuzhiyun 				if (!enabled) {
6091*4882a593Smuzhiyun 					dhd_wlfc_init(dhd);
6092*4882a593Smuzhiyun 					wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
6093*4882a593Smuzhiyun 				}
6094*4882a593Smuzhiyun 			}
6095*4882a593Smuzhiyun #endif /* BCMSDIO */
6096*4882a593Smuzhiyun #endif /* PROP_TXSTATUS_VSDB */
6097*4882a593Smuzhiyun 		}
6098*4882a593Smuzhiyun 	}
6099*4882a593Smuzhiyun 	else if (apstamode == IDUALAP_MODE) {
6100*4882a593Smuzhiyun 		wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
6101*4882a593Smuzhiyun 	} else if (apstamode == ISTAAPAP_MODE) {
6102*4882a593Smuzhiyun 		if (cur_if->ifmode == ISTA_MODE) {
6103*4882a593Smuzhiyun 			wl_ext_connect(cur_if->dev, &conn_info);
6104*4882a593Smuzhiyun 		} else if (cur_if->ifmode == IAP_MODE) {
6105*4882a593Smuzhiyun 			wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
6106*4882a593Smuzhiyun 		} else {
6107*4882a593Smuzhiyun 			IAPSTA_ERROR(cur_if->ifname, "wrong ifmode %d\n", cur_if->ifmode);
6108*4882a593Smuzhiyun 		}
6109*4882a593Smuzhiyun #ifdef WLMESH
6110*4882a593Smuzhiyun 	} else if (apstamode == IMESHONLY_MODE ||
6111*4882a593Smuzhiyun 			apstamode == ISTAMESH_MODE || apstamode == IMESHAP_MODE ||
6112*4882a593Smuzhiyun 			apstamode == ISTAAPMESH_MODE || apstamode == IMESHAPAP_MODE) {
6113*4882a593Smuzhiyun 		if (cur_if->ifmode == ISTA_MODE) {
6114*4882a593Smuzhiyun 			wl_ext_connect(cur_if->dev, &conn_info);
6115*4882a593Smuzhiyun 		} else if (cur_if->ifmode == IAP_MODE) {
6116*4882a593Smuzhiyun 			wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
6117*4882a593Smuzhiyun 		} else if (cur_if->ifmode == IMESH_MODE) {
6118*4882a593Smuzhiyun 			struct wl_join_params join_params;
6119*4882a593Smuzhiyun 			// need to up before setting ssid
6120*4882a593Smuzhiyun 			memset(&join_params, 0, sizeof(join_params));
6121*4882a593Smuzhiyun 			join_params.ssid.SSID_len = strlen(cur_if->ssid);
6122*4882a593Smuzhiyun 			memcpy((void *)join_params.ssid.SSID, cur_if->ssid, strlen(cur_if->ssid));
6123*4882a593Smuzhiyun 			join_params.params.chanspec_list[0] = fw_chspec;
6124*4882a593Smuzhiyun 			join_params.params.chanspec_num = 1;
6125*4882a593Smuzhiyun 			wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &join_params, sizeof(join_params), 1);
6126*4882a593Smuzhiyun 		} else {
6127*4882a593Smuzhiyun 			IAPSTA_ERROR(cur_if->ifname, "wrong ifmode %d\n", cur_if->ifmode);
6128*4882a593Smuzhiyun 		}
6129*4882a593Smuzhiyun #endif /* WLMESH */
6130*4882a593Smuzhiyun 	}
6131*4882a593Smuzhiyun 
6132*4882a593Smuzhiyun 	if (wait_up) {
6133*4882a593Smuzhiyun 		OSL_SLEEP(wait_up);
6134*4882a593Smuzhiyun 	} else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
6135*4882a593Smuzhiyun 		timeout = wait_event_interruptible_timeout(apsta_params->netif_change_event,
6136*4882a593Smuzhiyun 			wl_get_isam_status(cur_if, AP_CREATED),
6137*4882a593Smuzhiyun 			msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
6138*4882a593Smuzhiyun 		if (timeout <= 0 || !wl_get_isam_status(cur_if, AP_CREATED)) {
6139*4882a593Smuzhiyun 			if (lock)
6140*4882a593Smuzhiyun 				mutex_unlock(&apsta_params->usr_sync);
6141*4882a593Smuzhiyun 			wl_ext_disable_iface(dev, cur_if->ifname);
6142*4882a593Smuzhiyun 			WL_MSG(ifname, "[%c] failed to enable with SSID: \"%s\"\n",
6143*4882a593Smuzhiyun 				cur_if->prefix, cur_if->ssid);
6144*4882a593Smuzhiyun 			ret = -1;
6145*4882a593Smuzhiyun 		}
6146*4882a593Smuzhiyun 	}
6147*4882a593Smuzhiyun 
6148*4882a593Smuzhiyun 	if (wl_get_isam_status(cur_if, AP_CREATED) &&
6149*4882a593Smuzhiyun 			(cur_if->ifmode == IMESH_MODE || cur_if->ifmode == IAP_MODE) &&
6150*4882a593Smuzhiyun 			(apstamode == ISTAAP_MODE || apstamode == ISTAAPAP_MODE ||
6151*4882a593Smuzhiyun 			apstamode == ISTAMESH_MODE || apstamode == IMESHAP_MODE ||
6152*4882a593Smuzhiyun 			apstamode == ISTAAPMESH_MODE || apstamode == IMESHAPAP_MODE)) {
6153*4882a593Smuzhiyun 		wl_ext_set_scan_time(cur_if->dev, 80,
6154*4882a593Smuzhiyun 			WLC_GET_SCAN_CHANNEL_TIME, WLC_SET_SCAN_CHANNEL_TIME);
6155*4882a593Smuzhiyun 	}
6156*4882a593Smuzhiyun 
6157*4882a593Smuzhiyun 	wl_ext_isam_status(cur_if->dev, NULL, 0);
6158*4882a593Smuzhiyun 
6159*4882a593Smuzhiyun exit:
6160*4882a593Smuzhiyun 	if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
6161*4882a593Smuzhiyun 		wl_clr_isam_status(cur_if, AP_CREATING);
6162*4882a593Smuzhiyun 	}
6163*4882a593Smuzhiyun 	WL_MSG(ifname, "[%c] Exit ret=%d\n", cur_if->prefix, ret);
6164*4882a593Smuzhiyun 	if (lock)
6165*4882a593Smuzhiyun 		mutex_unlock(&apsta_params->usr_sync);
6166*4882a593Smuzhiyun 	return ret;
6167*4882a593Smuzhiyun }
6168*4882a593Smuzhiyun 
6169*4882a593Smuzhiyun int
wl_ext_isam_dev_status(struct net_device * dev,ifmode_t ifmode,char prefix,char * dump_buf,int dump_len)6170*4882a593Smuzhiyun wl_ext_isam_dev_status(struct net_device *dev, ifmode_t ifmode, char prefix,
6171*4882a593Smuzhiyun 	char *dump_buf, int dump_len)
6172*4882a593Smuzhiyun {
6173*4882a593Smuzhiyun 	struct wl_chan_info chan_info;
6174*4882a593Smuzhiyun 	wlc_ssid_t ssid = { 0, {0} };
6175*4882a593Smuzhiyun 	struct ether_addr bssid;
6176*4882a593Smuzhiyun 	scb_val_t scb_val;
6177*4882a593Smuzhiyun 	char sec[64];
6178*4882a593Smuzhiyun 	u32 chanspec = 0;
6179*4882a593Smuzhiyun 	int dump_written = 0;
6180*4882a593Smuzhiyun 
6181*4882a593Smuzhiyun 	if (dev) {
6182*4882a593Smuzhiyun 		memset(&ssid, 0, sizeof(ssid));
6183*4882a593Smuzhiyun 		memset(&bssid, 0, sizeof(bssid));
6184*4882a593Smuzhiyun 		memset(&scb_val, 0, sizeof(scb_val));
6185*4882a593Smuzhiyun 		memset(&chan_info, 0, sizeof(struct wl_chan_info));
6186*4882a593Smuzhiyun 		if (wl_ext_associated(dev)) {
6187*4882a593Smuzhiyun 			wl_ext_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0);
6188*4882a593Smuzhiyun 			wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
6189*4882a593Smuzhiyun 			wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0);
6190*4882a593Smuzhiyun 			chanspec = wl_ext_get_chanspec(dev, &chan_info);
6191*4882a593Smuzhiyun 			wl_ext_get_sec(dev, ifmode, sec, sizeof(sec), FALSE);
6192*4882a593Smuzhiyun 			dump_written += snprintf(dump_buf+dump_written, dump_len,
6193*4882a593Smuzhiyun 				"\n" DHD_LOG_PREFIXS "[%s-%c]: bssid=%pM, chan=%s-%-3d(0x%x %sMHz), "
6194*4882a593Smuzhiyun 				"rssi=%3d, sec=%-20s, SSID=\"%s\"",
6195*4882a593Smuzhiyun 				dev->name, prefix, &bssid,
6196*4882a593Smuzhiyun 				WLCBAND2STR(chan_info.band), chan_info.chan, chanspec,
6197*4882a593Smuzhiyun 				CHSPEC_IS20(chanspec)?"20":
6198*4882a593Smuzhiyun 				CHSPEC_IS40(chanspec)?"40":
6199*4882a593Smuzhiyun 				CHSPEC_IS80(chanspec)?"80":"160",
6200*4882a593Smuzhiyun 				dtoh32(scb_val.val), sec, ssid.SSID);
6201*4882a593Smuzhiyun 			if (ifmode == IAP_MODE) {
6202*4882a593Smuzhiyun 				dump_written += wl_ext_assoclist(dev, NULL,
6203*4882a593Smuzhiyun 					dump_buf+dump_written, dump_len-dump_written);
6204*4882a593Smuzhiyun 			}
6205*4882a593Smuzhiyun #ifdef WLMESH
6206*4882a593Smuzhiyun 			else if (ifmode == IMESH_MODE) {
6207*4882a593Smuzhiyun 				dump_written += snprintf(dump_buf+dump_written, dump_len, "\n");
6208*4882a593Smuzhiyun 				dump_written += wl_ext_mesh_peer_status(dev, NULL,
6209*4882a593Smuzhiyun 					dump_buf+dump_written, dump_len-dump_written);
6210*4882a593Smuzhiyun 			}
6211*4882a593Smuzhiyun #endif /* WLMESH */
6212*4882a593Smuzhiyun 		} else {
6213*4882a593Smuzhiyun 			dump_written += snprintf(dump_buf+dump_written, dump_len,
6214*4882a593Smuzhiyun 				"\n" DHD_LOG_PREFIXS "[%s-%c]:", dev->name, prefix);
6215*4882a593Smuzhiyun 		}
6216*4882a593Smuzhiyun 	}
6217*4882a593Smuzhiyun 
6218*4882a593Smuzhiyun 	return dump_written;
6219*4882a593Smuzhiyun }
6220*4882a593Smuzhiyun 
6221*4882a593Smuzhiyun int
wl_ext_isam_status(struct net_device * dev,char * command,int total_len)6222*4882a593Smuzhiyun wl_ext_isam_status(struct net_device *dev, char *command, int total_len)
6223*4882a593Smuzhiyun {
6224*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
6225*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6226*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
6227*4882a593Smuzhiyun 	char *dump_buf = NULL;
6228*4882a593Smuzhiyun 	int dump_len = WLC_IOCTL_MEDLEN, dump_written = 0;
6229*4882a593Smuzhiyun 	int i;
6230*4882a593Smuzhiyun 
6231*4882a593Smuzhiyun 	if (command || android_msg_level & ANDROID_INFO_LEVEL) {
6232*4882a593Smuzhiyun 		if (command) {
6233*4882a593Smuzhiyun 			dump_buf = command;
6234*4882a593Smuzhiyun 			dump_len = total_len;
6235*4882a593Smuzhiyun 		} else {
6236*4882a593Smuzhiyun 			dump_buf = kmalloc(dump_len, GFP_KERNEL);
6237*4882a593Smuzhiyun 			if (dump_buf == NULL) {
6238*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n",
6239*4882a593Smuzhiyun 					dump_len);
6240*4882a593Smuzhiyun 				return -1;
6241*4882a593Smuzhiyun 			}
6242*4882a593Smuzhiyun 			memset(dump_buf, 0, dump_len);
6243*4882a593Smuzhiyun 		}
6244*4882a593Smuzhiyun 		dump_written += snprintf(dump_buf+dump_written, dump_len,
6245*4882a593Smuzhiyun 			"apstamode=%d", apsta_params->apstamode);
6246*4882a593Smuzhiyun 		for (i=0; i<MAX_IF_NUM; i++) {
6247*4882a593Smuzhiyun 			cur_if = &apsta_params->if_info[i];
6248*4882a593Smuzhiyun 			if (cur_if->dev) {
6249*4882a593Smuzhiyun 				dump_written += wl_ext_isam_dev_status(cur_if->dev,
6250*4882a593Smuzhiyun 					cur_if->ifmode, cur_if->prefix,
6251*4882a593Smuzhiyun 					dump_buf+dump_written, dump_len-dump_written);
6252*4882a593Smuzhiyun 			}
6253*4882a593Smuzhiyun #ifdef WLDWDS
6254*4882a593Smuzhiyun 			if (cur_if->ifmode == IAP_MODE) {
6255*4882a593Smuzhiyun 				for (i=0; i<MAX_DWDS_IF_NUM; i++) {
6256*4882a593Smuzhiyun 					if (apsta_params->dwds_info[i].dev) {
6257*4882a593Smuzhiyun 						dump_written += wl_ext_isam_dev_status(apsta_params->dwds_info[i].dev,
6258*4882a593Smuzhiyun 							IAP_MODE, 'W',
6259*4882a593Smuzhiyun 							dump_buf+dump_written, dump_len-dump_written);
6260*4882a593Smuzhiyun 					}
6261*4882a593Smuzhiyun 				}
6262*4882a593Smuzhiyun 			}
6263*4882a593Smuzhiyun #endif /* WLDWDS */
6264*4882a593Smuzhiyun 		}
6265*4882a593Smuzhiyun 		IAPSTA_INFO(dev->name, "%s\n", dump_buf);
6266*4882a593Smuzhiyun 	}
6267*4882a593Smuzhiyun 
6268*4882a593Smuzhiyun 	if (!command && dump_buf)
6269*4882a593Smuzhiyun 		kfree(dump_buf);
6270*4882a593Smuzhiyun 	return dump_written;
6271*4882a593Smuzhiyun }
6272*4882a593Smuzhiyun 
6273*4882a593Smuzhiyun int
wl_ext_isam_param(struct net_device * dev,char * command,int total_len)6274*4882a593Smuzhiyun wl_ext_isam_param(struct net_device *dev, char *command, int total_len)
6275*4882a593Smuzhiyun {
6276*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
6277*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6278*4882a593Smuzhiyun 	int ret = -1;
6279*4882a593Smuzhiyun 	char *pick_tmp, *data, *param;
6280*4882a593Smuzhiyun 	int bytes_written=-1;
6281*4882a593Smuzhiyun 
6282*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "command=%s, len=%d\n", command, total_len);
6283*4882a593Smuzhiyun 
6284*4882a593Smuzhiyun 	pick_tmp = command;
6285*4882a593Smuzhiyun 	param = bcmstrtok(&pick_tmp, " ", 0); // pick isam_param
6286*4882a593Smuzhiyun 	param = bcmstrtok(&pick_tmp, " ", 0); // pick cmd
6287*4882a593Smuzhiyun 	while (param != NULL) {
6288*4882a593Smuzhiyun 		data = bcmstrtok(&pick_tmp, " ", 0); // pick data
6289*4882a593Smuzhiyun 		if (!strcmp(param, "acs")) {
6290*4882a593Smuzhiyun 			if (data) {
6291*4882a593Smuzhiyun 				apsta_params->acs = simple_strtol(data, NULL, 0);
6292*4882a593Smuzhiyun 				ret = 0;
6293*4882a593Smuzhiyun 			} else {
6294*4882a593Smuzhiyun 				bytes_written = snprintf(command, total_len, "%d", apsta_params->acs);
6295*4882a593Smuzhiyun 				ret = bytes_written;
6296*4882a593Smuzhiyun 				goto exit;
6297*4882a593Smuzhiyun 			}
6298*4882a593Smuzhiyun 		}
6299*4882a593Smuzhiyun #ifdef ACS_MONITOR
6300*4882a593Smuzhiyun 		else if (!strcmp(param, "acs_tmo")) {
6301*4882a593Smuzhiyun 			if (data) {
6302*4882a593Smuzhiyun 				struct wl_if_info *cur_if = NULL;
6303*4882a593Smuzhiyun 				uint acs_tmo;
6304*4882a593Smuzhiyun 				cur_if = wl_get_cur_if(dev);
6305*4882a593Smuzhiyun 				if (!cur_if)
6306*4882a593Smuzhiyun 					goto exit;
6307*4882a593Smuzhiyun 				acs_tmo = simple_strtol(data, NULL, 0);
6308*4882a593Smuzhiyun 				if (apsta_params->acs_tmo != acs_tmo) {
6309*4882a593Smuzhiyun 					apsta_params->acs_tmo = acs_tmo;
6310*4882a593Smuzhiyun 					WL_MSG(dev->name, "acs_timer reset to %d\n", acs_tmo);
6311*4882a593Smuzhiyun 					wl_timer_mod(dhd, &cur_if->acs_timer, 0);
6312*4882a593Smuzhiyun 				}
6313*4882a593Smuzhiyun 				ret = 0;
6314*4882a593Smuzhiyun 			} else {
6315*4882a593Smuzhiyun 				bytes_written = snprintf(command, total_len, "%d", apsta_params->acs_tmo);
6316*4882a593Smuzhiyun 				ret = bytes_written;
6317*4882a593Smuzhiyun 				goto exit;
6318*4882a593Smuzhiyun 			}
6319*4882a593Smuzhiyun 		}
6320*4882a593Smuzhiyun #endif /* ACS_MONITOR */
6321*4882a593Smuzhiyun 		param = bcmstrtok(&pick_tmp, " ", 0); // pick cmd
6322*4882a593Smuzhiyun 	}
6323*4882a593Smuzhiyun 
6324*4882a593Smuzhiyun exit:
6325*4882a593Smuzhiyun 	return ret;
6326*4882a593Smuzhiyun }
6327*4882a593Smuzhiyun 
6328*4882a593Smuzhiyun int
wl_ext_iapsta_disable(struct net_device * dev,char * command,int total_len)6329*4882a593Smuzhiyun wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
6330*4882a593Smuzhiyun {
6331*4882a593Smuzhiyun 	int ret = 0;
6332*4882a593Smuzhiyun 	char *pch, *pick_tmp, *param;
6333*4882a593Smuzhiyun 	char ifname[IFNAMSIZ+1];
6334*4882a593Smuzhiyun 
6335*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "command=%s, len=%d\n", command, total_len);
6336*4882a593Smuzhiyun 
6337*4882a593Smuzhiyun 	pick_tmp = command;
6338*4882a593Smuzhiyun 	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_disable
6339*4882a593Smuzhiyun 	param = bcmstrtok(&pick_tmp, " ", 0);
6340*4882a593Smuzhiyun 	while (param != NULL) {
6341*4882a593Smuzhiyun 		if (!strcmp(param, "ifname")) {
6342*4882a593Smuzhiyun 			pch = bcmstrtok(&pick_tmp, " ", 0);
6343*4882a593Smuzhiyun 			if (pch) {
6344*4882a593Smuzhiyun 				strcpy(ifname, pch);
6345*4882a593Smuzhiyun 				ret = wl_ext_disable_iface(dev, ifname);
6346*4882a593Smuzhiyun 				if (ret)
6347*4882a593Smuzhiyun 					return ret;
6348*4882a593Smuzhiyun 			}
6349*4882a593Smuzhiyun 			else {
6350*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "ifname [wlanX]\n");
6351*4882a593Smuzhiyun 				return -1;
6352*4882a593Smuzhiyun 			}
6353*4882a593Smuzhiyun 		}
6354*4882a593Smuzhiyun 		param = bcmstrtok(&pick_tmp, " ", 0);
6355*4882a593Smuzhiyun 	}
6356*4882a593Smuzhiyun 
6357*4882a593Smuzhiyun 	return ret;
6358*4882a593Smuzhiyun }
6359*4882a593Smuzhiyun 
6360*4882a593Smuzhiyun int
wl_ext_iapsta_enable(struct net_device * dev,char * command,int total_len)6361*4882a593Smuzhiyun wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len)
6362*4882a593Smuzhiyun {
6363*4882a593Smuzhiyun 	int ret = 0;
6364*4882a593Smuzhiyun 	char *pch, *pick_tmp, *param;
6365*4882a593Smuzhiyun 	char ifname[IFNAMSIZ+1];
6366*4882a593Smuzhiyun 
6367*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "command=%s, len=%d\n", command, total_len);
6368*4882a593Smuzhiyun 
6369*4882a593Smuzhiyun 	pick_tmp = command;
6370*4882a593Smuzhiyun 	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_enable
6371*4882a593Smuzhiyun 	param = bcmstrtok(&pick_tmp, " ", 0);
6372*4882a593Smuzhiyun 	while (param != NULL) {
6373*4882a593Smuzhiyun 		if (!strcmp(param, "ifname")) {
6374*4882a593Smuzhiyun 			pch = bcmstrtok(&pick_tmp, " ", 0);
6375*4882a593Smuzhiyun 			if (pch) {
6376*4882a593Smuzhiyun 				strcpy(ifname, pch);
6377*4882a593Smuzhiyun 				ret = wl_ext_enable_iface(dev, ifname, 0, TRUE);
6378*4882a593Smuzhiyun 				if (ret)
6379*4882a593Smuzhiyun 					return ret;
6380*4882a593Smuzhiyun 			} else {
6381*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "ifname [wlanX]\n");
6382*4882a593Smuzhiyun 				return -1;
6383*4882a593Smuzhiyun 			}
6384*4882a593Smuzhiyun 		}
6385*4882a593Smuzhiyun 		param = bcmstrtok(&pick_tmp, " ", 0);
6386*4882a593Smuzhiyun 	}
6387*4882a593Smuzhiyun 
6388*4882a593Smuzhiyun 	return ret;
6389*4882a593Smuzhiyun }
6390*4882a593Smuzhiyun 
6391*4882a593Smuzhiyun int
wl_ext_iapsta_config(struct net_device * dev,char * command,int total_len)6392*4882a593Smuzhiyun wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len)
6393*4882a593Smuzhiyun {
6394*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
6395*4882a593Smuzhiyun 	int ret=0, i;
6396*4882a593Smuzhiyun 	char *pch, *pch2, *pick_tmp, *pick_next=NULL, *param;
6397*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6398*4882a593Smuzhiyun 	char ifname[IFNAMSIZ+1];
6399*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL, *tmp_if = NULL;
6400*4882a593Smuzhiyun 
6401*4882a593Smuzhiyun 	if (!apsta_params->init) {
6402*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "please init first\n");
6403*4882a593Smuzhiyun 		return -1;
6404*4882a593Smuzhiyun 	}
6405*4882a593Smuzhiyun 
6406*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "command=%s, len=%d\n", command, total_len);
6407*4882a593Smuzhiyun 
6408*4882a593Smuzhiyun 	pick_tmp = command;
6409*4882a593Smuzhiyun 	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_config
6410*4882a593Smuzhiyun 
6411*4882a593Smuzhiyun 	mutex_lock(&apsta_params->usr_sync);
6412*4882a593Smuzhiyun 
6413*4882a593Smuzhiyun 	while (pick_tmp != NULL) {
6414*4882a593Smuzhiyun 		memset(ifname, 0, IFNAMSIZ+1);
6415*4882a593Smuzhiyun 		if (!strncmp(pick_tmp, "ifname ", strlen("ifname "))) {
6416*4882a593Smuzhiyun 			pch = pick_tmp + strlen("ifname ");
6417*4882a593Smuzhiyun 			pch2 = strchr(pch, ' ');
6418*4882a593Smuzhiyun 			if (pch && pch2) {
6419*4882a593Smuzhiyun 				strncpy(ifname, pch, pch2-pch);
6420*4882a593Smuzhiyun 			} else {
6421*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "ifname [wlanX]\n");
6422*4882a593Smuzhiyun 				ret = -1;
6423*4882a593Smuzhiyun 				break;
6424*4882a593Smuzhiyun 			}
6425*4882a593Smuzhiyun 			for (i=0; i<MAX_IF_NUM; i++) {
6426*4882a593Smuzhiyun 				tmp_if = &apsta_params->if_info[i];
6427*4882a593Smuzhiyun 				if (tmp_if->dev && !strcmp(tmp_if->dev->name, ifname)) {
6428*4882a593Smuzhiyun 					cur_if = tmp_if;
6429*4882a593Smuzhiyun 					break;
6430*4882a593Smuzhiyun 				}
6431*4882a593Smuzhiyun 			}
6432*4882a593Smuzhiyun 			if (!cur_if) {
6433*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "wrong ifname=%s in apstamode=%d\n",
6434*4882a593Smuzhiyun 					ifname, apsta_params->apstamode);
6435*4882a593Smuzhiyun 				ret = -1;
6436*4882a593Smuzhiyun 				break;
6437*4882a593Smuzhiyun 			}
6438*4882a593Smuzhiyun 			ret = wl_ext_parse_config(cur_if, pick_tmp, &pick_next);
6439*4882a593Smuzhiyun 			if (ret)
6440*4882a593Smuzhiyun 				break;
6441*4882a593Smuzhiyun 			pick_tmp = pick_next;
6442*4882a593Smuzhiyun 		} else {
6443*4882a593Smuzhiyun 			IAPSTA_ERROR(dev->name, "first arg must be ifname\n");
6444*4882a593Smuzhiyun 			ret = -1;
6445*4882a593Smuzhiyun 			break;
6446*4882a593Smuzhiyun 		}
6447*4882a593Smuzhiyun 
6448*4882a593Smuzhiyun 	}
6449*4882a593Smuzhiyun 
6450*4882a593Smuzhiyun 	mutex_unlock(&apsta_params->usr_sync);
6451*4882a593Smuzhiyun 
6452*4882a593Smuzhiyun 	return ret;
6453*4882a593Smuzhiyun }
6454*4882a593Smuzhiyun 
6455*4882a593Smuzhiyun int
wl_ext_isam_init(struct net_device * dev,char * command,int total_len)6456*4882a593Smuzhiyun wl_ext_isam_init(struct net_device *dev, char *command, int total_len)
6457*4882a593Smuzhiyun {
6458*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
6459*4882a593Smuzhiyun 	char *pch, *pick_tmp, *pick_tmp2, *param;
6460*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6461*4882a593Smuzhiyun 	int i;
6462*4882a593Smuzhiyun 
6463*4882a593Smuzhiyun 	if (apsta_params->init) {
6464*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "don't init twice\n");
6465*4882a593Smuzhiyun 		return -1;
6466*4882a593Smuzhiyun 	}
6467*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "command=%s, len=%d\n", command, total_len);
6468*4882a593Smuzhiyun 
6469*4882a593Smuzhiyun 	pick_tmp = command;
6470*4882a593Smuzhiyun 	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_init
6471*4882a593Smuzhiyun 	param = bcmstrtok(&pick_tmp, " ", 0);
6472*4882a593Smuzhiyun 	while (param != NULL) {
6473*4882a593Smuzhiyun 		pick_tmp2 = bcmstrtok(&pick_tmp, " ", 0);
6474*4882a593Smuzhiyun 		if (!pick_tmp2) {
6475*4882a593Smuzhiyun 			IAPSTA_ERROR(dev->name, "wrong param %s\n", param);
6476*4882a593Smuzhiyun 			return -1;
6477*4882a593Smuzhiyun 		}
6478*4882a593Smuzhiyun 		if (!strcmp(param, "mode")) {
6479*4882a593Smuzhiyun 			pch = NULL;
6480*4882a593Smuzhiyun 			if (!strcmp(pick_tmp2, "sta")) {
6481*4882a593Smuzhiyun 				apsta_params->apstamode = ISTAONLY_MODE;
6482*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "ap")) {
6483*4882a593Smuzhiyun 				apsta_params->apstamode = IAPONLY_MODE;
6484*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "sta-ap")) {
6485*4882a593Smuzhiyun 				apsta_params->apstamode = ISTAAP_MODE;
6486*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "sta-sta")) {
6487*4882a593Smuzhiyun 				apsta_params->apstamode = ISTASTA_MODE;
6488*4882a593Smuzhiyun 				apsta_params->vsdb = TRUE;
6489*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "ap-ap")) {
6490*4882a593Smuzhiyun 				apsta_params->apstamode = IDUALAP_MODE;
6491*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "sta-ap-ap")) {
6492*4882a593Smuzhiyun 				apsta_params->apstamode = ISTAAPAP_MODE;
6493*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "apsta")) {
6494*4882a593Smuzhiyun 				apsta_params->apstamode = ISTAAP_MODE;
6495*4882a593Smuzhiyun 				apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE;
6496*4882a593Smuzhiyun 				apsta_params->if_info[IF_VIF].ifmode = IAP_MODE;
6497*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "dualap")) {
6498*4882a593Smuzhiyun 				apsta_params->apstamode = IDUALAP_MODE;
6499*4882a593Smuzhiyun 				apsta_params->if_info[IF_PIF].ifmode = IAP_MODE;
6500*4882a593Smuzhiyun 				apsta_params->if_info[IF_VIF].ifmode = IAP_MODE;
6501*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "sta-go") ||
6502*4882a593Smuzhiyun 					!strcmp(pick_tmp2, "gosta")) {
6503*4882a593Smuzhiyun 				if (!FW_SUPPORTED(dhd, p2p)) {
6504*4882a593Smuzhiyun 					return -1;
6505*4882a593Smuzhiyun 				}
6506*4882a593Smuzhiyun 				apsta_params->apstamode = ISTAGO_MODE;
6507*4882a593Smuzhiyun 				apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE;
6508*4882a593Smuzhiyun 				apsta_params->if_info[IF_VIF].ifmode = IAP_MODE;
6509*4882a593Smuzhiyun #ifdef WLMESH
6510*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "mesh")) {
6511*4882a593Smuzhiyun 				apsta_params->apstamode = IMESHONLY_MODE;
6512*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "sta-mesh")) {
6513*4882a593Smuzhiyun 				apsta_params->apstamode = ISTAMESH_MODE;
6514*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "sta-ap-mesh")) {
6515*4882a593Smuzhiyun 				apsta_params->apstamode = ISTAAPMESH_MODE;
6516*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "mesh-ap")) {
6517*4882a593Smuzhiyun 				apsta_params->apstamode = IMESHAP_MODE;
6518*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "mesh-ap-ap")) {
6519*4882a593Smuzhiyun 				apsta_params->apstamode = IMESHAPAP_MODE;
6520*4882a593Smuzhiyun #endif /* WLMESH */
6521*4882a593Smuzhiyun 			} else {
6522*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "mode [sta|ap|sta-ap|ap-ap]\n");
6523*4882a593Smuzhiyun 				return -1;
6524*4882a593Smuzhiyun 			}
6525*4882a593Smuzhiyun 			pch = bcmstrtok(&pick_tmp2, " -", 0);
6526*4882a593Smuzhiyun 			for (i=0; i<MAX_IF_NUM && pch; i++) {
6527*4882a593Smuzhiyun 				if (!strcmp(pch, "sta"))
6528*4882a593Smuzhiyun 					apsta_params->if_info[i].ifmode = ISTA_MODE;
6529*4882a593Smuzhiyun 				else if (!strcmp(pch, "ap"))
6530*4882a593Smuzhiyun 					apsta_params->if_info[i].ifmode = IAP_MODE;
6531*4882a593Smuzhiyun #ifdef WLMESH
6532*4882a593Smuzhiyun 				else if (!strcmp(pch, "mesh")) {
6533*4882a593Smuzhiyun 					if (dhd->conf->fw_type != FW_TYPE_MESH) {
6534*4882a593Smuzhiyun 						IAPSTA_ERROR(dev->name, "wrong fw type\n");
6535*4882a593Smuzhiyun 						return -1;
6536*4882a593Smuzhiyun 					}
6537*4882a593Smuzhiyun 					apsta_params->if_info[i].ifmode = IMESH_MODE;
6538*4882a593Smuzhiyun 				}
6539*4882a593Smuzhiyun #endif /* WLMESH */
6540*4882a593Smuzhiyun 				pch = bcmstrtok(&pick_tmp2, " -", 0);
6541*4882a593Smuzhiyun 			}
6542*4882a593Smuzhiyun 		}
6543*4882a593Smuzhiyun 		else if (!strcmp(param, "rsdb")) {
6544*4882a593Smuzhiyun 			apsta_params->rsdb = (int)simple_strtol(pick_tmp2, NULL, 0);
6545*4882a593Smuzhiyun 		} else if (!strcmp(param, "vsdb")) {
6546*4882a593Smuzhiyun 			if (!strcmp(pick_tmp2, "y")) {
6547*4882a593Smuzhiyun 				apsta_params->vsdb = TRUE;
6548*4882a593Smuzhiyun 			} else if (!strcmp(pick_tmp2, "n")) {
6549*4882a593Smuzhiyun 				apsta_params->vsdb = FALSE;
6550*4882a593Smuzhiyun 			} else {
6551*4882a593Smuzhiyun 				IAPSTA_ERROR(dev->name, "vsdb [y|n]\n");
6552*4882a593Smuzhiyun 				return -1;
6553*4882a593Smuzhiyun 			}
6554*4882a593Smuzhiyun 		} else if (!strcmp(param, "csa")) {
6555*4882a593Smuzhiyun 			apsta_params->csa = (int)simple_strtol(pick_tmp2, NULL, 0);
6556*4882a593Smuzhiyun 		} else if (!strcmp(param, "acs")) {
6557*4882a593Smuzhiyun 			apsta_params->acs = (int)simple_strtol(pick_tmp2, NULL, 0);
6558*4882a593Smuzhiyun #if defined(WLMESH) && defined(WL_ESCAN)
6559*4882a593Smuzhiyun 		} else if (!strcmp(param, "macs")) {
6560*4882a593Smuzhiyun 			apsta_params->macs = (int)simple_strtol(pick_tmp2, NULL, 0);
6561*4882a593Smuzhiyun #endif /* WLMESH && WL_ESCAN */
6562*4882a593Smuzhiyun 		} else if (!strcmp(param, "ifname")) {
6563*4882a593Smuzhiyun 			pch = NULL;
6564*4882a593Smuzhiyun 			pch = bcmstrtok(&pick_tmp2, " -", 0);
6565*4882a593Smuzhiyun 			for (i=0; i<MAX_IF_NUM && pch; i++) {
6566*4882a593Smuzhiyun 				strcpy(apsta_params->if_info[i].ifname, pch);
6567*4882a593Smuzhiyun 				pch = bcmstrtok(&pick_tmp2, " -", 0);
6568*4882a593Smuzhiyun 			}
6569*4882a593Smuzhiyun 		} else if (!strcmp(param, "vifname")) {
6570*4882a593Smuzhiyun 			strcpy(apsta_params->if_info[IF_VIF].ifname, pick_tmp2);
6571*4882a593Smuzhiyun 		}
6572*4882a593Smuzhiyun 		param = bcmstrtok(&pick_tmp, " ", 0);
6573*4882a593Smuzhiyun 	}
6574*4882a593Smuzhiyun 
6575*4882a593Smuzhiyun 	if (apsta_params->apstamode == 0) {
6576*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "mode [sta|ap|sta-ap|ap-ap]\n");
6577*4882a593Smuzhiyun 		return -1;
6578*4882a593Smuzhiyun 	}
6579*4882a593Smuzhiyun 
6580*4882a593Smuzhiyun 	wl_ext_iapsta_preinit(dev, apsta_params);
6581*4882a593Smuzhiyun #ifndef WL_STATIC_IF
6582*4882a593Smuzhiyun 	wl_ext_iapsta_intf_add(dev, apsta_params);
6583*4882a593Smuzhiyun #endif /* WL_STATIC_IF */
6584*4882a593Smuzhiyun 
6585*4882a593Smuzhiyun 	return 0;
6586*4882a593Smuzhiyun }
6587*4882a593Smuzhiyun 
6588*4882a593Smuzhiyun int
wl_ext_iapsta_alive_preinit(struct net_device * dev)6589*4882a593Smuzhiyun wl_ext_iapsta_alive_preinit(struct net_device *dev)
6590*4882a593Smuzhiyun {
6591*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
6592*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6593*4882a593Smuzhiyun 
6594*4882a593Smuzhiyun 	if (apsta_params->init == TRUE) {
6595*4882a593Smuzhiyun 		IAPSTA_ERROR(dev->name, "don't init twice\n");
6596*4882a593Smuzhiyun 		return -1;
6597*4882a593Smuzhiyun 	}
6598*4882a593Smuzhiyun 
6599*4882a593Smuzhiyun 	IAPSTA_TRACE(dev->name, "Enter\n");
6600*4882a593Smuzhiyun 
6601*4882a593Smuzhiyun 	apsta_params->init = TRUE;
6602*4882a593Smuzhiyun 
6603*4882a593Smuzhiyun 	return 0;
6604*4882a593Smuzhiyun }
6605*4882a593Smuzhiyun 
6606*4882a593Smuzhiyun int
wl_ext_iapsta_alive_postinit(struct net_device * dev)6607*4882a593Smuzhiyun wl_ext_iapsta_alive_postinit(struct net_device *dev)
6608*4882a593Smuzhiyun {
6609*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(dev);
6610*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6611*4882a593Smuzhiyun 	s32 apsta = 0, ap = 0;
6612*4882a593Smuzhiyun 	struct wl_if_info *cur_if;
6613*4882a593Smuzhiyun 	int i;
6614*4882a593Smuzhiyun 
6615*4882a593Smuzhiyun 	wl_ext_iovar_getint(dev, "apsta", &apsta);
6616*4882a593Smuzhiyun 	wl_ext_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap), 0);
6617*4882a593Smuzhiyun 	if (apsta == 1 || ap == 0) {
6618*4882a593Smuzhiyun 		apsta_params->apstamode = ISTAONLY_MODE;
6619*4882a593Smuzhiyun 		apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE;
6620*4882a593Smuzhiyun 		op_mode = DHD_FLAG_STA_MODE;
6621*4882a593Smuzhiyun 	} else {
6622*4882a593Smuzhiyun 		apsta_params->apstamode = IAPONLY_MODE;
6623*4882a593Smuzhiyun 		apsta_params->if_info[IF_PIF].ifmode = IAP_MODE;
6624*4882a593Smuzhiyun 		op_mode = DHD_FLAG_HOSTAP_MODE;
6625*4882a593Smuzhiyun 	}
6626*4882a593Smuzhiyun 	// fix me: how to check it's ISTAAP_MODE or IDUALAP_MODE?
6627*4882a593Smuzhiyun 
6628*4882a593Smuzhiyun 	WL_MSG(dev->name, "apstamode=%d\n", apsta_params->apstamode);
6629*4882a593Smuzhiyun 
6630*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
6631*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[i];
6632*4882a593Smuzhiyun 		if (i == 1 && !strlen(cur_if->ifname))
6633*4882a593Smuzhiyun 			strcpy(cur_if->ifname, "wlan1");
6634*4882a593Smuzhiyun 		if (i == 2 && !strlen(cur_if->ifname))
6635*4882a593Smuzhiyun 			strcpy(cur_if->ifname, "wlan2");
6636*4882a593Smuzhiyun 		if (cur_if->ifmode == ISTA_MODE) {
6637*4882a593Smuzhiyun 			wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 0);
6638*4882a593Smuzhiyun 			cur_if->maxassoc = -1;
6639*4882a593Smuzhiyun 			wl_set_isam_status(cur_if, IF_READY);
6640*4882a593Smuzhiyun 			cur_if->prio = PRIO_STA;
6641*4882a593Smuzhiyun 			cur_if->vsdb = TRUE;
6642*4882a593Smuzhiyun 			cur_if->prefix = 'S';
6643*4882a593Smuzhiyun 			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta");
6644*4882a593Smuzhiyun 		}
6645*4882a593Smuzhiyun 		else if (cur_if->ifmode == IAP_MODE) {
6646*4882a593Smuzhiyun 			wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1);
6647*4882a593Smuzhiyun 			cur_if->maxassoc = -1;
6648*4882a593Smuzhiyun 			wl_set_isam_status(cur_if, IF_READY);
6649*4882a593Smuzhiyun 			cur_if->prio = PRIO_AP;
6650*4882a593Smuzhiyun 			cur_if->vsdb = FALSE;
6651*4882a593Smuzhiyun 			cur_if->prefix = 'A';
6652*4882a593Smuzhiyun 			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap");
6653*4882a593Smuzhiyun 		}
6654*4882a593Smuzhiyun #ifdef WLMESH
6655*4882a593Smuzhiyun 		else if (cur_if->ifmode == IMESH_MODE) {
6656*4882a593Smuzhiyun 			wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1);
6657*4882a593Smuzhiyun 			cur_if->maxassoc = -1;
6658*4882a593Smuzhiyun 			wl_set_isam_status(cur_if, IF_READY);
6659*4882a593Smuzhiyun 			cur_if->prio = PRIO_MESH;
6660*4882a593Smuzhiyun 			cur_if->vsdb = FALSE;
6661*4882a593Smuzhiyun 			cur_if->prefix = 'M';
6662*4882a593Smuzhiyun 			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh");
6663*4882a593Smuzhiyun 		}
6664*4882a593Smuzhiyun #endif /* WLMESH */
6665*4882a593Smuzhiyun 	}
6666*4882a593Smuzhiyun 
6667*4882a593Smuzhiyun 	return op_mode;
6668*4882a593Smuzhiyun }
6669*4882a593Smuzhiyun 
6670*4882a593Smuzhiyun static int
wl_ext_iapsta_get_rsdb(struct net_device * net,struct dhd_pub * dhd)6671*4882a593Smuzhiyun wl_ext_iapsta_get_rsdb(struct net_device *net, struct dhd_pub *dhd)
6672*4882a593Smuzhiyun {
6673*4882a593Smuzhiyun 	s8 iovar_buf[WLC_IOCTL_SMLEN];
6674*4882a593Smuzhiyun 	wl_config_t *rsdb_p;
6675*4882a593Smuzhiyun 	int ret = 0, rsdb = 0;
6676*4882a593Smuzhiyun 
6677*4882a593Smuzhiyun 	if (dhd->conf->chip == BCM4359_CHIP_ID || dhd->conf->chip == BCM4375_CHIP_ID) {
6678*4882a593Smuzhiyun 		ret = wldev_iovar_getbuf(net, "rsdb_mode", NULL, 0,
6679*4882a593Smuzhiyun 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
6680*4882a593Smuzhiyun 		if (!ret) {
6681*4882a593Smuzhiyun 			if (dhd->conf->fw_type == FW_TYPE_MESH) {
6682*4882a593Smuzhiyun 				rsdb = 1;
6683*4882a593Smuzhiyun 			} else {
6684*4882a593Smuzhiyun 				rsdb_p = (wl_config_t *) iovar_buf;
6685*4882a593Smuzhiyun 				rsdb = rsdb_p->status;
6686*4882a593Smuzhiyun 				IAPSTA_INFO(net->name, "config=%d, status=%d\n",
6687*4882a593Smuzhiyun 					rsdb_p->config, rsdb_p->status);
6688*4882a593Smuzhiyun 			}
6689*4882a593Smuzhiyun 		}
6690*4882a593Smuzhiyun 	}
6691*4882a593Smuzhiyun 
6692*4882a593Smuzhiyun 	IAPSTA_INFO(net->name, "rsdb_mode=%d\n", rsdb);
6693*4882a593Smuzhiyun 
6694*4882a593Smuzhiyun 	return rsdb;
6695*4882a593Smuzhiyun }
6696*4882a593Smuzhiyun 
6697*4882a593Smuzhiyun static void
wl_ext_iapsta_postinit(struct net_device * net,struct wl_if_info * cur_if)6698*4882a593Smuzhiyun wl_ext_iapsta_postinit(struct net_device *net, struct wl_if_info *cur_if)
6699*4882a593Smuzhiyun {
6700*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
6701*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6702*4882a593Smuzhiyun 	int pm;
6703*4882a593Smuzhiyun 
6704*4882a593Smuzhiyun 	IAPSTA_TRACE(cur_if->ifname, "ifidx=%d\n", cur_if->ifidx);
6705*4882a593Smuzhiyun 	if (cur_if->ifidx == 0) {
6706*4882a593Smuzhiyun 		apsta_params->rsdb = wl_ext_iapsta_get_rsdb(net, dhd);
6707*4882a593Smuzhiyun 		apsta_params->vsdb = FALSE;
6708*4882a593Smuzhiyun 		apsta_params->csa = 0;
6709*4882a593Smuzhiyun 		apsta_params->acs = 0;
6710*4882a593Smuzhiyun 		apsta_params->radar = wl_ext_radar_detect(net);
6711*4882a593Smuzhiyun 		if (dhd->conf->fw_type == FW_TYPE_MESH) {
6712*4882a593Smuzhiyun 			apsta_params->csa |= (CSA_FW_BIT | CSA_DRV_BIT);
6713*4882a593Smuzhiyun 		}
6714*4882a593Smuzhiyun 		cur_if->ifmode = ISTA_MODE;
6715*4882a593Smuzhiyun 		cur_if->prio = PRIO_STA;
6716*4882a593Smuzhiyun 		cur_if->vsdb = TRUE;
6717*4882a593Smuzhiyun 		cur_if->prefix = 'S';
6718*4882a593Smuzhiyun 		if (dhd->conf->vndr_ie_assocreq && strlen(dhd->conf->vndr_ie_assocreq))
6719*4882a593Smuzhiyun 			wl_ext_add_del_ie(net, VNDR_IE_ASSOCREQ_FLAG, dhd->conf->vndr_ie_assocreq, "add");
6720*4882a593Smuzhiyun 	} else {
6721*4882a593Smuzhiyun 		if (cur_if->ifmode == ISTA_MODE) {
6722*4882a593Smuzhiyun 			wl_ext_iovar_setint(cur_if->dev, "roam_off", dhd->conf->roam_off);
6723*4882a593Smuzhiyun 			wl_ext_iovar_setint(cur_if->dev, "bcn_timeout", dhd->conf->bcn_timeout);
6724*4882a593Smuzhiyun 			if (dhd->conf->pm >= 0)
6725*4882a593Smuzhiyun 				pm = dhd->conf->pm;
6726*4882a593Smuzhiyun 			else
6727*4882a593Smuzhiyun 				pm = PM_FAST;
6728*4882a593Smuzhiyun 			wl_ext_ioctl(cur_if->dev, WLC_SET_PM, &pm, sizeof(pm), 1);
6729*4882a593Smuzhiyun 			wl_ext_iovar_setint(cur_if->dev, "assoc_retry_max", 10);
6730*4882a593Smuzhiyun 		}
6731*4882a593Smuzhiyun #ifdef WLMESH
6732*4882a593Smuzhiyun 		else if (cur_if->ifmode == IMESH_MODE) {
6733*4882a593Smuzhiyun 			pm = 0;
6734*4882a593Smuzhiyun 			wl_ext_ioctl(cur_if->dev, WLC_SET_PM, &pm, sizeof(pm), 1);
6735*4882a593Smuzhiyun 		}
6736*4882a593Smuzhiyun #endif /* WLMESH */
6737*4882a593Smuzhiyun 	}
6738*4882a593Smuzhiyun #ifdef PROPTX_MAXCOUNT
6739*4882a593Smuzhiyun 	wl_ext_update_wlfc_maxcount(dhd);
6740*4882a593Smuzhiyun #endif /* PROPTX_MAXCOUNT */
6741*4882a593Smuzhiyun 
6742*4882a593Smuzhiyun }
6743*4882a593Smuzhiyun 
6744*4882a593Smuzhiyun void
wl_ext_iapsta_get_vif_macaddr(struct dhd_pub * dhd,int ifidx,u8 * mac_addr)6745*4882a593Smuzhiyun wl_ext_iapsta_get_vif_macaddr(struct dhd_pub *dhd, int ifidx, u8 *mac_addr)
6746*4882a593Smuzhiyun {
6747*4882a593Smuzhiyun 	if (ifidx >= 2) {
6748*4882a593Smuzhiyun 		IAPSTA_TRACE("wlan", "ifidx=%d\n", ifidx);
6749*4882a593Smuzhiyun 		mac_addr[0] |= 0x02;
6750*4882a593Smuzhiyun 		mac_addr[4] ^= 0x80;
6751*4882a593Smuzhiyun 		mac_addr[4] += ifidx;
6752*4882a593Smuzhiyun 		mac_addr[5] += (ifidx-1);
6753*4882a593Smuzhiyun 	}
6754*4882a593Smuzhiyun }
6755*4882a593Smuzhiyun 
6756*4882a593Smuzhiyun int
wl_ext_iapsta_attach_name(struct net_device * net,int ifidx)6757*4882a593Smuzhiyun wl_ext_iapsta_attach_name(struct net_device *net, int ifidx)
6758*4882a593Smuzhiyun {
6759*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
6760*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6761*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
6762*4882a593Smuzhiyun 
6763*4882a593Smuzhiyun 	if (ifidx < MAX_IF_NUM) {
6764*4882a593Smuzhiyun 		IAPSTA_TRACE(net->name, "ifidx=%d\n", ifidx);
6765*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[ifidx];
6766*4882a593Smuzhiyun 	}
6767*4882a593Smuzhiyun 	if (ifidx == 0) {
6768*4882a593Smuzhiyun 		strcpy(cur_if->ifname, net->name);
6769*4882a593Smuzhiyun 		wl_ext_iapsta_postinit(net, cur_if);
6770*4882a593Smuzhiyun 		wl_set_isam_status(cur_if, IF_READY);
6771*4882a593Smuzhiyun 	} else if (cur_if && wl_get_isam_status(cur_if, IF_ADDING)) {
6772*4882a593Smuzhiyun 		strcpy(cur_if->ifname, net->name);
6773*4882a593Smuzhiyun 		wl_ext_iapsta_postinit(net, cur_if);
6774*4882a593Smuzhiyun 		wl_clr_isam_status(cur_if, IF_ADDING);
6775*4882a593Smuzhiyun 		wl_set_isam_status(cur_if, IF_READY);
6776*4882a593Smuzhiyun #ifndef WL_STATIC_IF
6777*4882a593Smuzhiyun 		wake_up_interruptible(&apsta_params->netif_change_event);
6778*4882a593Smuzhiyun #endif /* WL_STATIC_IF */
6779*4882a593Smuzhiyun 	}
6780*4882a593Smuzhiyun 
6781*4882a593Smuzhiyun 	return 0;
6782*4882a593Smuzhiyun }
6783*4882a593Smuzhiyun 
6784*4882a593Smuzhiyun int
wl_ext_iapsta_update_net_device(struct net_device * net,int ifidx)6785*4882a593Smuzhiyun wl_ext_iapsta_update_net_device(struct net_device *net, int ifidx)
6786*4882a593Smuzhiyun {
6787*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
6788*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6789*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL, *primary_if;
6790*4882a593Smuzhiyun 
6791*4882a593Smuzhiyun 	if (ifidx < MAX_IF_NUM) {
6792*4882a593Smuzhiyun 		IAPSTA_TRACE(net->name, "ifidx=%d\n", ifidx);
6793*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[ifidx];
6794*4882a593Smuzhiyun 	}
6795*4882a593Smuzhiyun 	if (cur_if && wl_get_isam_status(cur_if, IF_ADDING)) {
6796*4882a593Smuzhiyun 		primary_if = &apsta_params->if_info[IF_PIF];
6797*4882a593Smuzhiyun 		if (strlen(cur_if->ifname)) {
6798*4882a593Smuzhiyun 			memset(net->name, 0, sizeof(IFNAMSIZ));
6799*4882a593Smuzhiyun 			strcpy(net->name, cur_if->ifname);
6800*4882a593Smuzhiyun 			net->name[IFNAMSIZ-1] = '\0';
6801*4882a593Smuzhiyun 		}
6802*4882a593Smuzhiyun #ifndef WL_STATIC_IF
6803*4882a593Smuzhiyun 		if (apsta_params->apstamode != IUNKNOWN_MODE &&
6804*4882a593Smuzhiyun 				apsta_params->apstamode != ISTAAPAP_MODE &&
6805*4882a593Smuzhiyun 				apsta_params->apstamode != ISTASTA_MODE) {
6806*4882a593Smuzhiyun 			u8 mac_addr[ETH_ALEN];
6807*4882a593Smuzhiyun 			memcpy(mac_addr, primary_if->dev->dev_addr, ETHER_ADDR_LEN);
6808*4882a593Smuzhiyun 			mac_addr[0] |= 0x02;
6809*4882a593Smuzhiyun 			wl_ext_iapsta_get_vif_macaddr(dhd, ifidx, mac_addr);
6810*4882a593Smuzhiyun 			dev_addr_set(net, mac_addr);
6811*4882a593Smuzhiyun 		}
6812*4882a593Smuzhiyun #endif /* WL_STATIC_IF */
6813*4882a593Smuzhiyun 	}
6814*4882a593Smuzhiyun 
6815*4882a593Smuzhiyun 	return 0;
6816*4882a593Smuzhiyun }
6817*4882a593Smuzhiyun 
6818*4882a593Smuzhiyun #ifdef WLDWDS
6819*4882a593Smuzhiyun int
wl_ext_iapsta_attach_dwds_netdev(struct net_device * net,int ifidx,uint8 bssidx)6820*4882a593Smuzhiyun wl_ext_iapsta_attach_dwds_netdev(struct net_device *net, int ifidx, uint8 bssidx)
6821*4882a593Smuzhiyun {
6822*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
6823*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6824*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
6825*4882a593Smuzhiyun 	int i;
6826*4882a593Smuzhiyun 
6827*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
6828*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[ifidx];
6829*4882a593Smuzhiyun 		if (cur_if->bssidx == bssidx) {
6830*4882a593Smuzhiyun 			break;
6831*4882a593Smuzhiyun 		}
6832*4882a593Smuzhiyun 	}
6833*4882a593Smuzhiyun 
6834*4882a593Smuzhiyun 	if (cur_if) {
6835*4882a593Smuzhiyun 		IAPSTA_TRACE(net->name, "ifidx=%d, bssidx=%d\n", ifidx, bssidx);
6836*4882a593Smuzhiyun 		for (i=0; i<MAX_DWDS_IF_NUM; i++) {
6837*4882a593Smuzhiyun 			if (apsta_params->dwds_info[i].dev == NULL) {
6838*4882a593Smuzhiyun 				apsta_params->dwds_info[i].dev = net;
6839*4882a593Smuzhiyun 				apsta_params->dwds_info[i].ifidx = ifidx;
6840*4882a593Smuzhiyun 				apsta_params->dwds_info[i].bssidx = bssidx;
6841*4882a593Smuzhiyun 				break;
6842*4882a593Smuzhiyun 			}
6843*4882a593Smuzhiyun 		}
6844*4882a593Smuzhiyun 	}
6845*4882a593Smuzhiyun 
6846*4882a593Smuzhiyun 	return 0;
6847*4882a593Smuzhiyun }
6848*4882a593Smuzhiyun 
6849*4882a593Smuzhiyun int
wl_ext_iapsta_dettach_dwds_netdev(struct net_device * net,int ifidx,uint8 bssidx)6850*4882a593Smuzhiyun wl_ext_iapsta_dettach_dwds_netdev(struct net_device *net, int ifidx, uint8 bssidx)
6851*4882a593Smuzhiyun {
6852*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
6853*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6854*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
6855*4882a593Smuzhiyun 	int i;
6856*4882a593Smuzhiyun 
6857*4882a593Smuzhiyun 	for (i=0; i<MAX_IF_NUM; i++) {
6858*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[ifidx];
6859*4882a593Smuzhiyun 		if (cur_if->bssidx == bssidx) {
6860*4882a593Smuzhiyun 			break;
6861*4882a593Smuzhiyun 		}
6862*4882a593Smuzhiyun 	}
6863*4882a593Smuzhiyun 
6864*4882a593Smuzhiyun 	if (cur_if) {
6865*4882a593Smuzhiyun 		IAPSTA_TRACE(net->name, "ifidx=%d, bssidx=%d\n", ifidx, bssidx);
6866*4882a593Smuzhiyun 		for (i=0; i<MAX_DWDS_IF_NUM; i++) {
6867*4882a593Smuzhiyun 			if (apsta_params->dwds_info[i].dev == net) {
6868*4882a593Smuzhiyun 				memset(&apsta_params->dwds_info[i], 0, sizeof(struct wl_dwds_info));
6869*4882a593Smuzhiyun 			}
6870*4882a593Smuzhiyun 		}
6871*4882a593Smuzhiyun 	}
6872*4882a593Smuzhiyun 
6873*4882a593Smuzhiyun 	return 0;
6874*4882a593Smuzhiyun }
6875*4882a593Smuzhiyun #endif /* WLDWDS */
6876*4882a593Smuzhiyun 
6877*4882a593Smuzhiyun static void
wl_ext_iapsta_init_priv(struct net_device * net)6878*4882a593Smuzhiyun wl_ext_iapsta_init_priv(struct net_device *net)
6879*4882a593Smuzhiyun {
6880*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
6881*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6882*4882a593Smuzhiyun 
6883*4882a593Smuzhiyun 	if (!apsta_params->ioctl_buf) {
6884*4882a593Smuzhiyun 		apsta_params->ioctl_buf = kmalloc(WL_DUMP_BUF_LEN, GFP_KERNEL);
6885*4882a593Smuzhiyun 		if (unlikely(!apsta_params->ioctl_buf)) {
6886*4882a593Smuzhiyun 			IAPSTA_ERROR(net->name, "Can not allocate ioctl_buf\n");
6887*4882a593Smuzhiyun 		}
6888*4882a593Smuzhiyun 	}
6889*4882a593Smuzhiyun 	init_waitqueue_head(&apsta_params->netif_change_event);
6890*4882a593Smuzhiyun 	mutex_init(&apsta_params->usr_sync);
6891*4882a593Smuzhiyun 	mutex_init(&apsta_params->in4way_sync);
6892*4882a593Smuzhiyun #ifdef STA_MGMT
6893*4882a593Smuzhiyun 	INIT_LIST_HEAD(&apsta_params->sta_list);
6894*4882a593Smuzhiyun #endif /* STA_MGMT */
6895*4882a593Smuzhiyun #ifdef EAPOL_RESEND
6896*4882a593Smuzhiyun 	spin_lock_init(&apsta_params->eapol_lock);
6897*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
6898*4882a593Smuzhiyun }
6899*4882a593Smuzhiyun 
6900*4882a593Smuzhiyun static void
wl_ext_iapsta_deinit_priv(struct net_device * net)6901*4882a593Smuzhiyun wl_ext_iapsta_deinit_priv(struct net_device *net)
6902*4882a593Smuzhiyun {
6903*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
6904*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6905*4882a593Smuzhiyun 
6906*4882a593Smuzhiyun 	if (apsta_params->ioctl_buf) {
6907*4882a593Smuzhiyun 		kfree(apsta_params->ioctl_buf);
6908*4882a593Smuzhiyun 		apsta_params->ioctl_buf = NULL;
6909*4882a593Smuzhiyun 	}
6910*4882a593Smuzhiyun 	memset(apsta_params, 0, sizeof(struct wl_apsta_params));
6911*4882a593Smuzhiyun }
6912*4882a593Smuzhiyun 
6913*4882a593Smuzhiyun int
wl_ext_iapsta_attach_netdev(struct net_device * net,int ifidx,uint8 bssidx)6914*4882a593Smuzhiyun wl_ext_iapsta_attach_netdev(struct net_device *net, int ifidx, uint8 bssidx)
6915*4882a593Smuzhiyun {
6916*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
6917*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6918*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
6919*4882a593Smuzhiyun 
6920*4882a593Smuzhiyun 	if (ifidx < MAX_IF_NUM) {
6921*4882a593Smuzhiyun 		IAPSTA_TRACE(net->name, "ifidx=%d, bssidx=%d\n", ifidx, bssidx);
6922*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[ifidx];
6923*4882a593Smuzhiyun 	}
6924*4882a593Smuzhiyun 
6925*4882a593Smuzhiyun 	if (ifidx == 0) {
6926*4882a593Smuzhiyun 		wl_ext_iapsta_init_priv(net);
6927*4882a593Smuzhiyun 		strcpy(cur_if->ifname, net->name);
6928*4882a593Smuzhiyun #ifdef TPUT_MONITOR
6929*4882a593Smuzhiyun 		wl_timer_register(net, &apsta_params->monitor_timer, wl_tput_monitor_timer);
6930*4882a593Smuzhiyun #endif /* TPUT_MONITOR */
6931*4882a593Smuzhiyun #ifdef RXF0OVFL_REINIT_WAR
6932*4882a593Smuzhiyun 		wl_timer_register(net, &apsta_params->rxf0ovfl_timer, wl_ext_rxf0ovfl_reinit_timeout);
6933*4882a593Smuzhiyun #endif /* RXF0OVFL_REINIT_WAR */
6934*4882a593Smuzhiyun 	}
6935*4882a593Smuzhiyun 
6936*4882a593Smuzhiyun 	if (ifidx == 0 || (cur_if && wl_get_isam_status(cur_if, IF_ADDING))) {
6937*4882a593Smuzhiyun 		cur_if->dev = net;
6938*4882a593Smuzhiyun 		cur_if->ifidx = ifidx;
6939*4882a593Smuzhiyun 		cur_if->bssidx = bssidx;
6940*4882a593Smuzhiyun 		mutex_init(&cur_if->pm_sync);
6941*4882a593Smuzhiyun 		INIT_DELAYED_WORK(&cur_if->pm_enable_work, wl_ext_pm_work_handler);
6942*4882a593Smuzhiyun 		init_waitqueue_head(&cur_if->ap_recon_sta_event);
6943*4882a593Smuzhiyun 		wl_ext_event_register(net, dhd, WLC_E_LAST, wl_ext_iapsta_event,
6944*4882a593Smuzhiyun 			apsta_params, PRIO_EVENT_IAPSTA);
6945*4882a593Smuzhiyun #if defined(WLMESH) && defined(WL_ESCAN)
6946*4882a593Smuzhiyun 		wl_mesh_escan_attach(dhd, cur_if);
6947*4882a593Smuzhiyun #endif /* WLMESH && WL_ESCAN */
6948*4882a593Smuzhiyun #ifdef ACS_MONITOR
6949*4882a593Smuzhiyun 		wl_acs_attach(dhd, cur_if);
6950*4882a593Smuzhiyun #endif /* ACS_MONITOR */
6951*4882a593Smuzhiyun #ifdef SET_CARRIER
6952*4882a593Smuzhiyun 		wl_ext_net_setcarrier(cur_if, FALSE, TRUE);
6953*4882a593Smuzhiyun #endif /* SET_CARRIER */
6954*4882a593Smuzhiyun 		wl_timer_register(net, &cur_if->connect_timer, wl_ext_connect_timeout);
6955*4882a593Smuzhiyun #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
6956*4882a593Smuzhiyun 		wl_timer_register(net, &cur_if->reconnect_timer, wl_ext_reconnect_timeout);
6957*4882a593Smuzhiyun #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
6958*4882a593Smuzhiyun #ifdef RESTART_AP_WAR
6959*4882a593Smuzhiyun 		wl_timer_register(net, &cur_if->restart_ap_timer, wl_ext_restart_ap_timeout);
6960*4882a593Smuzhiyun #endif /* RESTART_AP_WAR */
6961*4882a593Smuzhiyun #ifdef RESET_AP_WAR
6962*4882a593Smuzhiyun 		wl_timer_register(net, &cur_if->reset_ap_timer, wl_ext_reset_ap_timeout);
6963*4882a593Smuzhiyun #endif /* RESET_AP_WAR */
6964*4882a593Smuzhiyun #ifdef EAPOL_RESEND
6965*4882a593Smuzhiyun 		wl_timer_register(net, &cur_if->eapol_timer, wl_eapol_timer);
6966*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
6967*4882a593Smuzhiyun #ifdef KEY_INSTALL_CHECK
6968*4882a593Smuzhiyun 		wl_timer_register(net, &cur_if->key_install_timer, wl_ext_key_install_timeout);
6969*4882a593Smuzhiyun #endif /* KEY_INSTALL_CHECK */
6970*4882a593Smuzhiyun 	}
6971*4882a593Smuzhiyun 
6972*4882a593Smuzhiyun 	return 0;
6973*4882a593Smuzhiyun }
6974*4882a593Smuzhiyun 
6975*4882a593Smuzhiyun int
wl_ext_iapsta_dettach_netdev(struct net_device * net,int ifidx)6976*4882a593Smuzhiyun wl_ext_iapsta_dettach_netdev(struct net_device *net, int ifidx)
6977*4882a593Smuzhiyun {
6978*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
6979*4882a593Smuzhiyun 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
6980*4882a593Smuzhiyun 	struct wl_if_info *cur_if = NULL;
6981*4882a593Smuzhiyun 
6982*4882a593Smuzhiyun 	if (!apsta_params)
6983*4882a593Smuzhiyun 		return 0;
6984*4882a593Smuzhiyun 
6985*4882a593Smuzhiyun 	if (ifidx < MAX_IF_NUM) {
6986*4882a593Smuzhiyun 		IAPSTA_TRACE(net->name, "ifidx=%d\n", ifidx);
6987*4882a593Smuzhiyun 		cur_if = &apsta_params->if_info[ifidx];
6988*4882a593Smuzhiyun 	}
6989*4882a593Smuzhiyun 
6990*4882a593Smuzhiyun 	if (ifidx == 0 || (cur_if && (wl_get_isam_status(cur_if, IF_READY) ||
6991*4882a593Smuzhiyun 			wl_get_isam_status(cur_if, IF_ADDING)))) {
6992*4882a593Smuzhiyun #ifdef EAPOL_RESEND
6993*4882a593Smuzhiyun 		wl_ext_release_eapol_txpkt(dhd, ifidx, FALSE);
6994*4882a593Smuzhiyun #endif /* EAPOL_RESEND */
6995*4882a593Smuzhiyun #ifdef KEY_INSTALL_CHECK
6996*4882a593Smuzhiyun 		wl_timer_deregister(net, &cur_if->key_install_timer);
6997*4882a593Smuzhiyun #endif /* KEY_INSTALL_CHECK */
6998*4882a593Smuzhiyun 		wl_timer_deregister(net, &cur_if->connect_timer);
6999*4882a593Smuzhiyun #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
7000*4882a593Smuzhiyun 		wl_timer_deregister(net, &cur_if->reconnect_timer);
7001*4882a593Smuzhiyun #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
7002*4882a593Smuzhiyun #ifdef RESTART_AP_WAR
7003*4882a593Smuzhiyun 		wl_timer_deregister(net, &cur_if->restart_ap_timer);
7004*4882a593Smuzhiyun #endif /* RESTART_AP_WAR */
7005*4882a593Smuzhiyun #ifdef RESET_AP_WAR
7006*4882a593Smuzhiyun 		wl_timer_deregister(net, &cur_if->reset_ap_timer);
7007*4882a593Smuzhiyun #endif /* RESET_AP_WAR */
7008*4882a593Smuzhiyun #ifdef SET_CARRIER
7009*4882a593Smuzhiyun 		wl_ext_net_setcarrier(cur_if, FALSE, FALSE);
7010*4882a593Smuzhiyun #endif /* SET_CARRIER */
7011*4882a593Smuzhiyun 		wl_ext_add_remove_pm_enable_work(net, FALSE);
7012*4882a593Smuzhiyun #ifdef ACS_MONITOR
7013*4882a593Smuzhiyun 		wl_acs_detach(cur_if);
7014*4882a593Smuzhiyun #endif /* ACS_MONITOR */
7015*4882a593Smuzhiyun #if defined(WLMESH) && defined(WL_ESCAN)
7016*4882a593Smuzhiyun 		wl_mesh_escan_detach(dhd, cur_if);
7017*4882a593Smuzhiyun #endif /* WLMESH && WL_ESCAN */
7018*4882a593Smuzhiyun 		wl_ext_event_deregister(net, dhd, WLC_E_LAST, wl_ext_iapsta_event);
7019*4882a593Smuzhiyun #ifdef STA_MGMT
7020*4882a593Smuzhiyun 		wl_ext_flush_sta_list(net, ifidx);
7021*4882a593Smuzhiyun #endif /* STA_MGMT */
7022*4882a593Smuzhiyun 		memset(cur_if, 0, sizeof(struct wl_if_info));
7023*4882a593Smuzhiyun 	}
7024*4882a593Smuzhiyun 
7025*4882a593Smuzhiyun 	if (ifidx == 0) {
7026*4882a593Smuzhiyun #ifdef RXF0OVFL_REINIT_WAR
7027*4882a593Smuzhiyun 		wl_timer_deregister(net, &apsta_params->rxf0ovfl_timer);
7028*4882a593Smuzhiyun #endif /* RXF0OVFL_REINIT_WAR */
7029*4882a593Smuzhiyun #ifdef TPUT_MONITOR
7030*4882a593Smuzhiyun 		wl_timer_deregister(net, &apsta_params->monitor_timer);
7031*4882a593Smuzhiyun #endif /* TPUT_MONITOR */
7032*4882a593Smuzhiyun 		wl_ext_iapsta_deinit_priv(net);
7033*4882a593Smuzhiyun 	}
7034*4882a593Smuzhiyun 
7035*4882a593Smuzhiyun 	return 0;
7036*4882a593Smuzhiyun }
7037*4882a593Smuzhiyun 
7038*4882a593Smuzhiyun int
wl_ext_iapsta_attach(struct net_device * net)7039*4882a593Smuzhiyun wl_ext_iapsta_attach(struct net_device *net)
7040*4882a593Smuzhiyun {
7041*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
7042*4882a593Smuzhiyun 	struct wl_apsta_params *iapsta_params;
7043*4882a593Smuzhiyun 
7044*4882a593Smuzhiyun 	IAPSTA_TRACE(net->name, "Enter\n");
7045*4882a593Smuzhiyun 
7046*4882a593Smuzhiyun 	iapsta_params = kzalloc(sizeof(struct wl_apsta_params), GFP_KERNEL);
7047*4882a593Smuzhiyun 	if (unlikely(!iapsta_params)) {
7048*4882a593Smuzhiyun 		IAPSTA_ERROR(net->name, "Can not allocate apsta_params\n");
7049*4882a593Smuzhiyun 		return -ENOMEM;
7050*4882a593Smuzhiyun 	}
7051*4882a593Smuzhiyun 	dhd->iapsta_params = (void *)iapsta_params;
7052*4882a593Smuzhiyun 
7053*4882a593Smuzhiyun 	return 0;
7054*4882a593Smuzhiyun }
7055*4882a593Smuzhiyun 
7056*4882a593Smuzhiyun void
wl_ext_iapsta_dettach(struct net_device * net)7057*4882a593Smuzhiyun wl_ext_iapsta_dettach(struct net_device *net)
7058*4882a593Smuzhiyun {
7059*4882a593Smuzhiyun 	struct dhd_pub *dhd = dhd_get_pub(net);
7060*4882a593Smuzhiyun 
7061*4882a593Smuzhiyun 	IAPSTA_TRACE(net->name, "Enter\n");
7062*4882a593Smuzhiyun 
7063*4882a593Smuzhiyun 	if (dhd->iapsta_params) {
7064*4882a593Smuzhiyun 		wl_ext_iapsta_deinit_priv(net);
7065*4882a593Smuzhiyun 		kfree(dhd->iapsta_params);
7066*4882a593Smuzhiyun 		dhd->iapsta_params = NULL;
7067*4882a593Smuzhiyun 	}
7068*4882a593Smuzhiyun }
7069*4882a593Smuzhiyun #endif /* WL_EXT_IAPSTA */
7070