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