• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&ether_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(&ether_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", &param, 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, &ether_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(&ether_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, &ether_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