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