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