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