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