wifi: fix wifi close issue
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd.1.579.77.41.1.cn / wl_android_ext.c
CommitLineData
91a2c117 1
91a2c117
RC
2#include <linux/module.h>
3#include <linux/netdevice.h>
4#include <net/netlink.h>
dfb0f3ae
RC
5#include <typedefs.h>
6#include <linuxver.h>
7#include <osl.h>
8
9#include <bcmutils.h>
10#include <bcmendian.h>
11#include <ethernet.h>
91a2c117
RC
12
13#include <wl_android.h>
dfb0f3ae
RC
14#include <linux/if_arp.h>
15#include <asm/uaccess.h>
16#include <linux/wireless.h>
d964ce36 17#if defined(WL_WIRELESS_EXT)
dfb0f3ae 18#include <wl_iw.h>
d964ce36 19#endif
91a2c117
RC
20#include <wldev_common.h>
21#include <wlioctl.h>
22#include <bcmutils.h>
23#include <linux_osl.h>
24#include <dhd_dbg.h>
25#include <dngl_stats.h>
26#include <dhd.h>
27#include <dhd_config.h>
dfb0f3ae
RC
28#ifdef WL_CFG80211
29#include <wl_cfg80211.h>
30#endif
d964ce36 31#ifdef WL_ESCAN
32#include <wl_escan.h>
33#endif
91a2c117 34
dfb0f3ae 35#ifndef WL_CFG80211
91a2c117
RC
36#define htod32(i) i
37#define htod16(i) i
38#define dtoh32(i) i
39#define dtoh16(i) i
40#define htodchanspec(i) i
41#define dtohchanspec(i) i
dfb0f3ae
RC
42#define IEEE80211_BAND_2GHZ 0
43#define IEEE80211_BAND_5GHZ 1
44#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20
45#define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
46#define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
47#endif
91a2c117
RC
48#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
49
dfb0f3ae
RC
50#ifndef IW_CUSTOM_MAX
51#define IW_CUSTOM_MAX 256 /* size of extra buffer used for translation of events */
52#endif /* IW_CUSTOM_MAX */
53
91a2c117
RC
54#define CMD_CHANNEL "CHANNEL"
55#define CMD_CHANNELS "CHANNELS"
56#define CMD_ROAM_TRIGGER "ROAM_TRIGGER"
57#define CMD_KEEP_ALIVE "KEEP_ALIVE"
58#define CMD_PM "PM"
59#define CMD_MONITOR "MONITOR"
60#define CMD_SET_SUSPEND_BCN_LI_DTIM "SET_SUSPEND_BCN_LI_DTIM"
61
62#ifdef WL_EXT_IAPSTA
d964ce36 63#include <net/rtnetlink.h>
91a2c117
RC
64#define CMD_IAPSTA_INIT "IAPSTA_INIT"
65#define CMD_IAPSTA_CONFIG "IAPSTA_CONFIG"
66#define CMD_IAPSTA_ENABLE "IAPSTA_ENABLE"
67#define CMD_IAPSTA_DISABLE "IAPSTA_DISABLE"
dfb0f3ae
RC
68#define CMD_ISAM_INIT "ISAM_INIT"
69#define CMD_ISAM_CONFIG "ISAM_CONFIG"
70#define CMD_ISAM_ENABLE "ISAM_ENABLE"
71#define CMD_ISAM_DISABLE "ISAM_DISABLE"
d964ce36 72#define CMD_ISAM_STATUS "ISAM_STATUS"
91a2c117
RC
73#ifdef PROP_TXSTATUS
74#ifdef PROP_TXSTATUS_VSDB
75#include <dhd_wlfc.h>
010c3a89 76extern int disable_proptx;
91a2c117
RC
77#endif /* PROP_TXSTATUS_VSDB */
78#endif
79#endif
80#ifdef IDHCP
81#define CMD_DHCPC_ENABLE "DHCPC_ENABLE"
82#define CMD_DHCPC_DUMP "DHCPC_DUMP"
83#endif
d964ce36 84#define CMD_AUTOCHANNEL "AUTOCHANNEL"
91a2c117
RC
85#define CMD_WL "WL"
86
91a2c117
RC
87int wl_ext_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set)
88{
89 int ret;
90
91 ret = wldev_ioctl(dev, cmd, arg, len, set);
92 if (ret)
93 ANDROID_ERROR(("%s: cmd=%d ret=%d\n", __FUNCTION__, cmd, ret));
94 return ret;
95}
96
97int wl_ext_iovar_getint(struct net_device *dev, s8 *iovar, s32 *val)
98{
99 int ret;
100
101 ret = wldev_iovar_getint(dev, iovar, val);
102 if (ret)
103 ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar, ret));
104
105 return ret;
106}
107
108int wl_ext_iovar_setint(struct net_device *dev, s8 *iovar, s32 val)
109{
110 int ret;
111
112 ret = wldev_iovar_setint(dev, iovar, val);
113 if (ret)
114 ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar, ret));
115
116 return ret;
117}
118
119int wl_ext_iovar_getbuf(struct net_device *dev, s8 *iovar_name,
120 void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
121{
122 int ret;
123
124 ret = wldev_iovar_getbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync);
125 if (ret != 0)
126 ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar_name, ret));
127
128 return ret;
129}
130
131int wl_ext_iovar_setbuf(struct net_device *dev, s8 *iovar_name,
132 void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
133{
134 int ret;
135
136 ret = wldev_iovar_setbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync);
137 if (ret != 0)
138 ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar_name, ret));
139
140 return ret;
141}
142
143#ifdef WL_EXT_IAPSTA
d964ce36 144typedef enum IF_STATE {
145 IF_STATE_INIT = 1,
146 IF_STATE_DISALBE,
147 IF_STATE_ENABLE
148} if_state_t;
149
150typedef enum APSTAMODE {
151 ISTAONLY_MODE = 1,
152 IAPONLY_MODE,
153 IAPSTA_MODE,
154 IDUALAP_MODE,
155 ISTAAPAP_MODE,
156 IMESHONLY_MODE,
157 IMESHSTA_MODE,
158 IMESHAP_MODE,
159 IMESHAPSTA_MODE,
160 IMESHAPAP_MODE,
161 IGOSTA_MODE
162} apstamode_t;
163
164typedef enum IFMODE {
165 ISTA_MODE = 1,
166 IAP_MODE,
167 IMESH_MODE
168} ifmode_t;
169
170typedef enum BGNMODE {
171 IEEE80211B = 1,
172 IEEE80211G,
173 IEEE80211BG,
174 IEEE80211BGN,
175 IEEE80211BGNAC
176} bgnmode_t;
177
178typedef enum AUTHMODE {
179 AUTH_OPEN,
180 AUTH_SHARED,
181 AUTH_WPAPSK,
182 AUTH_WPA2PSK,
183 AUTH_WPAWPA2PSK,
184 AUTH_SAE
185} authmode_t;
186
187typedef enum ENCMODE {
188 ENC_NONE,
189 ENC_WEP,
190 ENC_TKIP,
191 ENC_AES,
192 ENC_TKIPAES
193} encmode_t;
194
195enum wl_if_list {
196 IF_PIF,
197 IF_VIF,
198 IF_VIF2,
199 MAX_IF_NUM
200};
201
202typedef enum WL_PRIO {
203 PRIO_AP,
204 PRIO_MESH,
205 PRIO_STA
206}wl_prio_t;
207
208typedef struct wl_if_info {
209 struct net_device *dev;
210 if_state_t ifstate;
211 ifmode_t ifmode;
212 char prefix;
213 wl_prio_t prio;
214 int ifidx;
215 uint8 bssidx;
216 char ifname[IFNAMSIZ+1];
217 char ssid[DOT11_MAX_SSID_LEN];
218 struct ether_addr bssid;
219 bgnmode_t bgnmode;
220 int hidden;
221 int maxassoc;
222 uint16 channel;
223 authmode_t amode;
224 encmode_t emode;
225 char key[100];
226} wl_if_info_t;
227
228#define CSA_FW_BIT (1<<0)
229#define CSA_DRV_BIT (1<<1)
230
231typedef struct wl_apsta_params {
232 struct wl_if_info if_info[MAX_IF_NUM];
233 int ioctl_ver;
234 bool init;
235 bool rsdb;
236 bool vsdb;
237 uint csa;
238 apstamode_t apstamode;
239 bool netif_change;
240 wait_queue_head_t netif_change_event;
241} wl_apsta_params_t;
242
243static int wl_ext_enable_iface(struct net_device *dev, char *ifname);
91a2c117 244int wl_ext_iovar_setbuf_bsscfg(struct net_device *dev, s8 *iovar_name,
d964ce36 245 void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx,
246 struct mutex* buf_sync)
91a2c117
RC
247{
248 int ret;
249
250 ret = wldev_iovar_setbuf_bsscfg(dev, iovar_name, param, paramlen,
251 buf, buflen, bsscfg_idx, buf_sync);
252 if (ret < 0)
253 ANDROID_ERROR(("%s: iovar_name=%s ret=%d\n", __FUNCTION__, iovar_name, ret));
254
255 return ret;
256}
91a2c117 257#endif
010c3a89
RC
258
259/* Return a legacy chanspec given a new chanspec
260 * Returns INVCHANSPEC on error
261 */
262static chanspec_t
91a2c117 263wl_ext_chspec_to_legacy(chanspec_t chspec)
010c3a89
RC
264{
265 chanspec_t lchspec;
266
267 if (wf_chspec_malformed(chspec)) {
91a2c117 268 ANDROID_ERROR(("wl_ext_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
010c3a89
RC
269 chspec));
270 return INVCHANSPEC;
271 }
272
273 /* get the channel number */
274 lchspec = CHSPEC_CHANNEL(chspec);
275
276 /* convert the band */
277 if (CHSPEC_IS2G(chspec)) {
278 lchspec |= WL_LCHANSPEC_BAND_2G;
279 } else {
280 lchspec |= WL_LCHANSPEC_BAND_5G;
281 }
282
283 /* convert the bw and sideband */
284 if (CHSPEC_IS20(chspec)) {
285 lchspec |= WL_LCHANSPEC_BW_20;
286 lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
287 } else if (CHSPEC_IS40(chspec)) {
288 lchspec |= WL_LCHANSPEC_BW_40;
289 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
290 lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
291 } else {
292 lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
293 }
294 } else {
295 /* cannot express the bandwidth */
296 char chanbuf[CHANSPEC_STR_LEN];
91a2c117
RC
297 ANDROID_ERROR((
298 "wl_ext_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
010c3a89
RC
299 "to pre-11ac format\n",
300 wf_chspec_ntoa(chspec, chanbuf), chspec));
301 return INVCHANSPEC;
302 }
303
304 return lchspec;
91a2c117 305}
010c3a89
RC
306
307/* given a chanspec value, do the endian and chanspec version conversion to
308 * a chanspec_t value
309 * Returns INVCHANSPEC on error
310 */
311static chanspec_t
91a2c117 312wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec)
010c3a89 313{
91a2c117
RC
314 if (ioctl_ver == 1) {
315 chanspec = wl_ext_chspec_to_legacy(chanspec);
010c3a89
RC
316 if (chanspec == INVCHANSPEC) {
317 return chanspec;
318 }
319 }
320 chanspec = htodchanspec(chanspec);
321
322 return chanspec;
91a2c117
RC
323}
324
d964ce36 325#if defined(WL_EXT_IAPSTA) || defined(WL_CFG80211) || defined(WL_ESCAN)
326static chanspec_t
327wl_ext_chspec_from_legacy(chanspec_t legacy_chspec)
328{
329 chanspec_t chspec;
330
331 /* get the channel number */
332 chspec = LCHSPEC_CHANNEL(legacy_chspec);
333
334 /* convert the band */
335 if (LCHSPEC_IS2G(legacy_chspec)) {
336 chspec |= WL_CHANSPEC_BAND_2G;
337 } else {
338 chspec |= WL_CHANSPEC_BAND_5G;
339 }
340
341 /* convert the bw and sideband */
342 if (LCHSPEC_IS20(legacy_chspec)) {
343 chspec |= WL_CHANSPEC_BW_20;
344 } else {
345 chspec |= WL_CHANSPEC_BW_40;
346 if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
347 chspec |= WL_CHANSPEC_CTL_SB_L;
348 } else {
349 chspec |= WL_CHANSPEC_CTL_SB_U;
350 }
351 }
352
353 if (wf_chspec_malformed(chspec)) {
354 ANDROID_ERROR(("wl_ext_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
355 chspec));
356 return INVCHANSPEC;
357 }
358
359 return chspec;
360}
361
362static chanspec_t
363wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec)
364{
365 chanspec = dtohchanspec(chanspec);
366 if (ioctl_ver == 1) {
367 chanspec = wl_ext_chspec_from_legacy(chanspec);
368 }
369
370 return chanspec;
371}
372#endif
373
91a2c117
RC
374static int
375wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver)
376{
377 int ret = 0;
378 s32 val = 0;
379
380 val = 1;
381 ret = wl_ext_ioctl(dev, WLC_GET_VERSION, &val, sizeof(val), 0);
382 if (ret) {
383 ANDROID_ERROR(("WLC_GET_VERSION failed, err=%d\n", ret));
384 return ret;
385 }
386 val = dtoh32(val);
387 if (val != WLC_IOCTL_VERSION && val != 1) {
388 ANDROID_ERROR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
389 val, WLC_IOCTL_VERSION));
390 return BCME_VERSION;
391 }
392 *ioctl_ver = val;
393
394 return ret;
395}
396
397static int
d964ce36 398wl_ext_set_chanspec(struct net_device *dev, int ioctl_ver,
399 uint16 channel, chanspec_t *ret_chspec)
91a2c117
RC
400{
401 s32 _chan = channel;
010c3a89 402 chanspec_t chspec = 0;
91a2c117
RC
403 chanspec_t fw_chspec = 0;
404 u32 bw = WL_CHANSPEC_BW_20;
010c3a89 405 s32 err = BCME_OK;
91a2c117
RC
406 s32 bw_cap = 0;
407 s8 iovar_buf[WLC_IOCTL_SMLEN];
010c3a89
RC
408 struct {
409 u32 band;
410 u32 bw_cap;
91a2c117
RC
411 } param = {0, 0};
412 uint band;
91a2c117
RC
413
414 if (_chan <= CH_MAX_2G_CHANNEL)
415 band = IEEE80211_BAND_2GHZ;
416 else
417 band = IEEE80211_BAND_5GHZ;
91a2c117
RC
418
419 if (band == IEEE80211_BAND_5GHZ) {
010c3a89
RC
420 param.band = WLC_BAND_5G;
421 err = wldev_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
91a2c117 422 iovar_buf, WLC_IOCTL_SMLEN, NULL);
010c3a89
RC
423 if (err) {
424 if (err != BCME_UNSUPPORTED) {
91a2c117 425 ANDROID_ERROR(("bw_cap failed, %d\n", err));
010c3a89
RC
426 return err;
427 } else {
428 err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
429 if (err) {
91a2c117 430 ANDROID_ERROR(("error get mimo_bw_cap (%d)\n", err));
010c3a89
RC
431 }
432 if (bw_cap != WLC_N_BW_20ALL)
433 bw = WL_CHANSPEC_BW_40;
434 }
435 } else {
91a2c117 436 if (WL_BW_CAP_80MHZ(iovar_buf[0]))
010c3a89 437 bw = WL_CHANSPEC_BW_80;
91a2c117 438 else if (WL_BW_CAP_40MHZ(iovar_buf[0]))
010c3a89
RC
439 bw = WL_CHANSPEC_BW_40;
440 else
441 bw = WL_CHANSPEC_BW_20;
442
91a2c117
RC
443 }
444 }
445 else if (band == IEEE80211_BAND_2GHZ)
446 bw = WL_CHANSPEC_BW_20;
447
010c3a89
RC
448set_channel:
449 chspec = wf_channel2chspec(_chan, bw);
450 if (wf_chspec_valid(chspec)) {
91a2c117 451 fw_chspec = wl_ext_chspec_host_to_driver(ioctl_ver, chspec);
010c3a89 452 if (fw_chspec != INVCHANSPEC) {
91a2c117 453 if ((err = wldev_iovar_setint(dev, "chanspec", fw_chspec)) == BCME_BADCHAN) {
010c3a89 454 if (bw == WL_CHANSPEC_BW_80)
91a2c117
RC
455 goto change_bw;
456 wl_ext_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), 1);
457 printf("%s: channel %d\n", __FUNCTION__, _chan);
010c3a89 458 } else if (err) {
d964ce36 459 ANDROID_ERROR(("%s: failed to set chanspec error %d\n",
460 __FUNCTION__, err));
91a2c117 461 } else
d964ce36 462 printf("%s: %s channel %d, 0x%x\n", __FUNCTION__,
463 dev->name, channel, chspec);
010c3a89 464 } else {
d964ce36 465 ANDROID_ERROR(("%s: failed to convert host chanspec to fw chanspec\n",
466 __FUNCTION__));
010c3a89
RC
467 err = BCME_ERROR;
468 }
469 } else {
470change_bw:
471 if (bw == WL_CHANSPEC_BW_80)
472 bw = WL_CHANSPEC_BW_40;
473 else if (bw == WL_CHANSPEC_BW_40)
474 bw = WL_CHANSPEC_BW_20;
475 else
476 bw = 0;
477 if (bw)
478 goto set_channel;
91a2c117 479 ANDROID_ERROR(("%s: Invalid chanspec 0x%x\n", __FUNCTION__, chspec));
010c3a89 480 err = BCME_ERROR;
91a2c117 481 }
dfb0f3ae 482 *ret_chspec = fw_chspec;
91a2c117
RC
483
484 return err;
485}
486
487int
488wl_ext_channel(struct net_device *dev, char* command, int total_len)
489{
490 int ret;
491 int channel=0;
492 channel_info_t ci;
493 int bytes_written = 0;
dfb0f3ae 494 chanspec_t fw_chspec;
d964ce36 495 int ioctl_ver = 0;
91a2c117
RC
496
497 ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
498
499 sscanf(command, "%*s %d", &channel);
500
501 if (channel > 0) {
d964ce36 502 wl_ext_get_ioctl_ver(dev, &ioctl_ver);
503 ret = wl_ext_set_chanspec(dev, ioctl_ver, channel, &fw_chspec);
91a2c117 504 } else {
d964ce36 505 if (!(ret = wldev_ioctl(dev, WLC_GET_CHANNEL, &ci,
506 sizeof(channel_info_t), FALSE))) {
91a2c117
RC
507 ANDROID_TRACE(("hw_channel %d\n", ci.hw_channel));
508 ANDROID_TRACE(("target_channel %d\n", ci.target_channel));
509 ANDROID_TRACE(("scan_channel %d\n", ci.scan_channel));
d964ce36 510 bytes_written = snprintf(command, sizeof(channel_info_t)+2,
511 "channel %d", ci.hw_channel);
91a2c117
RC
512 ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
513 ret = bytes_written;
514 }
515 }
516
517 return ret;
518}
519
520int
521wl_ext_channels(struct net_device *dev, char* command, int total_len)
522{
523 int ret, i;
524 int bytes_written = -1;
525 u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
526 wl_uint32_list_t *list;
527
528 ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
529
530 memset(valid_chan_list, 0, sizeof(valid_chan_list));
531 list = (wl_uint32_list_t *)(void *) valid_chan_list;
532 list->count = htod32(WL_NUMCHANNELS);
d964ce36 533 ret = wldev_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list,
534 sizeof(valid_chan_list), 0);
91a2c117
RC
535 if (ret<0) {
536 ANDROID_ERROR(("%s: get channels failed with %d\n", __FUNCTION__, ret));
537 } else {
538 bytes_written = snprintf(command, total_len, "channels");
539 for (i = 0; i < dtoh32(list->count); i++) {
d964ce36 540 bytes_written += snprintf(command+bytes_written, total_len, " %d",
541 dtoh32(list->element[i]));
91a2c117
RC
542 printf("%d ", dtoh32(list->element[i]));
543 }
544 printf("\n");
545 ret = bytes_written;
546 }
547
548 return ret;
549}
550
551int
552wl_ext_roam_trigger(struct net_device *dev, char* command, int total_len)
553{
554 int ret = 0;
555 int roam_trigger[2] = {0, 0};
556 int trigger[2]= {0, 0};
557 int bytes_written=-1;
558
559 sscanf(command, "%*s %10d", &roam_trigger[0]);
560
561 if (roam_trigger[0]) {
562 roam_trigger[1] = WLC_BAND_ALL;
d964ce36 563 ret = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
564 sizeof(roam_trigger), 1);
91a2c117 565 if (ret)
d964ce36 566 ANDROID_ERROR(("WLC_SET_ROAM_TRIGGER ERROR %d ret=%d\n",
567 roam_trigger[0], ret));
91a2c117
RC
568 } else {
569 roam_trigger[1] = WLC_BAND_2G;
d964ce36 570 ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
571 sizeof(roam_trigger), 0);
91a2c117
RC
572 if (!ret)
573 trigger[0] = roam_trigger[0];
574 else
d964ce36 575 ANDROID_ERROR(("2G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n",
576 roam_trigger[0], ret));
91a2c117
RC
577
578 roam_trigger[1] = WLC_BAND_5G;
d964ce36 579 ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
580 sizeof(roam_trigger), 0);
91a2c117
RC
581 if (!ret)
582 trigger[1] = roam_trigger[0];
583 else
d964ce36 584 ANDROID_ERROR(("5G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n",
585 roam_trigger[0], ret));
91a2c117
RC
586
587 ANDROID_TRACE(("roam_trigger %d %d\n", trigger[0], trigger[1]));
588 bytes_written = snprintf(command, total_len, "%d %d", trigger[0], trigger[1]);
589 ret = bytes_written;
590 }
591
592 return ret;
593}
594
595static int
596wl_ext_pattern_atoh(char *src, char *dst)
597{
598 int i;
599 if (strncmp(src, "0x", 2) != 0 &&
600 strncmp(src, "0X", 2) != 0) {
601 ANDROID_ERROR(("Mask invalid format. Needs to start with 0x\n"));
602 return -1;
603 }
604 src = src + 2; /* Skip past 0x */
605 if (strlen(src) % 2 != 0) {
606 DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
607 return -1;
608 }
609 for (i = 0; *src != '\0'; i++) {
610 char num[3];
611 bcm_strncpy_s(num, sizeof(num), src, 2);
612 num[2] = '\0';
613 dst[i] = (uint8)strtoul(num, NULL, 16);
614 src += 2;
615 }
616 return i;
617}
618
619int
620wl_ext_keep_alive(struct net_device *dev, char *command, int total_len)
621{
622 wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
623 int ret = -1, i;
624 int id, period=-1, len_bytes=0, buf_len=0;
625 char data[200]="\0";
626 char buf[WLC_IOCTL_SMLEN]="\0", iovar_buf[WLC_IOCTL_SMLEN]="\0";
627 int bytes_written = -1;
628
629 ANDROID_TRACE(("%s: command = %s\n", __FUNCTION__, command));
630 sscanf(command, "%*s %d %d %s", &id, &period, data);
631 ANDROID_TRACE(("%s: id=%d, period=%d, data=%s\n", __FUNCTION__, id, period, data));
632
633 if (period >= 0) {
634 mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *)buf;
635 mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION);
636 mkeep_alive_pktp->length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
637 mkeep_alive_pktp->keep_alive_id = id;
638 buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
639 mkeep_alive_pktp->period_msec = period;
640 if (strlen(data)) {
641 len_bytes = wl_ext_pattern_atoh(data, (char *) mkeep_alive_pktp->data);
642 buf_len += len_bytes;
643 }
644 mkeep_alive_pktp->len_bytes = htod16(len_bytes);
645
646 ret = wl_ext_iovar_setbuf(dev, "mkeep_alive", buf, buf_len,
647 iovar_buf, sizeof(iovar_buf), NULL);
648 } else {
649 if (id < 0)
650 id = 0;
d964ce36 651 ret = wl_ext_iovar_getbuf(dev, "mkeep_alive", &id, sizeof(id), buf,
652 sizeof(buf), NULL);
91a2c117
RC
653 if (ret) {
654 goto exit;
655 } else {
656 mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) buf;
657 printf("Id :%d\n"
658 "Period (msec) :%d\n"
659 "Length :%d\n"
660 "Packet :0x",
661 mkeep_alive_pktp->keep_alive_id,
662 dtoh32(mkeep_alive_pktp->period_msec),
663 dtoh16(mkeep_alive_pktp->len_bytes));
664 for (i=0; i<mkeep_alive_pktp->len_bytes; i++) {
665 printf("%02x", mkeep_alive_pktp->data[i]);
666 }
667 printf("\n");
668 }
d964ce36 669 bytes_written = snprintf(command, total_len, "mkeep_alive_period_msec %d ",
670 dtoh32(mkeep_alive_pktp->period_msec));
91a2c117
RC
671 bytes_written += snprintf(command+bytes_written, total_len, "0x");
672 for (i=0; i<mkeep_alive_pktp->len_bytes; i++) {
d964ce36 673 bytes_written += snprintf(command+bytes_written, total_len, "%x",
674 mkeep_alive_pktp->data[i]);
91a2c117
RC
675 }
676 ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
677 ret = bytes_written;
678 }
679
680exit:
681 return ret;
682}
683
684int
685wl_ext_pm(struct net_device *dev, char *command, int total_len)
686{
687 int pm=-1, ret = -1;
688 char *pm_local;
689 int bytes_written=-1;
690
691 ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
692
693 sscanf(command, "%*s %d", &pm);
694
695 if (pm >= 0) {
696 ret = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), FALSE);
697 if (ret)
698 ANDROID_ERROR(("WLC_SET_PM ERROR %d ret=%d\n", pm, ret));
699 } else {
700 ret = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), FALSE);
701 if (!ret) {
702 ANDROID_TRACE(("%s: PM = %d\n", __func__, pm));
703 if (pm == PM_OFF)
704 pm_local = "PM_OFF";
705 else if(pm == PM_MAX)
706 pm_local = "PM_MAX";
707 else if(pm == PM_FAST)
708 pm_local = "PM_FAST";
709 else {
710 pm = 0;
711 pm_local = "Invalid";
712 }
713 bytes_written = snprintf(command, total_len, "PM %s", pm_local);
714 ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
715 ret = bytes_written;
716 }
717 }
718
719 return ret;
720}
721
722static int
723wl_ext_monitor(struct net_device *dev, char *command, int total_len)
724{
725 int val, ret = -1;
726 int bytes_written=-1;
727
728 sscanf(command, "%*s %d", &val);
729
730 if (val >=0) {
731 ret = wldev_ioctl(dev, WLC_SET_MONITOR, &val, sizeof(int), 1);
732 if (ret)
733 ANDROID_ERROR(("WLC_SET_MONITOR ERROR %d ret=%d\n", val, ret));
734 } else {
735 ret = wldev_ioctl(dev, WLC_GET_MONITOR, &val, sizeof(val), FALSE);
736 if (!ret) {
737 ANDROID_TRACE(("%s: monitor = %d\n", __FUNCTION__, val));
738 bytes_written = snprintf(command, total_len, "monitor %d", val);
739 ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
740 ret = bytes_written;
741 }
742 }
743
744 return ret;
745}
746
747#ifdef WL_EXT_IAPSTA
748struct wl_apsta_params g_apsta_params;
749static int
750wl_ext_parse_wep(char *key, struct wl_wsec_key *wsec_key)
751{
752 char hex[] = "XX";
753 unsigned char *data = wsec_key->data;
754 char *keystr = key;
755
756 switch (strlen(keystr)) {
757 case 5:
758 case 13:
759 case 16:
760 wsec_key->len = strlen(keystr);
761 memcpy(data, keystr, wsec_key->len + 1);
762 break;
763 case 12:
764 case 28:
765 case 34:
766 case 66:
767 /* strip leading 0x */
768 if (!strnicmp(keystr, "0x", 2))
769 keystr += 2;
770 else
771 return -1;
772 /* fall through */
773 case 10:
774 case 26:
775 case 32:
776 case 64:
777 wsec_key->len = strlen(keystr) / 2;
778 while (*keystr) {
779 strncpy(hex, keystr, 2);
780 *data++ = (char) strtoul(hex, NULL, 16);
781 keystr += 2;
782 }
783 break;
784 default:
785 return -1;
786 }
787
788 switch (wsec_key->len) {
789 case 5:
790 wsec_key->algo = CRYPTO_ALGO_WEP1;
791 break;
792 case 13:
793 wsec_key->algo = CRYPTO_ALGO_WEP128;
794 break;
795 case 16:
796 /* default to AES-CCM */
797 wsec_key->algo = CRYPTO_ALGO_AES_CCM;
798 break;
799 case 32:
800 wsec_key->algo = CRYPTO_ALGO_TKIP;
801 break;
802 default:
803 return -1;
804 }
805
806 /* Set as primary wsec_key by default */
807 wsec_key->flags |= WL_PRIMARY_KEY;
808
809 return 0;
810}
811
812static int
813wl_ext_set_bgnmode(struct wl_if_info *cur_if)
814{
815 struct net_device *dev = cur_if->dev;
816 bgnmode_t bgnmode = cur_if->bgnmode;
817 int val;
818
819 if (bgnmode == 0)
820 return 0;
821
822 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
823 if (bgnmode == IEEE80211B) {
824 wl_ext_iovar_setint(dev, "nmode", 0);
825 val = 0;
826 wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
827 ANDROID_TRACE(("%s: Network mode: B only\n", __FUNCTION__));
828 } else if (bgnmode == IEEE80211G) {
829 wl_ext_iovar_setint(dev, "nmode", 0);
830 val = 2;
831 wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
832 ANDROID_TRACE(("%s: Network mode: G only\n", __FUNCTION__));
833 } else if (bgnmode == IEEE80211BG) {
834 wl_ext_iovar_setint(dev, "nmode", 0);
835 val = 1;
836 wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
837 ANDROID_TRACE(("%s: Network mode: B/G mixed\n", __FUNCTION__));
838 } else if (bgnmode == IEEE80211BGN) {
839 wl_ext_iovar_setint(dev, "nmode", 0);
840 wl_ext_iovar_setint(dev, "nmode", 1);
841 wl_ext_iovar_setint(dev, "vhtmode", 0);
842 val = 1;
843 wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
844 ANDROID_TRACE(("%s: Network mode: B/G/N mixed\n", __FUNCTION__));
845 } else if (bgnmode == IEEE80211BGNAC) {
846 wl_ext_iovar_setint(dev, "nmode", 0);
847 wl_ext_iovar_setint(dev, "nmode", 1);
848 wl_ext_iovar_setint(dev, "vhtmode", 1);
849 val = 1;
850 wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
851 ANDROID_TRACE(("%s: Network mode: B/G/N/AC mixed\n", __FUNCTION__));
852 }
853 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
854
855 return 0;
856}
857
d964ce36 858static void
859wl_ext_get_amode(struct wl_if_info *cur_if, char *amode)
860{
861 struct net_device *dev = cur_if->dev;
862 int auth=-1, wpa_auth=-1;
863
864 wl_ext_iovar_getint(dev, "auth", &auth);
865 wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
866
867 if (cur_if->ifmode == IMESH_MODE) {
868 if (auth == 0 && wpa_auth == 0) {
869 strcpy(amode, "open");
870 } else if (auth == 0 && wpa_auth == 128) {
871 strcpy(amode, "sae");
872 }
873 } else if (auth == 0 && wpa_auth == 0) {
874 strcpy(amode, "open");
875 } else if (auth == 1 && wpa_auth == 0) {
876 strcpy(amode, "shared");
877 } else if (auth == 0 && wpa_auth == 4) {
878 strcpy(amode, "wpapsk");
879 } else if (auth == 0 && wpa_auth == 128) {
880 strcpy(amode, "wpa2psk");
881 } else if (auth == 0 && wpa_auth == 132) {
882 strcpy(amode, "wpawpa2psk");
883 }
884}
885
886static void
887wl_ext_get_emode(struct wl_if_info *cur_if, char *emode)
888{
889 struct net_device *dev = cur_if->dev;
890 int wsec=0;
891
892 wl_ext_iovar_getint(dev, "wsec", &wsec);
893
894 if (cur_if->ifmode == IMESH_MODE) {
895 if (wsec == 0) {
896 strcpy(emode, "none");
897 } else {
898 strcpy(emode, "sae");
899 }
900 } else if (wsec == 0) {
901 strcpy(emode, "none");
902 } else if (wsec == 1) {
903 strcpy(emode, "wep");
904 } else if (wsec == 2 || wsec == 10) {
905 strcpy(emode, "tkip");
906 } else if (wsec == 4 || wsec == 12) {
907 strcpy(emode, "aes");
908 } else if (wsec == 6 || wsec == 14) {
909 strcpy(emode, "tkipaes");
910 }
911}
912
91a2c117 913static int
d964ce36 914wl_ext_set_amode(struct wl_if_info *cur_if)
91a2c117
RC
915{
916 struct net_device *dev = cur_if->dev;
917 authmode_t amode = cur_if->amode;
918 int auth=0, wpa_auth=0;
919
d964ce36 920 if (cur_if->ifmode == IMESH_MODE) {
921 if (amode == AUTH_SAE) {
922 auth = 0;
923 wpa_auth = 128;
924 ANDROID_INFO(("%s: Authentication: SAE\n", __FUNCTION__));
925 } else {
926 auth = 0;
927 wpa_auth = 0;
928 ANDROID_INFO(("%s: Authentication: Open System\n", __FUNCTION__));
929 }
930 } else if (amode == AUTH_OPEN) {
91a2c117
RC
931 auth = 0;
932 wpa_auth = 0;
d964ce36 933 ANDROID_INFO(("%s: Authentication: Open System\n", __FUNCTION__));
91a2c117
RC
934 } else if (amode == AUTH_SHARED) {
935 auth = 1;
936 wpa_auth = 0;
d964ce36 937 ANDROID_INFO(("%s: Authentication: Shared Key\n", __FUNCTION__));
91a2c117
RC
938 } else if (amode == AUTH_WPAPSK) {
939 auth = 0;
940 wpa_auth = 4;
d964ce36 941 ANDROID_INFO(("%s: Authentication: WPA-PSK\n", __FUNCTION__));
91a2c117
RC
942 } else if (amode == AUTH_WPA2PSK) {
943 auth = 0;
944 wpa_auth = 128;
d964ce36 945 ANDROID_INFO(("%s: Authentication: WPA2-PSK\n", __FUNCTION__));
91a2c117
RC
946 } else if (amode == AUTH_WPAWPA2PSK) {
947 auth = 0;
948 wpa_auth = 132;
d964ce36 949 ANDROID_INFO(("%s: Authentication: WPA/WPA2-PSK\n", __FUNCTION__));
91a2c117 950 }
dfb0f3ae
RC
951 if (cur_if->ifmode == IMESH_MODE) {
952 s32 val = WL_BSSTYPE_MESH;
953 wl_ext_ioctl(dev, WLC_SET_INFRA, &val, sizeof(val), 1);
954 } else if (cur_if->ifmode == ISTA_MODE) {
955 s32 val = WL_BSSTYPE_INFRA;
956 wl_ext_ioctl(dev, WLC_SET_INFRA, &val, sizeof(val), 1);
957 }
91a2c117
RC
958 wl_ext_iovar_setint(dev, "auth", auth);
959
960 wl_ext_iovar_setint(dev, "wpa_auth", wpa_auth);
961
962 return 0;
963}
964
965static int
966wl_ext_set_emode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params)
967{
968 struct net_device *dev = cur_if->dev;
969 int wsec=0;
970 struct wl_wsec_key wsec_key;
971 wsec_pmk_t psk;
dfb0f3ae 972 authmode_t amode = cur_if->amode;
91a2c117
RC
973 encmode_t emode = cur_if->emode;
974 char *key = cur_if->key;
dfb0f3ae 975 s8 iovar_buf[WLC_IOCTL_SMLEN];
d964ce36 976 struct dhd_pub *dhd = dhd_get_pub(dev);
91a2c117
RC
977
978 memset(&wsec_key, 0, sizeof(wsec_key));
979 memset(&psk, 0, sizeof(psk));
d964ce36 980
981 if (cur_if->ifmode == IMESH_MODE) {
982 if (amode == AUTH_SAE) {
983 wsec = 4;
984 ANDROID_INFO(("%s: Encryption: AES\n", __FUNCTION__));
985 } else {
986 wsec = 0;
987 ANDROID_INFO(("%s: Encryption: No securiy\n", __FUNCTION__));
988 }
989 } else if (emode == ENC_NONE) {
91a2c117 990 wsec = 0;
d964ce36 991 ANDROID_INFO(("%s: Encryption: No securiy\n", __FUNCTION__));
91a2c117
RC
992 } else if (emode == ENC_WEP) {
993 wsec = 1;
994 wl_ext_parse_wep(key, &wsec_key);
d964ce36 995 ANDROID_INFO(("%s: Encryption: WEP\n", __FUNCTION__));
996 ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, wsec_key.data));
91a2c117
RC
997 } else if (emode == ENC_TKIP) {
998 wsec = 2;
999 psk.key_len = strlen(key);
1000 psk.flags = WSEC_PASSPHRASE;
1001 memcpy(psk.key, key, strlen(key));
d964ce36 1002 ANDROID_INFO(("%s: Encryption: TKIP\n", __FUNCTION__));
1003 ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key));
1004 } else if (emode == ENC_AES || amode == AUTH_SAE) {
91a2c117
RC
1005 wsec = 4;
1006 psk.key_len = strlen(key);
1007 psk.flags = WSEC_PASSPHRASE;
1008 memcpy(psk.key, key, strlen(key));
d964ce36 1009 ANDROID_INFO(("%s: Encryption: AES\n", __FUNCTION__));
1010 ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key));
91a2c117
RC
1011 } else if (emode == ENC_TKIPAES) {
1012 wsec = 6;
1013 psk.key_len = strlen(key);
1014 psk.flags = WSEC_PASSPHRASE;
1015 memcpy(psk.key, key, strlen(key));
d964ce36 1016 ANDROID_INFO(("%s: Encryption: TKIP/AES\n", __FUNCTION__));
1017 ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key));
1018 }
1019 if (dhd->conf->chip == BCM43430_CHIP_ID && cur_if->ifidx > 0 && wsec >= 2 &&
1020 apsta_params->apstamode == IAPSTA_MODE) {
1021 wsec |= 0x8; // terence 20180628: fix me, this is a workaround
91a2c117
RC
1022 }
1023
1024 wl_ext_iovar_setint(dev, "wsec", wsec);
1025
dfb0f3ae 1026 if (cur_if->ifmode == IMESH_MODE) {
d964ce36 1027 if (amode == AUTH_SAE) {
1028 ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, key));
dfb0f3ae
RC
1029 wl_ext_iovar_setint(dev, "mesh_auth_proto", 1);
1030 wl_ext_iovar_setint(dev, "mfp", WL_MFP_REQUIRED);
1031 wl_ext_iovar_setbuf(dev, "sae_password", key, strlen(key),
1032 iovar_buf, WLC_IOCTL_SMLEN, NULL);
1033 } else {
1034 wl_ext_iovar_setint(dev, "mesh_auth_proto", 0);
1035 wl_ext_iovar_setint(dev, "mfp", WL_MFP_NONE);
1036 }
1037 } else if (emode == ENC_WEP) {
91a2c117
RC
1038 wl_ext_ioctl(dev, WLC_SET_KEY, &wsec_key, sizeof(wsec_key), 1);
1039 } else if (emode == ENC_TKIP || emode == ENC_AES || emode == ENC_TKIPAES) {
1040 if (dev) {
1041 if (cur_if->ifmode == ISTA_MODE)
1042 wl_ext_iovar_setint(dev, "sup_wpa", 1);
1043 wl_ext_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk), 1);
1044 } else {
1045 ANDROID_ERROR(("%s: apdev is null\n", __FUNCTION__));
1046 }
1047 }
1048
1049 return 0;
1050}
1051
d964ce36 1052static uint16
1053wl_ext_get_chan(struct net_device *dev)
1054{
1055 struct wl_apsta_params *apsta_params = &g_apsta_params;
1056 int ret = 0;
1057 uint16 chan = 0, ctl_chan;
1058 struct ether_addr bssid;
1059 u32 chanspec = 0;
1060
1061 ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
1062 if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
1063 if (wldev_iovar_getint(dev, "chanspec", (s32 *)&chanspec) == BCME_OK) {
1064 chanspec = wl_ext_chspec_driver_to_host(apsta_params->ioctl_ver, chanspec);
1065 ctl_chan = wf_chspec_ctlchan(chanspec);
1066 chan = (u16)(ctl_chan & 0x00FF);
1067 ANDROID_INFO(("%s: cur_chan=%d(0x%x)\n", __FUNCTION__,
1068 chan, chanspec));
1069 return chan;
1070 }
1071 }
1072
1073 return 0;
1074}
1075
1076static chanspec_t
1077wl_ext_get_chanspec(struct wl_apsta_params *apsta_params,
1078 struct net_device *dev, uint16 channel)
1079{
1080 s32 _chan = channel;
1081 chanspec_t chspec = 0;
1082 chanspec_t fw_chspec = 0;
1083 u32 bw = WL_CHANSPEC_BW_20;
1084 s32 err = BCME_OK;
1085 s32 bw_cap = 0;
1086 s8 iovar_buf[WLC_IOCTL_SMLEN];
1087 struct {
1088 u32 band;
1089 u32 bw_cap;
1090 } param = {0, 0};
1091 uint band;
1092
1093 if (_chan <= CH_MAX_2G_CHANNEL)
1094 band = IEEE80211_BAND_2GHZ;
1095 else
1096 band = IEEE80211_BAND_5GHZ;
1097
1098 if (band == IEEE80211_BAND_5GHZ) {
1099 param.band = WLC_BAND_5G;
1100 err = wldev_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
1101 iovar_buf, WLC_IOCTL_SMLEN, NULL);
1102 if (err) {
1103 if (err != BCME_UNSUPPORTED) {
1104 ANDROID_ERROR(("bw_cap failed, %d\n", err));
1105 return err;
1106 } else {
1107 err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
1108 if (err) {
1109 ANDROID_ERROR(("error get mimo_bw_cap (%d)\n", err));
1110 }
1111 if (bw_cap != WLC_N_BW_20ALL)
1112 bw = WL_CHANSPEC_BW_40;
1113 }
1114 } else {
1115 if (WL_BW_CAP_80MHZ(iovar_buf[0]))
1116 bw = WL_CHANSPEC_BW_80;
1117 else if (WL_BW_CAP_40MHZ(iovar_buf[0]))
1118 bw = WL_CHANSPEC_BW_40;
1119 else
1120 bw = WL_CHANSPEC_BW_20;
1121 }
1122 }
1123 else if (band == IEEE80211_BAND_2GHZ)
1124 bw = WL_CHANSPEC_BW_20;
1125
1126set_channel:
1127 chspec = wf_channel2chspec(_chan, bw);
1128 if (wf_chspec_valid(chspec)) {
1129 fw_chspec = wl_ext_chspec_host_to_driver(apsta_params->ioctl_ver, chspec);
1130 if (fw_chspec == INVCHANSPEC) {
1131 ANDROID_ERROR(("%s: failed to convert host chanspec to fw chanspec\n",
1132 __FUNCTION__));
1133 fw_chspec = 0;
1134 }
1135 } else {
1136 if (bw == WL_CHANSPEC_BW_80)
1137 bw = WL_CHANSPEC_BW_40;
1138 else if (bw == WL_CHANSPEC_BW_40)
1139 bw = WL_CHANSPEC_BW_20;
1140 else
1141 bw = 0;
1142 if (bw)
1143 goto set_channel;
1144 ANDROID_ERROR(("%s: Invalid chanspec 0x%x\n", __FUNCTION__, chspec));
1145 err = BCME_ERROR;
1146 }
1147
1148 return fw_chspec;
1149}
1150
dfb0f3ae
RC
1151static void
1152wl_ext_ch_to_chanspec(int ch, struct wl_join_params *join_params,
1153 size_t *join_params_size)
91a2c117 1154{
91a2c117 1155 struct wl_apsta_params *apsta_params = &g_apsta_params;
dfb0f3ae 1156 chanspec_t chanspec = 0;
91a2c117 1157
dfb0f3ae
RC
1158 if (ch != 0) {
1159 join_params->params.chanspec_num = 1;
1160 join_params->params.chanspec_list[0] = ch;
1161
1162 if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
1163 chanspec |= WL_CHANSPEC_BAND_2G;
1164 else
1165 chanspec |= WL_CHANSPEC_BAND_5G;
1166
1167 chanspec |= WL_CHANSPEC_BW_20;
1168 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
1169
1170 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
1171 join_params->params.chanspec_num * sizeof(chanspec_t);
1172
1173 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
1174 join_params->params.chanspec_list[0] |= chanspec;
1175 join_params->params.chanspec_list[0] =
1176 wl_ext_chspec_host_to_driver(apsta_params->ioctl_ver,
1177 join_params->params.chanspec_list[0]);
1178
1179 join_params->params.chanspec_num =
1180 htod32(join_params->params.chanspec_num);
1181 ANDROID_TRACE(("join_params->params.chanspec_list[0]= %X, %d channels\n",
1182 join_params->params.chanspec_list[0],
1183 join_params->params.chanspec_num));
91a2c117 1184 }
dfb0f3ae 1185}
91a2c117 1186
dfb0f3ae
RC
1187static s32
1188wl_ext_connect(struct wl_if_info *cur_if)
1189{
1190 struct wl_apsta_params *apsta_params = &g_apsta_params;
1191 wl_extjoin_params_t *ext_join_params;
1192 struct wl_join_params join_params;
1193 size_t join_params_size;
1194 s32 err = 0;
1195 u32 chan_cnt = 0;
1196 s8 iovar_buf[WLC_IOCTL_SMLEN];
1197
1198 if (cur_if->channel) {
1199 chan_cnt = 1;
1200 }
1201
1202 /*
1203 * Join with specific BSSID and cached SSID
1204 * If SSID is zero join based on BSSID only
1205 */
1206 join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
1207 chan_cnt * sizeof(chanspec_t);
1208 ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
1209 if (ext_join_params == NULL) {
1210 err = -ENOMEM;
1211 goto exit;
1212 }
d964ce36 1213 ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID),
1214 strlen(cur_if->ssid));
dfb0f3ae
RC
1215 memcpy(&ext_join_params->ssid.SSID, cur_if->ssid, ext_join_params->ssid.SSID_len);
1216 ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
1217 /* increate dwell time to receive probe response or detect Beacon
1218 * from target AP at a noisy air only during connect command
1219 */
1220 ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1;
1221 ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
1222 /* Set up join scan parameters */
1223 ext_join_params->scan.scan_type = -1;
1224 ext_join_params->scan.nprobes = chan_cnt ?
1225 (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
1226 ext_join_params->scan.home_time = -1;
1227
1228 if (memcmp(&ether_null, &cur_if->bssid, ETHER_ADDR_LEN))
1229 memcpy(&ext_join_params->assoc.bssid, &cur_if->bssid, ETH_ALEN);
1230 else
1231 memcpy(&ext_join_params->assoc.bssid, &ether_bcast, ETH_ALEN);
1232 ext_join_params->assoc.chanspec_num = chan_cnt;
1233 if (chan_cnt) {
1234 u16 channel, band, bw, ctl_sb;
1235 chanspec_t chspec;
1236 channel = cur_if->channel;
1237 band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
1238 : WL_CHANSPEC_BAND_5G;
1239 bw = WL_CHANSPEC_BW_20;
1240 ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
1241 chspec = (channel | band | bw | ctl_sb);
1242 ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
1243 ext_join_params->assoc.chanspec_list[0] |= chspec;
1244 ext_join_params->assoc.chanspec_list[0] =
1245 wl_ext_chspec_host_to_driver(apsta_params->ioctl_ver,
1246 ext_join_params->assoc.chanspec_list[0]);
1247 }
1248 ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
1249 if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
1250 ANDROID_INFO(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
1251 ext_join_params->ssid.SSID_len));
1252 }
1253
d964ce36 1254 err = wl_ext_iovar_setbuf_bsscfg(cur_if->dev, "join", ext_join_params,
1255 join_params_size, iovar_buf, WLC_IOCTL_SMLEN, cur_if->bssidx, NULL);
dfb0f3ae
RC
1256
1257 printf("Connecting with " MACDBG " channel (%d) ssid \"%s\", len (%d)\n\n",
1258 MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)), cur_if->channel,
1259 ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len);
1260
1261 kfree(ext_join_params);
1262 if (err) {
1263 if (err == BCME_UNSUPPORTED) {
1264 ANDROID_TRACE(("join iovar is not supported\n"));
1265 goto set_ssid;
1266 } else {
1267 ANDROID_ERROR(("error (%d)\n", err));
1268 goto exit;
1269 }
1270 } else
1271 goto exit;
1272
1273set_ssid:
1274 memset(&join_params, 0, sizeof(join_params));
1275 join_params_size = sizeof(join_params.ssid);
1276
1277 join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), strlen(cur_if->ssid));
1278 memcpy(&join_params.ssid.SSID, cur_if->ssid, join_params.ssid.SSID_len);
1279 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
1280 if (memcmp(&ether_null, &cur_if->bssid, ETHER_ADDR_LEN))
1281 memcpy(&join_params.params.bssid, &cur_if->bssid, ETH_ALEN);
1282 else
1283 memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
1284
1285 wl_ext_ch_to_chanspec(cur_if->channel, &join_params, &join_params_size);
1286 ANDROID_TRACE(("join_param_size %zu\n", join_params_size));
1287
1288 if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
1289 ANDROID_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
1290 join_params.ssid.SSID_len));
91a2c117 1291 }
dfb0f3ae
RC
1292 err = wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &join_params,join_params_size, 1);
1293 if (err) {
1294 ANDROID_ERROR(("error (%d)\n", err));
1295 }
1296
1297exit:
1298 return err;
1299
1300}
1301
d964ce36 1302static void
1303wl_ext_wait_netif_change(struct wl_apsta_params *apsta_params,
1304 bool need_rtnl_unlock)
1305{
1306 if (need_rtnl_unlock)
1307 rtnl_unlock();
1308 wait_event_interruptible_timeout(apsta_params->netif_change_event,
1309 apsta_params->netif_change, msecs_to_jiffies(1500));
1310 if (need_rtnl_unlock)
1311 rtnl_lock();
1312}
1313
dfb0f3ae
RC
1314static void
1315wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_params)
1316{
1317 struct dhd_pub *dhd;
d964ce36 1318 apstamode_t apstamode = apsta_params->apstamode;
dfb0f3ae
RC
1319 wl_interface_create_t iface;
1320 struct wl_if_info *cur_if;
1321 wlc_ssid_t ssid = { 0, {0} };
1322 s8 iovar_buf[WLC_IOCTL_SMLEN];
1323 wl_country_t cspec = {{0}, 0, {0}};
1324 wl_p2p_if_t ifreq;
1325 s32 val = 0;
d964ce36 1326 int i, dfs = 1, pm = 0;
91a2c117 1327
dfb0f3ae
RC
1328 dhd = dhd_get_pub(dev);
1329
dfb0f3ae
RC
1330 for (i=0; i<MAX_IF_NUM; i++) {
1331 cur_if = &apsta_params->if_info[i];
d964ce36 1332 if (i == 1 && !strlen(cur_if->ifname))
1333 strcpy(cur_if->ifname, "wlan1");
1334 if (i == 2 && !strlen(cur_if->ifname))
1335 strcpy(cur_if->ifname, "wlan2");
dfb0f3ae
RC
1336 if (cur_if->ifmode == ISTA_MODE) {
1337 cur_if->channel = 0;
1338 cur_if->maxassoc = -1;
1339 cur_if->ifstate = IF_STATE_INIT;
d964ce36 1340 cur_if->prio = PRIO_STA;
1341 cur_if->prefix = 'S';
1342 snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta");
dfb0f3ae
RC
1343 } else if (cur_if->ifmode == IAP_MODE) {
1344 cur_if->channel = 1;
1345 cur_if->maxassoc = -1;
1346 cur_if->ifstate = IF_STATE_INIT;
d964ce36 1347 cur_if->prio = PRIO_AP;
1348 cur_if->prefix = 'A';
1349 snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap");
dfb0f3ae
RC
1350 dfs = 0;
1351 } else if (cur_if->ifmode == IMESH_MODE) {
1352 cur_if->channel = 1;
1353 cur_if->maxassoc = -1;
1354 cur_if->ifstate = IF_STATE_INIT;
d964ce36 1355 cur_if->prio = PRIO_MESH;
1356 cur_if->prefix = 'M';
1357 snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh");
dfb0f3ae
RC
1358 dfs = 0;
1359 }
1360 }
d964ce36 1361
1362 if (!dfs && !apsta_params->vsdb) {
dfb0f3ae 1363 dhd_conf_get_country(dhd, &cspec);
d964ce36 1364 if (!dhd_conf_map_country_list(dhd, &cspec)) {
dfb0f3ae
RC
1365 dhd_conf_set_country(dhd, &cspec);
1366 dhd_bus_country_set(dev, &cspec, TRUE);
1367 }
d964ce36 1368 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
1369 wl_ext_iovar_setint(dev, "dfs_chan_disable", 1);
1370 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
1371 }
1372
1373 if (FW_SUPPORTED(dhd, rsdb)) {
1374 if (apstamode == IDUALAP_MODE)
1375 apsta_params->rsdb = TRUE;
1376 else if (apstamode == ISTAAPAP_MODE)
1377 apsta_params->rsdb = FALSE;
1378 if (apstamode == IDUALAP_MODE || apstamode == ISTAAPAP_MODE ||
1379 apstamode == IMESHONLY_MODE || apstamode == IMESHSTA_MODE ||
1380 apstamode == IMESHAP_MODE || apstamode == IMESHAPSTA_MODE ||
1381 apstamode == IMESHAPAP_MODE) {
1382 wl_config_t rsdb_mode_cfg = {0, 0};
1383 if (apsta_params->rsdb)
1384 rsdb_mode_cfg.config = 1;
1385 printf("%s: set rsdb_mode %d\n", __FUNCTION__, rsdb_mode_cfg.config);
1386 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
1387 wl_ext_iovar_setbuf(dev, "rsdb_mode", &rsdb_mode_cfg,
1388 sizeof(rsdb_mode_cfg), iovar_buf, sizeof(iovar_buf), NULL);
1389 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
1390 }
1391 } else {
1392 apsta_params->rsdb = FALSE;
dfb0f3ae 1393 }
91a2c117 1394
d964ce36 1395 if (apstamode == ISTAONLY_MODE) {
91a2c117
RC
1396 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
1397 wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
1398 // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
1399 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
d964ce36 1400 } else if (apstamode == IAPONLY_MODE) {
91a2c117 1401 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
010c3a89 1402#ifdef ARP_OFFLOAD_SUPPORT
91a2c117
RC
1403 /* IF SoftAP is enabled, disable arpoe */
1404 dhd_arp_offload_set(dhd, 0);
1405 dhd_arp_offload_enable(dhd, FALSE);
1406#endif /* ARP_OFFLOAD_SUPPORT */
1407 wl_ext_iovar_setint(dev, "mpc", 0);
1408 wl_ext_iovar_setint(dev, "apsta", 0);
1409 val = 1;
1410 wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1);
dfb0f3ae
RC
1411#ifdef PROP_TXSTATUS_VSDB
1412#if defined(BCMSDIO)
1413 if (!FW_SUPPORTED(dhd, rsdb) && !disable_proptx) {
1414 bool enabled;
1415 dhd_wlfc_get_enable(dhd, &enabled);
1416 if (!enabled) {
1417 dhd_wlfc_init(dhd);
1418 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
1419 }
91a2c117 1420 }
dfb0f3ae
RC
1421#endif
1422#endif /* PROP_TXSTATUS_VSDB */
1423 }
d964ce36 1424 else if (apstamode == IAPSTA_MODE) {
91a2c117 1425 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
dfb0f3ae 1426 wl_ext_iovar_setint(dev, "mpc", 0);
91a2c117
RC
1427 wl_ext_iovar_setint(dev, "apsta", 1);
1428 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
d964ce36 1429 apsta_params->netif_change = FALSE;
91a2c117
RC
1430 if (FW_SUPPORTED(dhd, rsdb)) {
1431 bzero(&iface, sizeof(wl_interface_create_t));
1432 iface.ver = WL_INTERFACE_CREATE_VER;
1433 iface.flags = WL_INTERFACE_CREATE_AP;
d964ce36 1434 wl_ext_iovar_getbuf(dev, "interface_create", &iface,
1435 sizeof(iface), iovar_buf, WLC_IOCTL_SMLEN, NULL);
91a2c117 1436 } else {
d964ce36 1437 wl_ext_iovar_setbuf_bsscfg(dev, "ssid", &ssid, sizeof(ssid),
1438 iovar_buf, WLC_IOCTL_SMLEN, 1, NULL);
91a2c117 1439 }
d964ce36 1440 wl_ext_wait_netif_change(apsta_params, TRUE);
91a2c117 1441 }
d964ce36 1442 else if (apstamode == IDUALAP_MODE) {
91a2c117 1443 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
91a2c117 1444 /* IF SoftAP is enabled, disable arpoe or wlan1 will ping fail */
010c3a89 1445#ifdef ARP_OFFLOAD_SUPPORT
91a2c117
RC
1446 /* IF SoftAP is enabled, disable arpoe */
1447 dhd_arp_offload_set(dhd, 0);
1448 dhd_arp_offload_enable(dhd, FALSE);
1449#endif /* ARP_OFFLOAD_SUPPORT */
dfb0f3ae 1450 wl_ext_iovar_setint(dev, "mpc", 0);
d964ce36 1451 wl_ext_iovar_setint(dev, "mbcn", 1);
dfb0f3ae
RC
1452 wl_ext_iovar_setint(dev, "apsta", 0);
1453 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
1454 val = 1;
1455 wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1);
91a2c117
RC
1456 bzero(&iface, sizeof(wl_interface_create_t));
1457 iface.ver = WL_INTERFACE_CREATE_VER;
1458 iface.flags = WL_INTERFACE_CREATE_AP;
dfb0f3ae 1459 apsta_params->netif_change = FALSE;
d964ce36 1460 wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
1461 iovar_buf, WLC_IOCTL_SMLEN, NULL);
1462 wl_ext_wait_netif_change(apsta_params, TRUE);
91a2c117 1463 }
d964ce36 1464 else if (apstamode == ISTAAPAP_MODE) {
1465 u8 rand_bytes[2] = {0, };
1466 get_random_bytes(&rand_bytes, sizeof(rand_bytes));
dfb0f3ae
RC
1467 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
1468 wl_ext_iovar_setint(dev, "mpc", 0);
d964ce36 1469 wl_ext_iovar_setint(dev, "mbss", 1);
dfb0f3ae 1470 wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
91a2c117 1471 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
d964ce36 1472 // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
dfb0f3ae
RC
1473 bzero(&iface, sizeof(wl_interface_create_t));
1474 iface.ver = WL_INTERFACE_CREATE_VER;
d964ce36 1475 iface.flags = WL_INTERFACE_CREATE_AP | WL_INTERFACE_MAC_USE;
1476 memcpy(&iface.mac_addr, dev->dev_addr, ETHER_ADDR_LEN);
1477 iface.mac_addr.octet[0] |= 0x02;
1478 iface.mac_addr.octet[5] += 0x01;
1479 memcpy(&iface.mac_addr.octet[3], rand_bytes, sizeof(rand_bytes));
dfb0f3ae 1480 apsta_params->netif_change = FALSE;
d964ce36 1481 wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
1482 iovar_buf, WLC_IOCTL_SMLEN, NULL);
1483 wl_ext_wait_netif_change(apsta_params, TRUE);
1484 bzero(&iface, sizeof(wl_interface_create_t));
1485 iface.ver = WL_INTERFACE_CREATE_VER;
1486 iface.flags = WL_INTERFACE_CREATE_AP | WL_INTERFACE_MAC_USE;
1487 memcpy(&iface.mac_addr, dev->dev_addr, ETHER_ADDR_LEN);
1488 iface.mac_addr.octet[0] |= 0x02;
1489 iface.mac_addr.octet[5] += 0x02;
1490 memcpy(&iface.mac_addr.octet[3], rand_bytes, sizeof(rand_bytes));
1491 apsta_params->netif_change = FALSE;
1492 wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
1493 iovar_buf, WLC_IOCTL_SMLEN, NULL);
1494 wl_ext_wait_netif_change(apsta_params, TRUE);
1495 }
1496 else if (apstamode == IMESHONLY_MODE) {
1497 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
1498 wl_ext_iovar_setint(dev, "mpc", 0);
1499 wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
1500 wl_ext_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), 1);
1501 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
1502 // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
1503 }
1504 else if (apstamode == IMESHSTA_MODE) {
dfb0f3ae
RC
1505 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
1506 wl_ext_iovar_setint(dev, "mpc", 0);
d964ce36 1507 wl_ext_iovar_setint(dev, "mbcn", 1);
1508 wl_ext_iovar_setint(dev, "apsta", 1);
1509 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
1510 bzero(&iface, sizeof(wl_interface_create_t));
1511 iface.ver = WL_INTERFACE_CREATE_VER;
1512 iface.flags = WL_INTERFACE_CREATE_STA;
1513 apsta_params->netif_change = FALSE;
1514 wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
1515 iovar_buf, WLC_IOCTL_SMLEN, NULL);
1516 wl_ext_wait_netif_change(apsta_params, TRUE);
1517 }
1518 else if (apstamode == IMESHAP_MODE) {
1519 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
1520 wl_ext_iovar_setint(dev, "mpc", 0);
1521 wl_ext_iovar_setint(dev, "mbcn", 1);
dfb0f3ae 1522 wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
d964ce36 1523 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
dfb0f3ae
RC
1524 // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
1525 bzero(&iface, sizeof(wl_interface_create_t));
1526 iface.ver = WL_INTERFACE_CREATE_VER;
1527 iface.flags = WL_INTERFACE_CREATE_AP;
dfb0f3ae 1528 apsta_params->netif_change = FALSE;
d964ce36 1529 wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
1530 iovar_buf, WLC_IOCTL_SMLEN, NULL);
1531 wl_ext_wait_netif_change(apsta_params, TRUE);
dfb0f3ae 1532 }
d964ce36 1533 else if (apstamode == IMESHAPSTA_MODE) {
dfb0f3ae
RC
1534 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
1535 wl_ext_iovar_setint(dev, "mpc", 0);
d964ce36 1536 wl_ext_iovar_setint(dev, "mbcn", 1);
dfb0f3ae 1537 wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
d964ce36 1538 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
dfb0f3ae
RC
1539 // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
1540 bzero(&iface, sizeof(wl_interface_create_t));
1541 iface.ver = WL_INTERFACE_CREATE_VER;
1542 iface.flags = WL_INTERFACE_CREATE_AP;
dfb0f3ae 1543 apsta_params->netif_change = FALSE;
d964ce36 1544 wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
1545 iovar_buf, WLC_IOCTL_SMLEN, NULL);
1546 wl_ext_wait_netif_change(apsta_params, TRUE);
dfb0f3ae
RC
1547 bzero(&iface, sizeof(wl_interface_create_t));
1548 iface.ver = WL_INTERFACE_CREATE_VER;
1549 iface.flags = WL_INTERFACE_CREATE_STA;
dfb0f3ae 1550 apsta_params->netif_change = FALSE;
d964ce36 1551 wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
1552 iovar_buf, WLC_IOCTL_SMLEN, NULL);
1553 wl_ext_wait_netif_change(apsta_params, TRUE);
dfb0f3ae 1554 }
d964ce36 1555 else if (apstamode == IMESHAPAP_MODE) {
dfb0f3ae
RC
1556 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
1557 wl_ext_iovar_setint(dev, "mpc", 0);
d964ce36 1558 wl_ext_iovar_setint(dev, "mbcn", 1);
dfb0f3ae 1559 wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
d964ce36 1560 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
dfb0f3ae
RC
1561 // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
1562 bzero(&iface, sizeof(wl_interface_create_t));
1563 iface.ver = WL_INTERFACE_CREATE_VER;
1564 iface.flags = WL_INTERFACE_CREATE_AP;
dfb0f3ae 1565 apsta_params->netif_change = FALSE;
d964ce36 1566 wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
1567 iovar_buf, WLC_IOCTL_SMLEN, NULL);
1568 wl_ext_wait_netif_change(apsta_params, TRUE);
dfb0f3ae
RC
1569 bzero(&iface, sizeof(wl_interface_create_t));
1570 iface.ver = WL_INTERFACE_CREATE_VER;
1571 iface.flags = WL_INTERFACE_CREATE_AP;
dfb0f3ae 1572 apsta_params->netif_change = FALSE;
d964ce36 1573 wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
1574 iovar_buf, WLC_IOCTL_SMLEN, NULL);
1575 wl_ext_wait_netif_change(apsta_params, TRUE);
91a2c117 1576 }
d964ce36 1577 else if (apstamode == IGOSTA_MODE) {
91a2c117
RC
1578 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
1579 wl_ext_iovar_setint(dev, "apsta", 1);
1580 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
1581 bzero(&ifreq, sizeof(wl_p2p_if_t));
dfb0f3ae 1582 ifreq.type = htod32(WL_P2P_IF_GO);
d964ce36 1583 apsta_params->netif_change = FALSE;
91a2c117
RC
1584 wl_ext_iovar_setbuf(dev, "p2p_ifadd", &ifreq, sizeof(ifreq),
1585 iovar_buf, WLC_IOCTL_SMLEN, NULL);
d964ce36 1586 wl_ext_wait_netif_change(apsta_params, TRUE);
91a2c117
RC
1587 }
1588
1589 wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver);
91a2c117 1590 apsta_params->init = TRUE;
d964ce36 1591
1592 printf("%s: apstamode=%d\n", __FUNCTION__, apstamode);
91a2c117
RC
1593}
1594
1595static int
dfb0f3ae 1596wl_ext_isam_init(struct net_device *dev, char *command, int total_len)
91a2c117 1597{
dfb0f3ae
RC
1598 char *pch, *pick_tmp, *pick_tmp2, *param;
1599 struct wl_apsta_params *apsta_params = &g_apsta_params;
1600 struct dhd_pub *dhd;
1601 int i;
91a2c117 1602
dfb0f3ae
RC
1603 if (apsta_params->init) {
1604 ANDROID_ERROR(("%s: don't init twice\n", __FUNCTION__));
1605 return -1;
1606 }
1607
1608 dhd = dhd_get_pub(dev);
1609
1610 ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
1611
1612 pick_tmp = command;
1613 param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_init
1614 param = bcmstrtok(&pick_tmp, " ", 0);
1615 while (param != NULL) {
1616 if (!strcmp(param, "mode")) {
1617 pch = NULL;
1618 pick_tmp2 = bcmstrtok(&pick_tmp, " ", 0);
1619 if (pick_tmp2) {
1620 if (!strcmp(pick_tmp2, "sta")) {
1621 apsta_params->apstamode = ISTAONLY_MODE;
1622 } else if (!strcmp(pick_tmp2, "ap")) {
1623 apsta_params->apstamode = IAPONLY_MODE;
1624 } else if (!strcmp(pick_tmp2, "sta-ap")) {
1625 apsta_params->apstamode = IAPSTA_MODE;
1626 } else if (!strcmp(pick_tmp2, "ap-ap")) {
1627 apsta_params->apstamode = IDUALAP_MODE;
d964ce36 1628 } else if (!strcmp(pick_tmp2, "sta-ap-ap")) {
1629 apsta_params->apstamode = ISTAAPAP_MODE;
dfb0f3ae
RC
1630 } else if (!strcmp(pick_tmp2, "mesh")) {
1631 apsta_params->apstamode = IMESHONLY_MODE;
d964ce36 1632 } else if (!strcmp(pick_tmp2, "mesh-sta") ||
1633 !strcmp(pick_tmp2, "sta-mesh")) {
dfb0f3ae 1634 apsta_params->apstamode = IMESHSTA_MODE;
d964ce36 1635 } else if (!strcmp(pick_tmp2, "mesh-ap") ||
1636 !strcmp(pick_tmp2, "ap-mesh")) {
dfb0f3ae 1637 apsta_params->apstamode = IMESHAP_MODE;
d964ce36 1638 } else if (!strcmp(pick_tmp2, "mesh-ap-sta") ||
1639 !strcmp(pick_tmp2, "sta-ap-mesh") ||
1640 !strcmp(pick_tmp2, "sta-mesh-ap")) {
dfb0f3ae 1641 apsta_params->apstamode = IMESHAPSTA_MODE;
d964ce36 1642 } else if (!strcmp(pick_tmp2, "mesh-ap-ap") ||
1643 !strcmp(pick_tmp2, "ap-ap-mesh")) {
dfb0f3ae
RC
1644 apsta_params->apstamode = IMESHAPAP_MODE;
1645 } else if (!strcmp(pick_tmp2, "apsta")) {
1646 apsta_params->apstamode = IAPSTA_MODE;
1647 apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE;
1648 apsta_params->if_info[IF_VIF].ifmode = IAP_MODE;
1649 } else if (!strcmp(pick_tmp2, "dualap")) {
1650 apsta_params->apstamode = IDUALAP_MODE;
1651 apsta_params->if_info[IF_PIF].ifmode = IAP_MODE;
1652 apsta_params->if_info[IF_VIF].ifmode = IAP_MODE;
1653 } else if (!strcmp(pick_tmp2, "gosta")) {
1654 if (!FW_SUPPORTED(dhd, p2p)) {
1655 return -1;
1656 }
1657 apsta_params->apstamode = IGOSTA_MODE;
1658 apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE;
1659 apsta_params->if_info[IF_VIF].ifmode = IAP_MODE;
1660 } else {
1661 ANDROID_ERROR(("%s: mode [sta|ap|sta-ap|ap-ap]\n", __FUNCTION__));
1662 return -1;
1663 }
1664 pch = bcmstrtok(&pick_tmp2, " -", 0);
1665 for (i=0; i<MAX_IF_NUM && pch; i++) {
1666 if (!strcmp(pch, "sta"))
1667 apsta_params->if_info[i].ifmode = ISTA_MODE;
1668 else if (!strcmp(pch, "ap"))
1669 apsta_params->if_info[i].ifmode = IAP_MODE;
d964ce36 1670 else if (!strcmp(pch, "mesh")) {
1671 if (dhd->conf->fw_type != FW_TYPE_MESH) {
1672 ANDROID_ERROR(("%s: wrong fw type\n", __FUNCTION__));
1673 return -1;
1674 }
dfb0f3ae 1675 apsta_params->if_info[i].ifmode = IMESH_MODE;
d964ce36 1676 }
dfb0f3ae
RC
1677 pch = bcmstrtok(&pick_tmp2, " -", 0);
1678 }
1679 }
d964ce36 1680 }
1681 else if (!strcmp(param, "rsdb")) {
1682 pch = bcmstrtok(&pick_tmp, " ", 0);
1683 if (pch) {
1684 if (!strcmp(pch, "y")) {
1685 apsta_params->rsdb = TRUE;
1686 } else if (!strcmp(pch, "n")) {
1687 apsta_params->rsdb = FALSE;
1688 } else {
1689 ANDROID_ERROR(("%s: rsdb [y|n]\n", __FUNCTION__));
1690 return -1;
1691 }
1692 }
dfb0f3ae
RC
1693 } else if (!strcmp(param, "vsdb")) {
1694 pch = bcmstrtok(&pick_tmp, " ", 0);
1695 if (pch) {
1696 if (!strcmp(pch, "y")) {
1697 apsta_params->vsdb = TRUE;
1698 } else if (!strcmp(pch, "n")) {
1699 apsta_params->vsdb = FALSE;
1700 } else {
1701 ANDROID_ERROR(("%s: vsdb [y|n]\n", __FUNCTION__));
1702 return -1;
1703 }
1704 }
d964ce36 1705 } else if (!strcmp(param, "csa")) {
1706 pch = bcmstrtok(&pick_tmp, " ", 0);
1707 if (pch) {
1708 apsta_params->csa = (int)simple_strtol(pch, NULL, 0);
1709 }
dfb0f3ae
RC
1710 } else if (!strcmp(param, "ifname")) {
1711 pch = NULL;
1712 pick_tmp2 = bcmstrtok(&pick_tmp, " ", 0);
1713 if (pick_tmp2)
1714 pch = bcmstrtok(&pick_tmp2, " -", 0);
1715 for (i=0; i<MAX_IF_NUM && pch; i++) {
1716 strcpy(apsta_params->if_info[i].ifname, pch);
1717 pch = bcmstrtok(&pick_tmp2, " -", 0);
1718 }
1719 } else if (!strcmp(param, "vifname")) {
1720 pch = bcmstrtok(&pick_tmp, " ", 0);
1721 if (pch)
1722 strcpy(apsta_params->if_info[IF_VIF].ifname, pch);
1723 else {
1724 ANDROID_ERROR(("%s: vifname [wlan1]\n", __FUNCTION__));
1725 return -1;
1726 }
1727 }
1728 param = bcmstrtok(&pick_tmp, " ", 0);
1729 }
1730
1731 if (apsta_params->apstamode == 0) {
1732 ANDROID_ERROR(("%s: mode [sta|ap|sta-ap|ap-ap]\n", __FUNCTION__));
1733 return -1;
1734 }
1735
1736 wl_ext_iapsta_preinit(dev, apsta_params);
1737
1738 return 0;
1739}
1740
1741static int
1742wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
1743{
1744 char *pch, *pick_tmp;
1745 char name[20], data[100];
d964ce36 1746 int i, j, len;
dfb0f3ae
RC
1747 char *ifname_head = NULL;
1748
1749 typedef struct config_map_t {
1750 char name[20];
1751 char *head;
1752 char *tail;
1753 } config_map_t;
d964ce36 1754
dfb0f3ae
RC
1755 config_map_t config_map [] = {
1756 {" ifname ", NULL, NULL},
1757 {" ssid ", NULL, NULL},
1758 {" bssid ", NULL, NULL},
1759 {" bgnmode ", NULL, NULL},
1760 {" hidden ", NULL, NULL},
1761 {" maxassoc ", NULL, NULL},
1762 {" chan ", NULL, NULL},
1763 {" amode ", NULL, NULL},
1764 {" emode ", NULL, NULL},
1765 {" key ", NULL, NULL},
1766 };
1767 config_map_t *row, *row_prev;
91a2c117
RC
1768
1769 pick_tmp = command;
1770
1771 // reset head and tail
d964ce36 1772 for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
91a2c117
RC
1773 row = &config_map[i];
1774 row->head = NULL;
dfb0f3ae 1775 row->tail = pick_tmp + strlen(pick_tmp);
91a2c117
RC
1776 }
1777
1778 // pick head
d964ce36 1779 for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
91a2c117
RC
1780 row = &config_map[i];
1781 pch = strstr(pick_tmp, row->name);
1782 if (pch) {
1783 row->head = pch;
1784 }
1785 }
1786
1787 // sort by head
d964ce36 1788 for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]) - 1; i++) {
91a2c117 1789 row_prev = &config_map[i];
d964ce36 1790 for (j = i+1; j < sizeof(config_map)/sizeof(config_map[0]); j++) {
91a2c117
RC
1791 row = &config_map[j];
1792 if (row->head < row_prev->head) {
1793 strcpy(name, row_prev->name);
1794 strcpy(row_prev->name, row->name);
1795 strcpy(row->name, name);
1796 pch = row_prev->head;
1797 row_prev->head = row->head;
1798 row->head = pch;
1799 }
1800 }
1801 }
1802
1803 // pick tail
d964ce36 1804 for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]) - 1; i++) {
91a2c117
RC
1805 row_prev = &config_map[i];
1806 row = &config_map[i+1];
1807 if (row_prev->head) {
1808 row_prev->tail = row->head;
1809 }
1810 }
1811
1812 // remove name from head
d964ce36 1813 for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
91a2c117
RC
1814 row = &config_map[i];
1815 if (row->head) {
1816 if (!strcmp(row->name, " ifname ")) {
1817 ifname_head = row->head + 1;
1818 break;
1819 }
1820 row->head += strlen(row->name);
1821 }
1822 }
1823
d964ce36 1824 for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
91a2c117
RC
1825 row = &config_map[i];
1826 if (row->head) {
1827 memset(data, 0, sizeof(data));
d964ce36 1828 if (row->tail && row->tail > row->head) {
91a2c117
RC
1829 strncpy(data, row->head, row->tail-row->head);
1830 } else {
1831 strcpy(data, row->head);
1832 }
1833 pick_tmp = data;
1834
dfb0f3ae
RC
1835 if (!strcmp(row->name, " ifname ")) {
1836 break;
1837 } else if (!strcmp(row->name, " ssid ")) {
d964ce36 1838 len = strlen(pick_tmp);
1839 memset(cur_if->ssid, 0, sizeof(cur_if->ssid));
1840 if (pick_tmp[0] == '"' && pick_tmp[len-1] == '"')
1841 strncpy(cur_if->ssid, &pick_tmp[1], len-2);
1842 else
1843 strcpy(cur_if->ssid, pick_tmp);
91a2c117
RC
1844 } else if (!strcmp(row->name, " bssid ")) {
1845 pch = bcmstrtok(&pick_tmp, ": ", 0);
1846 for (j=0; j<6 && pch; j++) {
1847 ((u8 *)&cur_if->bssid)[j] = (int)simple_strtol(pch, NULL, 16);
1848 pch = bcmstrtok(&pick_tmp, ": ", 0);
1849 }
1850 } else if (!strcmp(row->name, " bgnmode ")) {
1851 if (!strcmp(pick_tmp, "b"))
1852 cur_if->bgnmode = IEEE80211B;
1853 else if (!strcmp(pick_tmp, "g"))
1854 cur_if->bgnmode = IEEE80211G;
1855 else if (!strcmp(pick_tmp, "bg"))
1856 cur_if->bgnmode = IEEE80211BG;
1857 else if (!strcmp(pick_tmp, "bgn"))
1858 cur_if->bgnmode = IEEE80211BGN;
1859 else if (!strcmp(pick_tmp, "bgnac"))
1860 cur_if->bgnmode = IEEE80211BGNAC;
1861 else {
1862 ANDROID_ERROR(("%s: bgnmode [b|g|bg|bgn|bgnac]\n", __FUNCTION__));
1863 return -1;
1864 }
1865 } else if (!strcmp(row->name, " hidden ")) {
1866 if (!strcmp(pick_tmp, "n"))
1867 cur_if->hidden = 0;
1868 else if (!strcmp(pick_tmp, "y"))
1869 cur_if->hidden = 1;
1870 else {
1871 ANDROID_ERROR(("%s: hidden [y|n]\n", __FUNCTION__));
1872 return -1;
1873 }
1874 } else if (!strcmp(row->name, " maxassoc ")) {
1875 cur_if->maxassoc = (int)simple_strtol(pick_tmp, NULL, 10);
1876 } else if (!strcmp(row->name, " chan ")) {
1877 cur_if->channel = (int)simple_strtol(pick_tmp, NULL, 10);
1878 } else if (!strcmp(row->name, " amode ")) {
1879 if (!strcmp(pick_tmp, "open"))
1880 cur_if->amode = AUTH_OPEN;
1881 else if (!strcmp(pick_tmp, "shared"))
1882 cur_if->amode = AUTH_SHARED;
1883 else if (!strcmp(pick_tmp, "wpapsk"))
1884 cur_if->amode = AUTH_WPAPSK;
1885 else if (!strcmp(pick_tmp, "wpa2psk"))
1886 cur_if->amode = AUTH_WPA2PSK;
1887 else if (!strcmp(pick_tmp, "wpawpa2psk"))
1888 cur_if->amode = AUTH_WPAWPA2PSK;
d964ce36 1889 else if (!strcmp(pick_tmp, "sae"))
1890 cur_if->amode = AUTH_SAE;
91a2c117
RC
1891 else {
1892 ANDROID_ERROR(("%s: amode [open|shared|wpapsk|wpa2psk|wpawpa2psk]\n",
1893 __FUNCTION__));
1894 return -1;
1895 }
1896 } else if (!strcmp(row->name, " emode ")) {
1897 if (!strcmp(pick_tmp, "none"))
1898 cur_if->emode = ENC_NONE;
1899 else if (!strcmp(pick_tmp, "wep"))
1900 cur_if->emode = ENC_WEP;
1901 else if (!strcmp(pick_tmp, "tkip"))
1902 cur_if->emode = ENC_TKIP;
1903 else if (!strcmp(pick_tmp, "aes"))
1904 cur_if->emode = ENC_AES;
1905 else if (!strcmp(pick_tmp, "tkipaes"))
1906 cur_if->emode = ENC_TKIPAES;
1907 else {
1908 ANDROID_ERROR(("%s: emode [none|wep|tkip|aes|tkipaes]\n",
1909 __FUNCTION__));
1910 return -1;
1911 }
1912 } else if (!strcmp(row->name, " key ")) {
d964ce36 1913 len = strlen(pick_tmp);
1914 memset(cur_if->key, 0, sizeof(cur_if->key));
1915 if (pick_tmp[0] == '"' && pick_tmp[len-1] == '"')
1916 strncpy(cur_if->key, &pick_tmp[1], len-2);
1917 else
1918 strcpy(cur_if->key, pick_tmp);
91a2c117
RC
1919 }
1920 }
1921 }
1922
1923 *pick_next = ifname_head;
1924 return 0;
1925}
1926
1927static int
1928wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len)
1929{
d964ce36 1930 int ret=0, i;
91a2c117
RC
1931 char *pch, *pch2, *pick_tmp, *pick_next=NULL, *param;
1932 struct wl_apsta_params *apsta_params = &g_apsta_params;
1933 char ifname[IFNAMSIZ+1];
d964ce36 1934 struct wl_if_info *cur_if = NULL;
91a2c117
RC
1935
1936 if (!apsta_params->init) {
1937 ANDROID_ERROR(("%s: please init first\n", __FUNCTION__));
1938 return -1;
1939 }
1940
1941 ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
1942
1943 pick_tmp = command;
1944 param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_config
1945
1946 while (pick_tmp != NULL) {
1947 memset(ifname, 0, IFNAMSIZ+1);
1948 if (!strncmp(pick_tmp, "ifname ", strlen("ifname "))) {
1949 pch = pick_tmp + strlen("ifname ");
1950 pch2 = strchr(pch, ' ');
1951 if (pch && pch2) {
1952 strncpy(ifname, pch, pch2-pch);
1953 } else {
1954 ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__));
1955 return -1;
1956 }
d964ce36 1957 for (i=0; i<MAX_IF_NUM; i++) {
1958 if (apsta_params->if_info[i].dev &&
1959 !strcmp(apsta_params->if_info[i].dev->name, ifname)) {
1960 cur_if = &apsta_params->if_info[i];
1961 break;
1962 }
1963 }
1964 if (!cur_if) {
1965 ANDROID_ERROR(("%s: wrong ifname=%s in apstamode=%d\n",
1966 __FUNCTION__, ifname, apsta_params->apstamode));
91a2c117
RC
1967 return -1;
1968 }
1969 ret = wl_ext_parse_config(cur_if, pick_tmp, &pick_next);
1970 if (ret)
1971 return -1;
1972 pick_tmp = pick_next;
1973 } else {
1974 ANDROID_ERROR(("%s: first arg must be ifname\n", __FUNCTION__));
1975 return -1;
1976 }
1977
1978 }
1979
1980 return 0;
1981}
1982
d964ce36 1983static int
1984wl_ext_isam_status(struct net_device *dev)
1985{
1986 struct wl_apsta_params *apsta_params = &g_apsta_params;
1987 int i;
1988 bool now_if;
1989 struct wl_if_info *tmp_if;
1990 uint16 chan = 0;
1991 wlc_ssid_t ssid = { 0, {0} };
1992 char amode[16], emode[16];
1993
1994 if (apsta_params->init == FALSE) {
1995 return 0;
1996 }
1997
1998 printf("****************************\n");
1999 printf("%s: apstamode=%d\n", __FUNCTION__, apsta_params->apstamode);
2000 for (i=0; i<MAX_IF_NUM; i++) {
2001 now_if = FALSE;
2002 memset(&ssid, 0, sizeof(ssid));
2003 memset(amode, 0, sizeof(amode));
2004 memset(emode, 0, sizeof(emode));
2005 tmp_if = &apsta_params->if_info[i];
2006 if (dev == tmp_if->dev)
2007 now_if = TRUE;
2008 if (tmp_if->dev) {
2009 chan = wl_ext_get_chan(tmp_if->dev);
2010 if (chan) {
2011 wl_ext_ioctl(tmp_if->dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0);
2012 wl_ext_get_amode(tmp_if, amode);
2013 wl_ext_get_emode(tmp_if, emode);
2014 }
2015 if (chan) {
2016 printf("%s[%c-%c%s]: chan %3d, amode %s, emode %s, SSID \"%s\"\n",
2017 tmp_if->ifname, tmp_if->prefix, chan?'E':'D',
2018 now_if?"*":" ", chan, amode, emode, ssid.SSID);
2019 } else {
2020 printf("%s[%c-%c%s]:\n",
2021 tmp_if->ifname, tmp_if->prefix, chan?'E':'D',
2022 now_if?"*":" ");
2023 }
2024 }
2025 }
2026 printf("****************************\n");
2027
2028 return 0;
2029}
2030
2031static int
2032wl_ext_if_down(struct wl_if_info *cur_if)
2033{
2034 s8 iovar_buf[WLC_IOCTL_SMLEN];
2035 scb_val_t scbval;
2036 struct {
2037 s32 cfg;
2038 s32 val;
2039 } bss_setbuf;
2040 apstamode_t apstamode = g_apsta_params.apstamode;
2041
2042 printf("%s: %s[%c] Turning off\n", __FUNCTION__, cur_if->ifname, cur_if->prefix);
2043
2044 if (cur_if->ifmode == ISTA_MODE) {
2045 wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
2046 } else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
2047 // deauthenticate all STA first
2048 memcpy(scbval.ea.octet, &ether_bcast, ETHER_ADDR_LEN);
2049 wl_ext_ioctl(cur_if->dev, WLC_SCB_DEAUTHENTICATE, &scbval.ea, ETHER_ADDR_LEN, 1);
2050 }
2051
2052 if (apstamode == IAPONLY_MODE || apstamode == IMESHONLY_MODE) {
2053 wl_ext_ioctl(cur_if->dev, WLC_DOWN, NULL, 0, 1);
2054 } else {
2055 bss_setbuf.cfg = 0xffffffff;
2056 bss_setbuf.val = htod32(0);
2057 wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
2058 iovar_buf, WLC_IOCTL_SMLEN, NULL);
2059 }
2060
2061 return 0;
2062}
2063
2064static int
2065wl_ext_if_up(struct wl_if_info *cur_if)
2066{
2067 s8 iovar_buf[WLC_IOCTL_SMLEN];
2068 struct {
2069 s32 cfg;
2070 s32 val;
2071 } bss_setbuf;
2072 struct wl_apsta_params *apsta_params = &g_apsta_params;
2073 apstamode_t apstamode = apsta_params->apstamode;
2074 chanspec_t fw_chspec;
2075
2076 if (cur_if->ifmode != IAP_MODE) {
2077 ANDROID_ERROR(("%s: Wrong ifmode on %s[%c]\n", __FUNCTION__,
2078 cur_if->ifname, cur_if->prefix));
2079 return 0;
2080 }
2081
2082 if (cur_if->channel >= 52 && cur_if->channel <= 148) {
2083 printf("%s: %s[%c] skip DFS channel %d\n", __FUNCTION__,
2084 cur_if->ifname, cur_if->prefix, cur_if->channel);
2085 return 0;
2086 }
2087
2088 printf("%s: %s[%c] Turning on\n", __FUNCTION__, cur_if->ifname, cur_if->prefix);
2089 wl_ext_isam_status(cur_if->dev);
2090
2091 wl_ext_set_chanspec(cur_if->dev, apsta_params->ioctl_ver, cur_if->channel,
2092 &fw_chspec);
2093
2094 if (apstamode == IAPONLY_MODE) {
2095 wl_ext_ioctl(cur_if->dev, WLC_UP, NULL, 0, 1);
2096 } else {
2097 bss_setbuf.cfg = 0xffffffff;
2098 bss_setbuf.val = htod32(1);
2099 wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf,
2100 sizeof(bss_setbuf), iovar_buf, WLC_IOCTL_SMLEN, NULL);
2101 }
2102
2103 OSL_SLEEP(500);
2104
2105 return 0;
2106}
2107
91a2c117
RC
2108static int
2109wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
2110{
2111 char *pch, *pick_tmp, *param;
2112 s8 iovar_buf[WLC_IOCTL_SMLEN];
2113 wlc_ssid_t ssid = { 0, {0} };
2114 scb_val_t scbval;
2115 struct {
010c3a89
RC
2116 s32 cfg;
2117 s32 val;
91a2c117
RC
2118 } bss_setbuf;
2119 struct wl_apsta_params *apsta_params = &g_apsta_params;
2120 apstamode_t apstamode = apsta_params->apstamode;
2121 char ifname[IFNAMSIZ+1];
dfb0f3ae 2122 struct wl_if_info *cur_if = NULL;
91a2c117 2123 struct dhd_pub *dhd;
dfb0f3ae 2124 int i;
91a2c117
RC
2125
2126 if (!apsta_params->init) {
2127 ANDROID_ERROR(("%s: please init first\n", __FUNCTION__));
2128 return -1;
2129 }
2130
2131 ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
2132 dhd = dhd_get_pub(dev);
2133
2134 pick_tmp = command;
2135 param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_disable
2136 param = bcmstrtok(&pick_tmp, " ", 0);
2137 while (param != NULL) {
2138 if (!strcmp(param, "ifname")) {
2139 pch = bcmstrtok(&pick_tmp, " ", 0);
2140 if (pch)
2141 strcpy(ifname, pch);
2142 else {
2143 ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__));
2144 return -1;
2145 }
2146 }
2147 param = bcmstrtok(&pick_tmp, " ", 0);
2148 }
dfb0f3ae
RC
2149
2150 for (i=0; i<MAX_IF_NUM; i++) {
2151 if (apsta_params->if_info[i].dev &&
2152 !strcmp(apsta_params->if_info[i].dev->name, ifname)) {
2153 cur_if = &apsta_params->if_info[i];
2154 break;
2155 }
91a2c117 2156 }
dfb0f3ae
RC
2157 if (!cur_if) {
2158 ANDROID_ERROR(("%s: wrong ifname=%s or dev not ready\n", __FUNCTION__, ifname));
91a2c117
RC
2159 return -1;
2160 }
2161
d964ce36 2162 printf("%s: %s[%c] Disabling\n", __FUNCTION__, ifname, cur_if->prefix);
2163
91a2c117
RC
2164 if (cur_if->ifmode == ISTA_MODE) {
2165 wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
dfb0f3ae 2166 } else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
91a2c117
RC
2167 // deauthenticate all STA first
2168 memcpy(scbval.ea.octet, &ether_bcast, ETHER_ADDR_LEN);
2169 wl_ext_ioctl(cur_if->dev, WLC_SCB_DEAUTHENTICATE, &scbval.ea, ETHER_ADDR_LEN, 1);
2170 }
2171
dfb0f3ae 2172 if (apstamode == IAPONLY_MODE || apstamode == IMESHONLY_MODE) {
91a2c117
RC
2173 wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
2174 wl_ext_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); // reset ssid
2175 wl_ext_iovar_setint(dev, "mpc", 1);
2176 } else if ((apstamode==IAPSTA_MODE || apstamode==IGOSTA_MODE) &&
2177 cur_if->ifmode == IAP_MODE) {
d964ce36 2178 bss_setbuf.cfg = 0xffffffff;
91a2c117
RC
2179 bss_setbuf.val = htod32(0);
2180 wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
2181 iovar_buf, WLC_IOCTL_SMLEN, NULL);
2182 wl_ext_iovar_setint(dev, "mpc", 1);
2183#ifdef ARP_OFFLOAD_SUPPORT
2184 /* IF SoftAP is disabled, enable arpoe back for STA mode. */
2185 dhd_arp_offload_set(dhd, dhd_arp_mode);
2186 dhd_arp_offload_enable(dhd, TRUE);
2187#endif /* ARP_OFFLOAD_SUPPORT */
dfb0f3ae
RC
2188#ifdef PROP_TXSTATUS_VSDB
2189#if defined(BCMSDIO)
2190 if (dhd->conf->disable_proptx!=0) {
2191 bool enabled;
2192 dhd_wlfc_get_enable(dhd, &enabled);
2193 if (enabled) {
2194 dhd_wlfc_deinit(dhd);
2195 }
2196 }
2197#endif
2198#endif /* PROP_TXSTATUS_VSDB */
d964ce36 2199 }
2200 else if (apstamode == IDUALAP_MODE) {
2201 bss_setbuf.cfg = 0xffffffff;
91a2c117
RC
2202 bss_setbuf.val = htod32(0);
2203 wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
2204 iovar_buf, WLC_IOCTL_SMLEN, NULL);
dfb0f3ae 2205 } else if (apstamode == IMESHSTA_MODE || apstamode == IMESHAP_MODE ||
d964ce36 2206 apstamode == IMESHAPSTA_MODE || apstamode == IMESHAPAP_MODE ||
2207 apstamode == ISTAAPAP_MODE) {
2208 bss_setbuf.cfg = 0xffffffff;
dfb0f3ae
RC
2209 bss_setbuf.val = htod32(0);
2210 wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
2211 iovar_buf, WLC_IOCTL_SMLEN, NULL);
91a2c117
RC
2212 }
2213
dfb0f3ae
RC
2214 cur_if->ifstate = IF_STATE_DISALBE;
2215
d964ce36 2216 printf("%s: %s[%c] disabled\n", __FUNCTION__, ifname, cur_if->prefix);
dfb0f3ae
RC
2217
2218 return 0;
2219}
2220
dfb0f3ae 2221static uint16
d964ce36 2222wl_ext_get_vsdb_chan(struct net_device *dev,
2223 struct wl_if_info *cur_if, struct wl_if_info *target_if)
dfb0f3ae
RC
2224{
2225 struct wl_apsta_params *apsta_params = &g_apsta_params;
d964ce36 2226 uint16 target_chan = 0, cur_chan = cur_if->channel;
dfb0f3ae 2227 struct dhd_pub *dhd;
dfb0f3ae
RC
2228
2229 dhd = dhd_get_pub(dev);
d964ce36 2230
2231 target_chan = wl_ext_get_chan(target_if->dev);
2232 if (target_chan) {
2233 ANDROID_INFO(("%s: cur_chan=%d, target_chan=%d\n", __FUNCTION__,
2234 cur_chan, target_chan));
2235 if ((cur_chan <= CH_MAX_2G_CHANNEL && target_chan > CH_MAX_2G_CHANNEL) ||
2236 (cur_chan > CH_MAX_2G_CHANNEL && target_chan <= CH_MAX_2G_CHANNEL)) {
2237 // different band
2238 if (!FW_SUPPORTED(dhd, rsdb) || !apsta_params->rsdb)
2239 return target_chan;
2240 } else {
2241 // same band
2242 if (target_chan != cur_chan)
2243 return target_chan;
dfb0f3ae
RC
2244 }
2245 }
91a2c117
RC
2246
2247 return 0;
2248}
2249
d964ce36 2250static int
2251wl_ext_triger_csa(struct wl_if_info *cur_if)
dfb0f3ae 2252{
d964ce36 2253 struct wl_apsta_params *apsta_params = &g_apsta_params;
2254 s8 iovar_buf[WLC_IOCTL_SMLEN];
2255
2256 if (apsta_params->csa & CSA_DRV_BIT &&
2257 (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE)) {
2258 if (!cur_if->channel) {
2259 printf("%s: %s[%c] skip channel %d\n", __FUNCTION__,
2260 cur_if->ifname, cur_if->prefix, cur_if->channel);
2261 } else if (cur_if->channel >= 52 && cur_if->channel <= 148) {
2262 printf("%s: %s[%c] skip DFS channel %d\n", __FUNCTION__,
2263 cur_if->ifname, cur_if->prefix, cur_if->channel);
2264 wl_ext_if_down(cur_if);
2265 } else {
2266 wl_chan_switch_t csa_arg;
2267 memset(&csa_arg, 0, sizeof(csa_arg));
2268 csa_arg.mode = 1;
2269 csa_arg.count = 3;
2270 csa_arg.chspec = wl_ext_get_chanspec(apsta_params, cur_if->dev,
2271 cur_if->channel);
2272 if (csa_arg.chspec) {
2273 printf("%s: Trigger CSA to channel %d(0x%x)\n", __FUNCTION__,
2274 cur_if->channel, csa_arg.chspec);
2275 wl_ext_iovar_setbuf(cur_if->dev, "csa", &csa_arg, sizeof(csa_arg),
2276 iovar_buf, sizeof(iovar_buf), NULL);
2277 OSL_SLEEP(500);
2278 wl_ext_isam_status(cur_if->dev);
2279 } else {
2280 printf("%s: fail to get chanspec\n", __FUNCTION__);
2281 }
2282 }
dfb0f3ae 2283 }
d964ce36 2284
2285 return 0;
dfb0f3ae
RC
2286}
2287
d964ce36 2288static uint16
2289wl_ext_move_cur_channel(struct net_device *dev,
dfb0f3ae
RC
2290 struct wl_if_info *cur_if)
2291{
2292 struct wl_apsta_params *apsta_params = &g_apsta_params;
d964ce36 2293 struct wl_if_info *tmp_if, *target_if = NULL;
2294 uint16 tmp_chan, target_chan = 0;
2295 wl_prio_t max_prio;
dfb0f3ae
RC
2296 int i;
2297
d964ce36 2298 if (apsta_params->vsdb) {
2299 target_chan = cur_if->channel;
2300 goto exit;
2301 }
2302
2303 // find the max prio
2304 max_prio = cur_if->prio;
2305 for (i=0; i<MAX_IF_NUM; i++) {
2306 tmp_if = &apsta_params->if_info[i];
2307 if (tmp_if->ifstate >= IF_STATE_INIT && cur_if != tmp_if &&
2308 tmp_if->prio > max_prio) {
2309 tmp_chan = wl_ext_get_vsdb_chan(dev, cur_if, tmp_if);
2310 if (tmp_chan) {
2311 target_if = tmp_if;
2312 target_chan = tmp_chan;
2313 max_prio = tmp_if->prio;
dfb0f3ae
RC
2314 }
2315 }
2316 }
d964ce36 2317
2318 if (target_chan) {
2319 printf("%s: %s channel=%d => %s channel=%d\n", __FUNCTION__,
2320 cur_if->ifname, cur_if->channel, target_if->ifname, target_chan);
2321 cur_if->channel = target_chan;
2322 }
2323exit:
2324 if ((cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) &&
2325 (cur_if->channel >= 52 && cur_if->channel <= 148)) {
2326 printf("%s: %s[%c] skip DFS channel %d\n", __FUNCTION__,
2327 cur_if->ifname, cur_if->prefix, cur_if->channel);
2328 cur_if->channel = 0;
dfb0f3ae
RC
2329 }
2330
d964ce36 2331 return cur_if->channel;
dfb0f3ae
RC
2332}
2333
2334static void
d964ce36 2335wl_ext_move_other_channel(struct net_device *dev,
dfb0f3ae
RC
2336 struct wl_if_info *cur_if)
2337{
2338 struct wl_apsta_params *apsta_params = &g_apsta_params;
d964ce36 2339 struct wl_if_info *tmp_if, *target_if=NULL;
2340 uint16 tmp_chan, target_chan = 0;
2341 wl_prio_t max_prio = 0, cur_prio;
dfb0f3ae
RC
2342 int i;
2343
d964ce36 2344 if (apsta_params->vsdb || !cur_if->channel) {
2345 return;
2346 }
2347
2348 // find the max prio, but lower than cur_if
2349 cur_prio = cur_if->prio;
2350 for (i=0; i<MAX_IF_NUM; i++) {
2351 tmp_if = &apsta_params->if_info[i];
2352 if (tmp_if->ifstate >= IF_STATE_INIT && cur_if != tmp_if &&
2353 tmp_if->prio >= max_prio && tmp_if->prio <= cur_prio) {
2354 tmp_chan = wl_ext_get_vsdb_chan(dev, cur_if, tmp_if);
2355 if (tmp_chan) {
2356 target_if = tmp_if;
2357 target_chan = tmp_chan;
2358 max_prio = tmp_if->prio;
dfb0f3ae
RC
2359 }
2360 }
d964ce36 2361 }
2362
2363 if (target_if) {
2364 printf("%s: %s channel=%d => %s channel=%d\n", __FUNCTION__,
2365 target_if->ifname, target_chan, cur_if->ifname, cur_if->channel);
2366 target_if->channel = cur_if->channel;
2367 if (apsta_params->csa == 0) {
2368 wl_ext_if_down(target_if);
2369 wl_ext_move_other_channel(dev, target_if);
2370 if (target_if->ifmode == ISTA_MODE || target_if->ifmode == IMESH_MODE) {
2371 wl_ext_enable_iface(target_if->dev, target_if->ifname);
2372 } else if (target_if->ifmode == IAP_MODE) {
2373 wl_ext_if_up(target_if);
dfb0f3ae 2374 }
d964ce36 2375 } else {
2376 wl_ext_triger_csa(target_if);
dfb0f3ae
RC
2377 }
2378 }
2379
2380}
2381
91a2c117 2382static int
d964ce36 2383wl_ext_enable_iface(struct net_device *dev, char *ifname)
91a2c117 2384{
d964ce36 2385 int i;
91a2c117
RC
2386 s8 iovar_buf[WLC_IOCTL_SMLEN];
2387 wlc_ssid_t ssid = { 0, {0} };
dfb0f3ae
RC
2388 chanspec_t fw_chspec;
2389 struct wl_join_params join_params;
2390 size_t join_params_size;
91a2c117 2391 struct {
010c3a89
RC
2392 s32 cfg;
2393 s32 val;
91a2c117
RC
2394 } bss_setbuf;
2395 struct wl_apsta_params *apsta_params = &g_apsta_params;
2396 apstamode_t apstamode = apsta_params->apstamode;
dfb0f3ae 2397 struct wl_if_info *cur_if = NULL;
91a2c117 2398 struct dhd_pub *dhd;
dfb0f3ae 2399 uint16 cur_chan;
91a2c117 2400
91a2c117
RC
2401 dhd = dhd_get_pub(dev);
2402
dfb0f3ae
RC
2403 for (i=0; i<MAX_IF_NUM; i++) {
2404 if (apsta_params->if_info[i].dev &&
2405 !strcmp(apsta_params->if_info[i].dev->name, ifname)) {
2406 cur_if = &apsta_params->if_info[i];
2407 break;
91a2c117 2408 }
91a2c117 2409 }
dfb0f3ae
RC
2410 if (!cur_if) {
2411 ANDROID_ERROR(("%s: wrong ifname=%s or dev not ready\n", __FUNCTION__, ifname));
91a2c117
RC
2412 return -1;
2413 }
dfb0f3ae 2414
d964ce36 2415 printf("%s: %s[%c] Enabling\n", __FUNCTION__, ifname, cur_if->prefix);
dfb0f3ae 2416
d964ce36 2417 wl_ext_isam_status(cur_if->dev);
dfb0f3ae 2418
d964ce36 2419 wl_ext_move_cur_channel(dev, cur_if);
2420 if (!cur_if->channel && cur_if->ifmode != ISTA_MODE) {
dfb0f3ae 2421 return 0;
91a2c117 2422 }
dfb0f3ae 2423
d964ce36 2424 cur_chan = wl_ext_get_chan(cur_if->dev);
2425 if (cur_chan) {
2426 ANDROID_INFO(("%s: Associated!\n", __FUNCTION__));
2427 if (cur_chan != cur_if->channel) {
2428 wl_ext_triger_csa(cur_if);
2429 }
2430 return 0;
2431 }
91a2c117 2432
d964ce36 2433 wl_ext_move_other_channel(dev, cur_if);
91a2c117 2434
d964ce36 2435 if (cur_if->ifidx > 0) {
91a2c117
RC
2436 wl_ext_iovar_setbuf(cur_if->dev, "cur_etheraddr", (u8 *)cur_if->dev->dev_addr,
2437 ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL);
2438 }
2439
2440 // set ssid for AP
d964ce36 2441 ssid.SSID_len = strlen(cur_if->ssid);
2442 memcpy(ssid.SSID, cur_if->ssid, ssid.SSID_len);
dfb0f3ae 2443 if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
91a2c117
RC
2444 wl_ext_iovar_setint(dev, "mpc", 0);
2445 if (apstamode == IAPONLY_MODE) {
2446 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
2447 } else if (apstamode==IAPSTA_MODE || apstamode==IGOSTA_MODE) {
2448 wl_ext_iovar_setbuf_bsscfg(cur_if->dev, "ssid", &ssid, sizeof(ssid),
2449 iovar_buf, WLC_IOCTL_SMLEN, cur_if->bssidx, NULL);
2450 }
2451 }
2452
dfb0f3ae 2453 if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
91a2c117 2454 wl_ext_set_bgnmode(cur_if);
d964ce36 2455 if (!cur_if->channel) {
dfb0f3ae 2456#ifdef WL_CFG80211
d964ce36 2457 char *pick_tmp, *param;
2458 char cmd[128];
2459 uint16 cur_chan;
2460 cur_chan = 1;
dfb0f3ae
RC
2461 snprintf(cmd, 128, "get_best_channels");
2462 wl_cfg80211_get_best_channels(dev, cmd, strlen(cmd));
2463 pick_tmp = cmd;
2464 param = bcmstrtok(&pick_tmp, " ", 0);
2465 while (param != NULL) {
2466 if (!strnicmp(param, "2g=", strlen("2g="))) {
2467 cur_chan = (int)simple_strtol(param+strlen("2g="), NULL, 10);
2468 } else if (!strnicmp(param, "5g=", strlen("5g="))) {
2469 cur_chan = (int)simple_strtol(param+strlen("5g="), NULL, 10);
2470 }
2471 param = bcmstrtok(&pick_tmp, " ", 0);
2472 }
d964ce36 2473 cur_if->channel = cur_chan;
2474#else
2475 cur_if->channel = 1;
dfb0f3ae
RC
2476#endif
2477 }
d964ce36 2478 wl_ext_set_chanspec(cur_if->dev, apsta_params->ioctl_ver, cur_if->channel,
2479 &fw_chspec);
91a2c117 2480 }
dfb0f3ae 2481
d964ce36 2482 wl_ext_set_amode(cur_if);
91a2c117
RC
2483 wl_ext_set_emode(cur_if, apsta_params);
2484
91a2c117
RC
2485 if (cur_if->ifmode == IAP_MODE) {
2486 if (cur_if->maxassoc >= 0)
2487 wl_ext_iovar_setint(dev, "maxassoc", cur_if->maxassoc);
91a2c117 2488 // terence: fix me, hidden does not work in dualAP mode
dfb0f3ae 2489 if (cur_if->hidden > 0) {
d964ce36 2490 wl_ext_ioctl(cur_if->dev, WLC_SET_CLOSED, &cur_if->hidden,
2491 sizeof(cur_if->hidden), 1);
2492 printf("%s: Broadcast SSID: %s\n", __FUNCTION__,
2493 cur_if->hidden ? "OFF":"ON");
dfb0f3ae 2494 }
91a2c117
RC
2495 }
2496
dfb0f3ae
RC
2497 if (apstamode == ISTAONLY_MODE) {
2498 wl_ext_connect(cur_if);
91a2c117
RC
2499 } else if (apstamode == IAPONLY_MODE) {
2500 wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
2501 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
2502 } else if (apstamode == IAPSTA_MODE || apstamode == IGOSTA_MODE) {
2503 if (cur_if->ifmode == ISTA_MODE) {
dfb0f3ae 2504 wl_ext_connect(cur_if);
91a2c117
RC
2505 } else {
2506 if (FW_SUPPORTED(dhd, rsdb)) {
2507 wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
2508 } else {
2509 bss_setbuf.cfg = htod32(cur_if->bssidx);
2510 bss_setbuf.val = htod32(1);
d964ce36 2511 wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf,
2512 sizeof(bss_setbuf), iovar_buf, WLC_IOCTL_SMLEN, NULL);
91a2c117 2513 }
010c3a89 2514#ifdef ARP_OFFLOAD_SUPPORT
91a2c117
RC
2515 /* IF SoftAP is enabled, disable arpoe */
2516 dhd_arp_offload_set(dhd, 0);
2517 dhd_arp_offload_enable(dhd, FALSE);
2518#endif /* ARP_OFFLOAD_SUPPORT */
dfb0f3ae
RC
2519#ifdef PROP_TXSTATUS_VSDB
2520#if defined(BCMSDIO)
2521 if (!FW_SUPPORTED(dhd, rsdb) && !disable_proptx) {
2522 bool enabled;
2523 dhd_wlfc_get_enable(dhd, &enabled);
2524 if (!enabled) {
2525 dhd_wlfc_init(dhd);
2526 wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
2527 }
2528 }
2529#endif
2530#endif /* PROP_TXSTATUS_VSDB */
91a2c117
RC
2531 }
2532 }
2533 else if (apstamode == IDUALAP_MODE) {
2534 wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
d964ce36 2535 } else if (apstamode == ISTAAPAP_MODE) {
2536 if (cur_if->ifmode == ISTA_MODE) {
2537 wl_ext_connect(cur_if);
2538 } else if (cur_if->ifmode == IAP_MODE) {
2539 wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
2540 } else {
2541 printf("%s: wrong ifmode %d\n", __FUNCTION__, cur_if->ifmode);
2542 }
dfb0f3ae
RC
2543 } else if (apstamode == IMESHONLY_MODE ||
2544 apstamode == IMESHSTA_MODE || apstamode == IMESHAP_MODE ||
2545 apstamode == IMESHAPSTA_MODE || apstamode == IMESHAPAP_MODE) {
2546 if (cur_if->ifmode == ISTA_MODE) {
2547 wl_ext_connect(cur_if);
2548 } else if (cur_if->ifmode == IAP_MODE) {
2549 wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
2550 } else if (cur_if->ifmode == IMESH_MODE) {
2551 // need to up before setting ssid
dfb0f3ae
RC
2552 memset(&join_params, 0, sizeof(join_params));
2553 join_params.ssid.SSID_len = strlen(cur_if->ssid);
d964ce36 2554 memcpy((void *)join_params.ssid.SSID, cur_if->ssid, strlen(cur_if->ssid));
dfb0f3ae
RC
2555 join_params.params.chanspec_list[0] = fw_chspec;
2556 join_params.params.chanspec_num = 1;
2557 join_params_size = sizeof(join_params);
2558 wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &join_params, join_params_size, 1);
2559 } else {
2560 printf("%s: wrong ifmode %d\n", __FUNCTION__, cur_if->ifmode);
91a2c117
RC
2561 }
2562 }
91a2c117 2563
d964ce36 2564 OSL_SLEEP(500);
2565 printf("%s: %s[%c] enabled with SSID: \"%s\"\n", __FUNCTION__,
2566 ifname, cur_if->prefix, cur_if->ssid);
2567 wl_ext_isam_status(cur_if->dev);
91a2c117
RC
2568
2569 cur_if->ifstate = IF_STATE_ENABLE;
2570
dfb0f3ae
RC
2571 return 0;
2572}
2573
2574static int
2575wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len)
2576{
2577 int ret = 0;
2578 char *pch, *pick_tmp, *param;
2579 struct wl_apsta_params *apsta_params = &g_apsta_params;
2580 char ifname[IFNAMSIZ+1];
2581
2582 if (!apsta_params->init) {
2583 ANDROID_ERROR(("%s: please init first\n", __FUNCTION__));
2584 return -1;
2585 }
2586
2587 ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
2588
2589 pick_tmp = command;
2590 param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_enable
2591 param = bcmstrtok(&pick_tmp, " ", 0);
2592 while (param != NULL) {
2593 if (!strcmp(param, "ifname")) {
2594 pch = bcmstrtok(&pick_tmp, " ", 0);
2595 if (pch) {
2596 strcpy(ifname, pch);
d964ce36 2597 ret = wl_ext_enable_iface(dev, ifname);
dfb0f3ae
RC
2598 if (ret)
2599 return ret;
dfb0f3ae
RC
2600 } else {
2601 ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__));
2602 return -1;
2603 }
2604 }
2605 param = bcmstrtok(&pick_tmp, " ", 0);
2606 }
2607
91a2c117
RC
2608 return ret;
2609}
2610
dfb0f3ae
RC
2611int
2612wl_ext_iapsta_alive_preinit(struct net_device *dev)
91a2c117
RC
2613{
2614 struct wl_apsta_params *apsta_params = &g_apsta_params;
d964ce36 2615 struct wl_if_info *cur_if;
2616 int i;
91a2c117 2617
dfb0f3ae
RC
2618 if (apsta_params->init == TRUE) {
2619 ANDROID_ERROR(("%s: don't init twice\n", __FUNCTION__));
2620 return -1;
2621 }
2622
2623 ANDROID_TRACE(("%s: Enter\n", __FUNCTION__));
2624
d964ce36 2625 for (i=0; i<MAX_IF_NUM; i++) {
2626 cur_if = &apsta_params->if_info[i];
2627 if (i == 1 && !strlen(cur_if->ifname))
2628 strcpy(cur_if->ifname, "wlan1");
2629 if (i == 2 && !strlen(cur_if->ifname))
2630 strcpy(cur_if->ifname, "wlan2");
2631 if (cur_if->ifmode == ISTA_MODE) {
2632 cur_if->channel = 0;
2633 cur_if->maxassoc = -1;
2634 cur_if->ifstate = IF_STATE_INIT;
2635 cur_if->prio = PRIO_STA;
2636 cur_if->prefix = 'S';
2637 snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta");
2638 } else if (cur_if->ifmode == IAP_MODE) {
2639 cur_if->channel = 1;
2640 cur_if->maxassoc = -1;
2641 cur_if->ifstate = IF_STATE_INIT;
2642 cur_if->prio = PRIO_AP;
2643 cur_if->prefix = 'A';
2644 snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap");
2645 } else if (cur_if->ifmode == IMESH_MODE) {
2646 cur_if->channel = 1;
2647 cur_if->maxassoc = -1;
2648 cur_if->ifstate = IF_STATE_INIT;
2649 cur_if->prio = PRIO_MESH;
2650 cur_if->prefix = 'M';
2651 snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh");
2652 }
2653 }
dfb0f3ae
RC
2654
2655 apsta_params->init = TRUE;
2656
2657 return 0;
2658}
2659
2660int
2661wl_ext_iapsta_alive_postinit(struct net_device *dev)
2662{
2663 s32 apsta = 0;
2664 struct wl_apsta_params *apsta_params = &g_apsta_params;
2665
2666 wl_ext_iovar_getint(dev, "apsta", &apsta);
2667 if (apsta == 1) {
2668 apsta_params->apstamode = ISTAONLY_MODE;
2669 apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE;
2670 op_mode = DHD_FLAG_STA_MODE;
2671 } else {
2672 apsta_params->apstamode = IAPONLY_MODE;
2673 apsta_params->if_info[IF_PIF].ifmode = IAP_MODE;
2674 op_mode = DHD_FLAG_HOSTAP_MODE;
2675 }
2676 // fix me: how to check it's IAPSTA_MODE or IDUALAP_MODE?
2677
2678 wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver);
2679 printf("%s: apstamode=%d\n", __FUNCTION__, apsta_params->apstamode);
2680
2681 return op_mode;
2682}
2683
d964ce36 2684#if defined(WL_WIRELESS_EXT)
dfb0f3ae
RC
2685static bool
2686wl_ext_conn_status_str(uint32 event_type,
2687 uint32 status, uint32 reason, char* stringBuf, uint buflen)
2688{
2689 int i;
2690
2691 typedef struct conn_fail_event_map_t {
2692 uint32 inEvent; /* input: event type to match */
2693 uint32 inStatus; /* input: event status code to match */
2694 uint32 inReason; /* input: event reason code to match */
2695 } conn_fail_event_map_t;
2696
2697 /* Map of WLC_E events to connection failure strings */
2698# define WL_IW_DONT_CARE 9999
2699 const conn_fail_event_map_t event_map [] = {
2700 /* inEvent inStatus inReason */
2701 {WLC_E_LINK, WL_IW_DONT_CARE, WL_IW_DONT_CARE},
2702 {WLC_E_DEAUTH, WL_IW_DONT_CARE, WL_IW_DONT_CARE},
2703 {WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE},
2704 {WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE},
2705 {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE},
2706 {WLC_E_OVERLAY_REQ, WL_IW_DONT_CARE, WL_IW_DONT_CARE},
2707 {WLC_E_ASSOC_IND, WL_IW_DONT_CARE, DOT11_SC_SUCCESS},
2708 {WLC_E_REASSOC_IND, WL_IW_DONT_CARE, DOT11_SC_SUCCESS},
2709 };
2710
2711 /* Search the event map table for a matching event */
2712 for (i = 0; i < sizeof(event_map)/sizeof(event_map[0]); i++) {
2713 const conn_fail_event_map_t* row = &event_map[i];
2714 if (row->inEvent == event_type &&
2715 (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) &&
2716 (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) {
2717 memset(stringBuf, 0, buflen);
2718 snprintf(stringBuf, buflen, "isam_event event=%d reason=%d",
2719 event_type, reason);
2720 return TRUE;
2721 }
2722 }
2723
2724 return FALSE;
2725}
d964ce36 2726#endif /* WL_WIRELESS_EXT */
dfb0f3ae
RC
2727
2728int
2729wl_ext_iapsta_event(struct net_device *dev, wl_event_msg_t *e, void* data)
2730{
2731 struct wl_apsta_params *apsta_params = &g_apsta_params;
2732 struct wl_if_info *cur_if = NULL;
dfb0f3ae
RC
2733 int i;
2734#if defined(WL_WIRELESS_EXT)
d964ce36 2735 char extra[IW_CUSTOM_MAX + 1];
dfb0f3ae 2736 union iwreq_data wrqu;
dfb0f3ae
RC
2737#endif
2738 uint32 event_type = ntoh32(e->event_type);
2739 uint32 status = ntoh32(e->status);
2740 uint32 reason = ntoh32(e->reason);
2741 uint16 flags = ntoh16(e->flags);
2742
2743 if (!apsta_params->init) {
2744 ANDROID_TRACE(("%s: please init first\n", __FUNCTION__));
2745 return -1;
2746 }
2747
2748 for (i=0; i<MAX_IF_NUM; i++) {
d964ce36 2749 if (apsta_params->if_info[i].ifidx == e->ifidx) {
dfb0f3ae
RC
2750 cur_if = &apsta_params->if_info[i];
2751 break;
2752 }
2753 }
2754 if (!cur_if || !cur_if->dev) {
2755 ANDROID_ERROR(("%s: %s ifidx %d is not ready\n", __FUNCTION__,
2756 dev->name, e->ifidx));
2757 return -1;
2758 }
2759
dfb0f3ae 2760 if (cur_if->ifmode == ISTA_MODE) {
d964ce36 2761 if (event_type == WLC_E_LINK) {
2762 if (!(flags & WLC_EVENT_MSG_LINK)) {
2763 printf("%s: %s[%c] Link Down with %pM\n", __FUNCTION__,
2764 cur_if->ifname, cur_if->prefix, &e->addr);
2765 } else {
2766 printf("%s: %s[%c] Link UP with %pM\n", __FUNCTION__,
2767 cur_if->ifname, cur_if->prefix, &e->addr);
2768 }
dfb0f3ae 2769 }
d964ce36 2770 }
2771 else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
2772 if ((event_type == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
2773 (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
2774 reason == WLC_E_REASON_INITIAL_ASSOC)) {
2775 printf("%s: %s[%c] Link up\n", __FUNCTION__,
2776 cur_if->ifname, cur_if->prefix);
2777 } else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) ||
2778 (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
2779 reason == WLC_E_REASON_DEAUTH)) {
2780 printf("%s: %s[%c] Link down\n", __FUNCTION__,
2781 cur_if->ifname, cur_if->prefix);
2782 }
2783 else if ((event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) &&
2784 reason == DOT11_SC_SUCCESS) {
2785 printf("%s: %s[%c] connected device %pM\n", __FUNCTION__,
2786 cur_if->ifname, cur_if->prefix, &e->addr);
dfb0f3ae 2787 } else if (event_type == WLC_E_DISASSOC_IND) {
d964ce36 2788 printf("%s: %s[%c] disassociated device %pM\n", __FUNCTION__,
2789 cur_if->ifname, cur_if->prefix, &e->addr);
2790 } else if (event_type == WLC_E_DEAUTH_IND ||
2791 (event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) {
2792 printf("%s: %s[%c] deauthenticated device %pM\n", __FUNCTION__,
2793 cur_if->ifname, cur_if->prefix, &e->addr);
91a2c117
RC
2794 }
2795 }
dfb0f3ae 2796
dfb0f3ae 2797#if defined(WL_WIRELESS_EXT)
d964ce36 2798 memset(extra, 0, sizeof(extra));
2799 memset(&wrqu, 0, sizeof(wrqu));
2800 memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
2801 wrqu.addr.sa_family = ARPHRD_ETHER;
2802 if (wl_ext_conn_status_str(event_type, status, reason, extra, sizeof(extra))) {
dfb0f3ae 2803 wrqu.data.length = strlen(extra);
d964ce36 2804 wireless_send_event(cur_if->dev, IWEVCUSTOM, &wrqu, extra);
2805 ANDROID_INFO(("%s: %s[%c] event=%d, status=%d, reason=%d, flags=%d sent up\n",
2806 __FUNCTION__, cur_if->ifname, cur_if->prefix, event_type, status,
2807 reason, flags));
2808 } else
dfb0f3ae 2809#endif /* WL_WIRELESS_EXT */
d964ce36 2810 {
2811 ANDROID_INFO(("%s: %s[%c] event=%d, status=%d, reason=%d, flags=%d\n",
2812 __FUNCTION__, cur_if->ifname, cur_if->prefix, event_type, status,
2813 reason, flags));
dfb0f3ae
RC
2814 }
2815
2816 return 0;
91a2c117
RC
2817}
2818
d964ce36 2819u32
2820wl_ext_iapsta_update_channel(struct net_device *dev, u32 channel)
91a2c117 2821{
dfb0f3ae 2822 struct wl_apsta_params *apsta_params = &g_apsta_params;
d964ce36 2823 struct wl_if_info *cur_if = NULL, *tmp_if = NULL;
dfb0f3ae
RC
2824 int i;
2825
2826 for (i=0; i<MAX_IF_NUM; i++) {
d964ce36 2827 tmp_if = &apsta_params->if_info[i];
2828 if (tmp_if->dev && tmp_if->dev == dev) {
2829 cur_if = tmp_if;
2830 break;
dfb0f3ae
RC
2831 }
2832 }
2833
d964ce36 2834 if (cur_if) {
2835 wl_ext_isam_status(cur_if->dev);
2836 cur_if->channel = channel;
2837 channel = wl_ext_move_cur_channel(apsta_params->if_info[IF_PIF].dev, cur_if);
2838 if (channel)
2839 wl_ext_move_other_channel(apsta_params->if_info[IF_PIF].dev, cur_if);
2840 }
2841
2842 return channel;
dfb0f3ae
RC
2843}
2844
2845int
d964ce36 2846wl_ext_iapsta_attach_name(struct net_device *net, int ifidx)
dfb0f3ae
RC
2847{
2848 struct wl_apsta_params *apsta_params = &g_apsta_params;
d964ce36 2849 struct dhd_pub *dhd;
2850 struct wl_if_info *cur_if = NULL;
dfb0f3ae 2851
d964ce36 2852 dhd = dhd_get_pub(net);
2853
2854 ANDROID_TRACE(("%s: ifidx=%d, %s\n", __FUNCTION__, ifidx, net->name));
2855 if (ifidx < MAX_IF_NUM) {
2856 cur_if = &apsta_params->if_info[ifidx];
2857 }
2858 if (ifidx == 0) {
2859 if (dhd->conf->fw_type == FW_TYPE_MESH) {
2860 apsta_params->rsdb = TRUE;
2861 apsta_params->csa = CSA_FW_BIT | CSA_DRV_BIT;
2862 }
2863 strcpy(cur_if->ifname, net->name);
2864 } else if (cur_if && cur_if->ifstate == IF_STATE_INIT) {
2865 strcpy(cur_if->ifname, net->name);
2866 apsta_params->netif_change = TRUE;
2867 wake_up_interruptible(&apsta_params->netif_change_event);
91a2c117 2868 }
dfb0f3ae
RC
2869
2870 return 0;
2871}
2872
2873int
d964ce36 2874wl_ext_iapsta_attach_netdev(struct net_device *net, int ifidx, uint8 bssidx)
dfb0f3ae
RC
2875{
2876 struct wl_apsta_params *apsta_params = &g_apsta_params;
d964ce36 2877 struct dhd_pub *dhd;
2878 struct wl_if_info *cur_if = NULL, *primary_if;
dfb0f3ae 2879
d964ce36 2880 dhd = dhd_get_pub(net);
2881
2882 printf("%s: ifidx=%d, bssidx=%d\n", __FUNCTION__, ifidx, bssidx);
2883 if (ifidx < MAX_IF_NUM) {
2884 cur_if = &apsta_params->if_info[ifidx];
2885 }
2886 if (ifidx == 0) {
dfb0f3ae
RC
2887 memset(apsta_params, 0, sizeof(struct wl_apsta_params));
2888 apsta_params->vsdb = FALSE;
d964ce36 2889 cur_if->dev = net;
2890 cur_if->ifidx = ifidx;
2891 cur_if->bssidx = bssidx;
2892 strcpy(cur_if->ifname, net->name);
dfb0f3ae 2893 init_waitqueue_head(&apsta_params->netif_change_event);
d964ce36 2894 } else if (cur_if && cur_if->ifstate == IF_STATE_INIT) {
2895 primary_if = &apsta_params->if_info[IF_PIF];
2896 cur_if->dev = net;
2897 cur_if->ifidx = ifidx;
2898 cur_if->bssidx = bssidx;
2899 if (strlen(cur_if->ifname)) {
dfb0f3ae 2900 memset(net->name, 0, sizeof(IFNAMSIZ));
d964ce36 2901 strcpy(net->name, cur_if->ifname);
dfb0f3ae
RC
2902 net->name[IFNAMSIZ-1] = '\0';
2903 }
d964ce36 2904 if (apsta_params->apstamode != ISTAAPAP_MODE) {
2905 memcpy(net->dev_addr, primary_if->dev->dev_addr, ETHER_ADDR_LEN);
dfb0f3ae 2906 net->dev_addr[0] |= 0x02;
d964ce36 2907 if (ifidx >= 2) {
2908 net->dev_addr[4] ^= 0x80;
2909 net->dev_addr[4] += ifidx;
2910 net->dev_addr[5] += (ifidx-1);
2911 }
dfb0f3ae 2912 }
d964ce36 2913 if (cur_if->ifmode == ISTA_MODE) {
2914 wl_ext_iovar_setint(net, "roam_off", dhd->conf->roam_off);
2915 wl_ext_iovar_setint(net, "bcn_timeout", dhd->conf->bcn_timeout);
2916 } else if (cur_if->ifmode == IMESH_MODE) {
2917 int pm = 0;
2918 wl_ext_ioctl(net, WLC_SET_PM, &pm, sizeof(pm), 1);
dfb0f3ae 2919 }
91a2c117
RC
2920 }
2921
2922 return 0;
2923}
2924
dfb0f3ae
RC
2925int
2926wl_ext_iapsta_dettach_netdev(void)
91a2c117
RC
2927{
2928 struct wl_apsta_params *apsta_params = &g_apsta_params;
2929
dfb0f3ae 2930 printf("%s: Enter\n", __FUNCTION__);
91a2c117
RC
2931 memset(apsta_params, 0, sizeof(struct wl_apsta_params));
2932
2933 return 0;
2934}
2935#endif
2936
2937#ifdef IDHCP
dfb0f3ae
RC
2938int
2939wl_ext_ip_dump(int ip, char *buf)
91a2c117
RC
2940{
2941 unsigned char bytes[4];
2942 int bytes_written=-1;
2943
2944 bytes[0] = ip & 0xFF;
2945 bytes[1] = (ip >> 8) & 0xFF;
2946 bytes[2] = (ip >> 16) & 0xFF;
2947 bytes[3] = (ip >> 24) & 0xFF;
2948 bytes_written = sprintf(buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
2949
2950 return bytes_written;
2951}
2952
2953/*
2954terence 20170215:
2955dhd_priv dhcpc_dump ifname [wlan0|wlan1]
2956dhd_priv dhcpc_enable [0|1]
2957*/
2958int
2959wl_ext_dhcpc_enable(struct net_device *dev, char *command, int total_len)
2960{
2961 int enable = -1, ret = -1;
2962 int bytes_written = -1;
2963
2964 ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
2965
2966 sscanf(command, "%*s %d", &enable);
2967
2968 if (enable >= 0)
2969 ret = wl_ext_iovar_setint(dev, "dhcpc_enable", enable);
2970 else {
2971 ret = wl_ext_iovar_getint(dev, "dhcpc_enable", &enable);
2972 if (!ret) {
2973 bytes_written = snprintf(command, total_len, "%d", enable);
2974 ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
2975 ret = bytes_written;
2976 }
2977 }
2978
2979 return ret;
2980}
2981
2982int
2983wl_ext_dhcpc_dump(struct net_device *dev, char *command, int total_len)
2984{
91a2c117
RC
2985 int ret = 0;
2986 int bytes_written = 0;
2987 uint32 ip_addr;
2988 char buf[20]="";
2989
2990 ret = wl_ext_iovar_getint(dev, "dhcpc_ip_addr", &ip_addr);
2991 if (!ret) {
2992 wl_ext_ip_dump(ip_addr, buf);
2993 bytes_written += snprintf(command+bytes_written, total_len, "ipaddr %s ", buf);
2994 }
2995
2996 ret = wl_ext_iovar_getint(dev, "dhcpc_ip_mask", &ip_addr);
2997 if (!ret) {
2998 wl_ext_ip_dump(ip_addr, buf);
2999 bytes_written += snprintf(command+bytes_written, total_len, "mask %s ", buf);
3000 }
3001
3002 ret = wl_ext_iovar_getint(dev, "dhcpc_ip_gateway", &ip_addr);
3003 if (!ret) {
3004 wl_ext_ip_dump(ip_addr, buf);
3005 bytes_written += snprintf(command+bytes_written, total_len, "gw %s ", buf);
3006 }
3007
3008 ret = wl_ext_iovar_getint(dev, "dhcpc_ip_dnsserv", &ip_addr);
3009 if (!ret) {
3010 wl_ext_ip_dump(ip_addr, buf);
3011 bytes_written += snprintf(command+bytes_written, total_len, "dnsserv %s ", buf);
3012 }
3013
3014 if (!bytes_written)
3015 bytes_written = -1;
3016
3017 ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
3018
3019 return bytes_written;
3020}
3021#endif
3022
5011fc31
RC
3023static int
3024wl_ext_rsdb_mode(struct net_device *dev, char *data, char *command,
3025 int total_len)
3026{
3027 s8 iovar_buf[WLC_IOCTL_SMLEN];
3028 wl_config_t rsdb_mode_cfg = {1, 0}, *rsdb_p;
3029 int ret = 0;
3030
3031 ANDROID_TRACE(("%s: Enter\n", __FUNCTION__));
3032
3033 if (data) {
3034 rsdb_mode_cfg.config = (int)simple_strtol(data, NULL, 0);
3035 ret = wl_ext_iovar_setbuf(dev, "rsdb_mode", (char *)&rsdb_mode_cfg,
3036 sizeof(rsdb_mode_cfg), iovar_buf, WLC_IOCTL_SMLEN, NULL);
3037 printf("%s: rsdb_mode %d\n", __FUNCTION__, rsdb_mode_cfg.config);
3038 } else {
3039 ret = wl_ext_iovar_getbuf(dev, "rsdb_mode", NULL, 0,
3040 iovar_buf, WLC_IOCTL_SMLEN, NULL);
3041 if (!ret) {
3042 rsdb_p = (wl_config_t *) iovar_buf;
3043 ret = snprintf(command, total_len, "%d", rsdb_p->config);
3044 ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__,
3045 command));
3046 }
3047 }
3048
3049 return ret;
3050}
3051
3052typedef int (wl_ext_tpl_parse_t)(struct net_device *dev, char *data, char *command,
3053 int total_len);
3054
3055typedef struct wl_ext_iovar_tpl_t {
3056 int get;
3057 int set;
3058 char *name;
3059 wl_ext_tpl_parse_t *parse;
3060} wl_ext_iovar_tpl_t;
3061
3062const wl_ext_iovar_tpl_t wl_ext_iovar_tpl_list[] = {
3063 {WLC_GET_VAR, WLC_SET_VAR, "rsdb_mode", wl_ext_rsdb_mode},
3064};
3065
91a2c117 3066/*
5011fc31 3067Ex: dhd_priv wl [cmd] [val]
91a2c117
RC
3068 dhd_priv wl 85
3069 dhd_priv wl 86 1
91a2c117
RC
3070 dhd_priv wl mpc
3071 dhd_priv wl mpc 1
3072*/
3073int
5011fc31 3074wl_ext_wl_iovar(struct net_device *dev, char *command, int total_len)
91a2c117 3075{
5011fc31
RC
3076 int cmd, val, ret = -1, i;
3077 char name[32], *pch, *pick_tmp, *data;
91a2c117 3078 int bytes_written=-1;
5011fc31
RC
3079 const wl_ext_iovar_tpl_t *tpl = wl_ext_iovar_tpl_list;
3080 int tpl_count = ARRAY_SIZE(wl_ext_iovar_tpl_list);
91a2c117
RC
3081
3082 ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
5011fc31 3083 pick_tmp = command;
91a2c117 3084
5011fc31
RC
3085 pch = bcmstrtok(&pick_tmp, " ", 0); // pick wl
3086 if (!pch || strncmp(pch, "wl", 2))
3087 goto exit;
3088
3089 pch = bcmstrtok(&pick_tmp, " ", 0); // pick cmd
3090 if (!pch)
3091 goto exit;
3092
3093 memset(name, 0 , sizeof (name));
3094 cmd = (int)simple_strtol(pch, NULL, 0);
3095 if (cmd == 0) {
3096 strcpy(name, pch);
3097 }
3098 data = bcmstrtok(&pick_tmp, " ", 0); // pick data
3099 if (data && cmd == 0) {
3100 cmd = WLC_SET_VAR;
3101 } else if (cmd == 0) {
3102 cmd = WLC_GET_VAR;
3103 }
3104
3105 /* look for a matching code in the table */
3106 for (i = 0; i < tpl_count; i++, tpl++) {
3107 if ((tpl->get == cmd || tpl->set == cmd) && !strcmp(tpl->name, name))
3108 break;
3109 }
3110 if (i < tpl_count && tpl->parse) {
3111 ret = tpl->parse(dev, data, command, total_len);
3112 } else {
3113 if (cmd == WLC_SET_VAR) {
3114 val = (int)simple_strtol(data, NULL, 0);
3115 ANDROID_TRACE(("%s: set %s %d\n", __FUNCTION__, name, val));
3116 ret = wl_ext_iovar_setint(dev, name, val);
3117 } else if (cmd == WLC_GET_VAR) {
3118 ANDROID_TRACE(("%s: get %s\n", __FUNCTION__, name));
3119 ret = wl_ext_iovar_getint(dev, name, &val);
3120 if (!ret) {
3121 bytes_written = snprintf(command, total_len, "%d", val);
3122 ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__,
3123 command));
3124 ret = bytes_written;
91a2c117 3125 }
5011fc31
RC
3126 } else if (data) {
3127 val = (int)simple_strtol(data, NULL, 0);
3128 ANDROID_TRACE(("%s: set %d %d\n", __FUNCTION__, cmd, val));
3129 ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), TRUE);
3130 } else {
3131 ANDROID_TRACE(("%s: get %d\n", __FUNCTION__, cmd));
3132 ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), FALSE);
3133 if (!ret) {
3134 bytes_written = snprintf(command, total_len, "%d", val);
3135 ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__,
3136 command));
3137 ret = bytes_written;
91a2c117
RC
3138 }
3139 }
3140 }
3141
5011fc31 3142exit:
91a2c117
RC
3143 return ret;
3144}
3145
d964ce36 3146int wl_android_ext_priv_cmd(struct net_device *net, char *command,
3147 int total_len, int *bytes_written)
91a2c117
RC
3148{
3149 int ret = 0;
3150
3151 if (strnicmp(command, CMD_CHANNELS, strlen(CMD_CHANNELS)) == 0) {
3152 *bytes_written = wl_ext_channels(net, command, total_len);
3153 }
3154 else if (strnicmp(command, CMD_CHANNEL, strlen(CMD_CHANNEL)) == 0) {
3155 *bytes_written = wl_ext_channel(net, command, total_len);
3156 }
3157 else if (strnicmp(command, CMD_ROAM_TRIGGER, strlen(CMD_ROAM_TRIGGER)) == 0) {
3158 *bytes_written = wl_ext_roam_trigger(net, command, total_len);
3159 }
3160 else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
3161 *bytes_written = wl_ext_keep_alive(net, command, total_len);
3162 }
3163 else if (strnicmp(command, CMD_PM, strlen(CMD_PM)) == 0) {
3164 *bytes_written = wl_ext_pm(net, command, total_len);
3165 }
010c3a89 3166 else if (strnicmp(command, CMD_MONITOR, strlen(CMD_MONITOR)) == 0) {
91a2c117
RC
3167 *bytes_written = wl_ext_monitor(net, command, total_len);
3168 }
3169 else if (strnicmp(command, CMD_SET_SUSPEND_BCN_LI_DTIM, strlen(CMD_SET_SUSPEND_BCN_LI_DTIM)) == 0) {
3170 int bcn_li_dtim;
3171 bcn_li_dtim = (int)simple_strtol((command + strlen(CMD_SET_SUSPEND_BCN_LI_DTIM) + 1), NULL, 10);
3172 *bytes_written = net_os_set_suspend_bcn_li_dtim(net, bcn_li_dtim);
3173 }
3174#ifdef WL_EXT_IAPSTA
3175 else if (strnicmp(command, CMD_IAPSTA_INIT, strlen(CMD_IAPSTA_INIT)) == 0) {
dfb0f3ae
RC
3176 *bytes_written = wl_ext_isam_init(net, command, total_len);
3177 }
3178 else if (strnicmp(command, CMD_ISAM_INIT, strlen(CMD_ISAM_INIT)) == 0) {
3179 *bytes_written = wl_ext_isam_init(net, command, total_len);
91a2c117
RC
3180 }
3181 else if (strnicmp(command, CMD_IAPSTA_CONFIG, strlen(CMD_IAPSTA_CONFIG)) == 0) {
3182 *bytes_written = wl_ext_iapsta_config(net, command, total_len);
3183 }
dfb0f3ae
RC
3184 else if (strnicmp(command, CMD_ISAM_CONFIG, strlen(CMD_ISAM_CONFIG)) == 0) {
3185 *bytes_written = wl_ext_iapsta_config(net, command, total_len);
3186 }
91a2c117
RC
3187 else if (strnicmp(command, CMD_IAPSTA_ENABLE, strlen(CMD_IAPSTA_ENABLE)) == 0) {
3188 *bytes_written = wl_ext_iapsta_enable(net, command, total_len);
3189 }
dfb0f3ae
RC
3190 else if (strnicmp(command, CMD_ISAM_ENABLE, strlen(CMD_ISAM_ENABLE)) == 0) {
3191 *bytes_written = wl_ext_iapsta_enable(net, command, total_len);
3192 }
91a2c117
RC
3193 else if (strnicmp(command, CMD_IAPSTA_DISABLE, strlen(CMD_IAPSTA_DISABLE)) == 0) {
3194 *bytes_written = wl_ext_iapsta_disable(net, command, total_len);
3195 }
dfb0f3ae
RC
3196 else if (strnicmp(command, CMD_ISAM_DISABLE, strlen(CMD_ISAM_DISABLE)) == 0) {
3197 *bytes_written = wl_ext_iapsta_disable(net, command, total_len);
3198 }
d964ce36 3199 else if (strnicmp(command, CMD_ISAM_STATUS, strlen(CMD_ISAM_STATUS)) == 0) {
3200 *bytes_written = wl_ext_isam_status(net);
3201 }
91a2c117
RC
3202#endif
3203#ifdef IDHCP
3204 else if (strnicmp(command, CMD_DHCPC_ENABLE, strlen(CMD_DHCPC_ENABLE)) == 0) {
3205 *bytes_written = wl_ext_dhcpc_enable(net, command, total_len);
3206 }
3207 else if (strnicmp(command, CMD_DHCPC_DUMP, strlen(CMD_DHCPC_DUMP)) == 0) {
3208 *bytes_written = wl_ext_dhcpc_dump(net, command, total_len);
3209 }
d964ce36 3210#endif
3211#ifdef WL_CFG80211
3212 else if (strnicmp(command, CMD_AUTOCHANNEL, strlen(CMD_AUTOCHANNEL)) == 0) {
3213 *bytes_written = wl_cfg80211_autochannel(net, command, total_len);
3214 }
3215#endif
3216#ifdef WL_ESCAN
3217 else if (strnicmp(command, CMD_AUTOCHANNEL, strlen(CMD_AUTOCHANNEL)) == 0) {
3218 *bytes_written = wl_escan_autochannel(net, command, total_len);
3219 }
91a2c117
RC
3220#endif
3221 else if (strnicmp(command, CMD_WL, strlen(CMD_WL)) == 0) {
5011fc31 3222 *bytes_written = wl_ext_wl_iovar(net, command, total_len);
91a2c117
RC
3223 }
3224 else
3225 ret = -1;
3226
3227 return ret;
3228}
3229
d964ce36 3230#if defined(WL_CFG80211) || defined(WL_ESCAN)
3231int
3232wl_ext_get_distance(struct net_device *net, u32 band)
3233{
3234 u32 bw = WL_CHANSPEC_BW_20;
3235 s32 bw_cap = 0, distance = 0;
3236 struct {
3237 u32 band;
3238 u32 bw_cap;
3239 } param = {0, 0};
3240 char buf[WLC_IOCTL_SMLEN]="\0";
3241 s32 err = BCME_OK;
3242
3243 param.band = band;
3244 err = wldev_iovar_getbuf(net, "bw_cap", &param, sizeof(param), buf,
3245 sizeof(buf), NULL);
3246 if (err) {
3247 if (err != BCME_UNSUPPORTED) {
3248 ANDROID_ERROR(("bw_cap failed, %d\n", err));
3249 return err;
3250 } else {
3251 err = wl_ext_iovar_getint(net, "mimo_bw_cap", &bw_cap);
3252 if (err) {
3253 ANDROID_ERROR(("error get mimo_bw_cap (%d)\n", err));
3254 }
3255 if (bw_cap != WLC_N_BW_20ALL)
3256 bw = WL_CHANSPEC_BW_40;
3257 }
3258 } else {
3259 if (WL_BW_CAP_80MHZ(buf[0]))
3260 bw = WL_CHANSPEC_BW_80;
3261 else if (WL_BW_CAP_40MHZ(buf[0]))
3262 bw = WL_CHANSPEC_BW_40;
3263 else
3264 bw = WL_CHANSPEC_BW_20;
3265 }
3266
3267 if (bw == WL_CHANSPEC_BW_20)
3268 distance = 2;
3269 else if (bw == WL_CHANSPEC_BW_40)
3270 distance = 4;
3271 else if (bw == WL_CHANSPEC_BW_80)
3272 distance = 8;
3273 else
3274 distance = 16;
3275 ANDROID_INFO(("%s: bw=0x%x, distance=%d\n", __FUNCTION__, bw, distance));
3276
3277 return distance;
3278}
3279
3280int
3281wl_ext_get_best_channel(struct net_device *net,
3282#if defined(BSSCACHE)
3283 wl_bss_cache_ctrl_t *bss_cache_ctrl,
3284#else
3285 struct wl_scan_results *bss_list,
3286#endif
3287 int ioctl_ver, int *best_2g_ch, int *best_5g_ch
3288)
3289{
3290 struct wl_bss_info *bi = NULL; /* must be initialized */
3291 s32 i, j;
3292#if defined(BSSCACHE)
3293 wl_bss_cache_t *node;
3294#endif
3295 int b_band[CH_MAX_2G_CHANNEL]={0}, a_band1[4]={0}, a_band4[5]={0};
3296 s32 cen_ch, distance, distance_2g, distance_5g, ch, min_ap=999;
3297 u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
3298 wl_uint32_list_t *list;
3299 int ret;
3300 chanspec_t chanspec;
3301
3302 memset(b_band, -1, sizeof(b_band));
3303 memset(a_band1, -1, sizeof(a_band1));
3304 memset(a_band4, -1, sizeof(a_band4));
3305
3306 memset(valid_chan_list, 0, sizeof(valid_chan_list));
3307 list = (wl_uint32_list_t *)(void *) valid_chan_list;
3308 list->count = htod32(WL_NUMCHANNELS);
3309 ret = wldev_ioctl(net, WLC_GET_VALID_CHANNELS, valid_chan_list,
3310 sizeof(valid_chan_list), 0);
3311 if (ret<0) {
3312 ANDROID_ERROR(("%s: get channels failed with %d\n", __FUNCTION__, ret));
3313 return 0;
3314 } else {
3315 for (i = 0; i < dtoh32(list->count); i++) {
3316 ch = dtoh32(list->element[i]);
3317 if (ch < CH_MAX_2G_CHANNEL)
3318 b_band[ch-1] = 0;
3319 else if (ch <= 48)
3320 a_band1[(ch-36)/4] = 0;
3321 else if (ch >= 149 && ch <= 161)
3322 a_band4[(ch-149)/4] = 0;
3323 }
3324 }
3325
3326 distance_2g = wl_ext_get_distance(net, WLC_BAND_2G);
3327 distance_5g = wl_ext_get_distance(net, WLC_BAND_5G);
3328
3329#if defined(BSSCACHE)
3330 node = bss_cache_ctrl->m_cache_head;
3331 for (i=0; node && i<256; i++)
3332#else
3333 for (i=0; i < bss_list->count; i++)
3334#endif
3335 {
3336#if defined(BSSCACHE)
3337 bi = node->results.bss_info;
3338#else
3339 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : bss_list->bss_info;
3340#endif
3341 chanspec = wl_ext_chspec_driver_to_host(ioctl_ver, bi->chanspec);
3342 cen_ch = CHSPEC_CHANNEL(bi->chanspec);
3343 distance = 0;
3344 if (CHSPEC_IS20(chanspec))
3345 distance += 2;
3346 else if (CHSPEC_IS40(chanspec))
3347 distance += 4;
3348 else if (CHSPEC_IS80(chanspec))
3349 distance += 8;
3350 else
3351 distance += 16;
3352
3353 if (CHSPEC_IS2G(chanspec)) {
3354 distance += distance_2g;
3355 for (j=0; j<ARRAYSIZE(b_band); j++) {
3356 if (b_band[j] >= 0 && abs(cen_ch-(1+j)) <= distance)
3357 b_band[j] += 1;
3358 }
3359 } else {
3360 distance += distance_5g;
3361 if (cen_ch <= 48) {
3362 for (j=0; j<ARRAYSIZE(a_band1); j++) {
3363 if (a_band1[j] >= 0 && abs(cen_ch-(36+j*4)) <= distance)
3364 a_band1[j] += 1;
3365 }
3366 } else if (cen_ch >= 149) {
3367 for (j=0; j<ARRAYSIZE(a_band4); j++) {
3368 if (a_band4[j] >= 0 && abs(cen_ch-(149+j*4)) <= distance)
3369 a_band4[j] += 1;
3370 }
3371 }
3372 }
3373#if defined(BSSCACHE)
3374 node = node->next;
3375#endif
3376 }
3377
3378 *best_2g_ch = 0;
3379 min_ap = 999;
3380 for (i=0; i<CH_MAX_2G_CHANNEL; i++) {
3381 if(b_band[i] < min_ap && b_band[i] >= 0) {
3382 min_ap = b_band[i];
3383 *best_2g_ch = i+1;
3384 }
3385 }
3386 *best_5g_ch = 0;
3387 min_ap = 999;
3388 for (i=0; i<ARRAYSIZE(a_band1); i++) {
3389 if(a_band1[i] < min_ap && a_band1[i] >= 0) {
3390 min_ap = a_band1[i];
3391 *best_5g_ch = i*4 + 36;
3392 }
3393 }
3394 for (i=0; i<ARRAYSIZE(a_band4); i++) {
3395 if(a_band4[i] < min_ap && a_band4[i] >= 0) {
3396 min_ap = a_band4[i];
3397 *best_5g_ch = i*4 + 149;
3398 }
3399 }
3400
3401 if (android_msg_level&ANDROID_INFO_LEVEL) {
3402 printf("%s: b_band: ", __FUNCTION__);
3403 for (j=0; j<ARRAYSIZE(b_band); j++)
3404 printf("%d, ", b_band[j]);
3405 printf("\n");
3406 printf("%s: a_band1: ", __FUNCTION__);
3407 for (j=0; j<ARRAYSIZE(a_band1); j++)
3408 printf("%d, ", a_band1[j]);
3409 printf("\n");
3410 printf("%s: a_band4: ", __FUNCTION__);
3411 for (j=0; j<ARRAYSIZE(a_band4); j++)
3412 printf("%d, ", a_band4[j]);
3413 printf("\n");
3414 printf("%s: best_2g_ch=%d, best_5g_ch=%d\n", __FUNCTION__,
3415 *best_2g_ch, *best_5g_ch);
3416 }
3417
3418 return 0;
3419}
3420#endif
3421
91a2c117
RC
3422#if defined(RSSIAVG)
3423void
3424wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
3425{
3426 wl_rssi_cache_t *node, *cur, **rssi_head;
3427 int i=0;
3428
3429 rssi_head = &rssi_cache_ctrl->m_cache_head;
3430 node = *rssi_head;
3431
3432 for (;node;) {
3433 ANDROID_INFO(("%s: Free %d with BSSID %pM\n",
3434 __FUNCTION__, i, &node->BSSID));
3435 cur = node;
3436 node = cur->next;
3437 kfree(cur);
3438 i++;
3439 }
3440 *rssi_head = NULL;
3441}
3442
3443void
3444wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
3445{
3446 wl_rssi_cache_t *node, *prev, **rssi_head;
3447 int i = -1, tmp = 0;
3448 struct timeval now;
3449
3450 do_gettimeofday(&now);
3451
3452 rssi_head = &rssi_cache_ctrl->m_cache_head;
3453 node = *rssi_head;
3454 prev = node;
3455 for (;node;) {
3456 i++;
3457 if (now.tv_sec > node->tv.tv_sec) {
3458 if (node == *rssi_head) {
3459 tmp = 1;
3460 *rssi_head = node->next;
3461 } else {
3462 tmp = 0;
3463 prev->next = node->next;
3464 }
3465 ANDROID_INFO(("%s: Del %d with BSSID %pM\n",
3466 __FUNCTION__, i, &node->BSSID));
3467 kfree(node);
3468 if (tmp == 1) {
3469 node = *rssi_head;
3470 prev = node;
3471 } else {
3472 node = prev->next;
3473 }
3474 continue;
3475 }
3476 prev = node;
3477 node = node->next;
3478 }
3479}
3480
3481void
d964ce36 3482wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
3483 u8 *bssid)
91a2c117
RC
3484{
3485 wl_rssi_cache_t *node, *prev, **rssi_head;
3486 int i = -1, tmp = 0;
3487
3488 rssi_head = &rssi_cache_ctrl->m_cache_head;
3489 node = *rssi_head;
3490 prev = node;
3491 for (;node;) {
3492 i++;
3493 if (!memcmp(&node->BSSID, bssid, ETHER_ADDR_LEN)) {
3494 if (node == *rssi_head) {
3495 tmp = 1;
3496 *rssi_head = node->next;
3497 } else {
3498 tmp = 0;
3499 prev->next = node->next;
3500 }
3501 ANDROID_INFO(("%s: Del %d with BSSID %pM\n",
3502 __FUNCTION__, i, &node->BSSID));
3503 kfree(node);
3504 if (tmp == 1) {
3505 node = *rssi_head;
3506 prev = node;
3507 } else {
3508 node = prev->next;
3509 }
3510 continue;
3511 }
3512 prev = node;
3513 node = node->next;
3514 }
3515}
3516
3517void
3518wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
3519{
3520 wl_rssi_cache_t *node, **rssi_head;
3521
3522 rssi_head = &rssi_cache_ctrl->m_cache_head;
3523
3524 /* reset dirty */
3525 node = *rssi_head;
3526 for (;node;) {
3527 node->dirty += 1;
3528 node = node->next;
3529 }
3530}
3531
3532int
d964ce36 3533wl_update_connected_rssi_cache(struct net_device *net,
3534 wl_rssi_cache_ctrl_t *rssi_cache_ctrl, int *rssi_avg)
91a2c117
RC
3535{
3536 wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
3537 int j, k=0;
3538 int rssi, error=0;
3539 struct ether_addr bssid;
3540 struct timeval now, timeout;
d964ce36 3541 scb_val_t scbval;
91a2c117
RC
3542
3543 if (!g_wifi_on)
3544 return 0;
3545
3546 error = wldev_ioctl(net, WLC_GET_BSSID, &bssid, sizeof(bssid), false);
3547 if (error == BCME_NOTASSOCIATED) {
3548 ANDROID_INFO(("%s: Not Associated! res:%d\n", __FUNCTION__, error));
3549 return 0;
3550 }
3551 if (error) {
3552 ANDROID_ERROR(("Could not get bssid (%d)\n", error));
3553 }
d964ce36 3554 error = wldev_get_rssi(net, &scbval);
91a2c117
RC
3555 if (error) {
3556 ANDROID_ERROR(("Could not get rssi (%d)\n", error));
3557 return error;
3558 }
d964ce36 3559 rssi = scbval.val;
91a2c117
RC
3560
3561 do_gettimeofday(&now);
3562 timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT;
3563 if (timeout.tv_sec < now.tv_sec) {
3564 /*
3565 * Integer overflow - assume long enough timeout to be assumed
3566 * to be infinite, i.e., the timeout would never happen.
3567 */
3568 ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu",
3569 __FUNCTION__, RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec));
3570 }
3571
3572 /* update RSSI */
3573 rssi_head = &rssi_cache_ctrl->m_cache_head;
3574 node = *rssi_head;
3575 prev = NULL;
3576 for (;node;) {
3577 if (!memcmp(&node->BSSID, &bssid, ETHER_ADDR_LEN)) {
3578 ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%d\n",
3579 __FUNCTION__, k, &bssid, rssi));
3580 for (j=0; j<RSSIAVG_LEN-1; j++)
3581 node->RSSI[j] = node->RSSI[j+1];
3582 node->RSSI[j] = rssi;
3583 node->dirty = 0;
3584 node->tv = timeout;
3585 goto exit;
3586 }
3587 prev = node;
3588 node = node->next;
3589 k++;
3590 }
3591
3592 leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
3593 if (!leaf) {
3594 ANDROID_ERROR(("%s: Memory alloc failure %d\n",
3595 __FUNCTION__, (int)sizeof(wl_rssi_cache_t)));
3596 return 0;
3597 }
3598 ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%3d in the leaf\n",
3599 __FUNCTION__, k, &bssid, rssi));
3600
3601 leaf->next = NULL;
3602 leaf->dirty = 0;
3603 leaf->tv = timeout;
3604 memcpy(&leaf->BSSID, &bssid, ETHER_ADDR_LEN);
3605 for (j=0; j<RSSIAVG_LEN; j++)
3606 leaf->RSSI[j] = rssi;
3607
3608 if (!prev)
3609 *rssi_head = leaf;
3610 else
3611 prev->next = leaf;
3612
3613exit:
3614 *rssi_avg = (int)wl_get_avg_rssi(rssi_cache_ctrl, &bssid);
3615
3616 return error;
3617}
3618
3619void
d964ce36 3620wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
3621 wl_scan_results_t *ss_list)
91a2c117
RC
3622{
3623 wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
3624 wl_bss_info_t *bi = NULL;
3625 int i, j, k;
3626 struct timeval now, timeout;
3627
3628 if (!ss_list->count)
3629 return;
3630
3631 do_gettimeofday(&now);
3632 timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT;
3633 if (timeout.tv_sec < now.tv_sec) {
3634 /*
3635 * Integer overflow - assume long enough timeout to be assumed
3636 * to be infinite, i.e., the timeout would never happen.
3637 */
3638 ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu",
3639 __FUNCTION__, RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec));
3640 }
3641
3642 rssi_head = &rssi_cache_ctrl->m_cache_head;
3643
3644 /* update RSSI */
3645 for (i = 0; i < ss_list->count; i++) {
3646 node = *rssi_head;
3647 prev = NULL;
3648 k = 0;
3649 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
3650 for (;node;) {
3651 if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
3652 ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
3653 __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
3654 for (j=0; j<RSSIAVG_LEN-1; j++)
3655 node->RSSI[j] = node->RSSI[j+1];
3656 node->RSSI[j] = dtoh16(bi->RSSI);
3657 node->dirty = 0;
3658 node->tv = timeout;
3659 break;
3660 }
3661 prev = node;
3662 node = node->next;
3663 k++;
3664 }
3665
3666 if (node)
3667 continue;
3668
3669 leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
3670 if (!leaf) {
3671 ANDROID_ERROR(("%s: Memory alloc failure %d\n",
3672 __FUNCTION__, (int)sizeof(wl_rssi_cache_t)));
3673 return;
3674 }
3675 ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\" in the leaf\n",
3676 __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
3677
3678 leaf->next = NULL;
3679 leaf->dirty = 0;
3680 leaf->tv = timeout;
3681 memcpy(&leaf->BSSID, &bi->BSSID, ETHER_ADDR_LEN);
3682 for (j=0; j<RSSIAVG_LEN; j++)
3683 leaf->RSSI[j] = dtoh16(bi->RSSI);
3684
3685 if (!prev)
3686 *rssi_head = leaf;
3687 else
3688 prev->next = leaf;
3689 }
3690}
3691
3692int16
3693wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr)
3694{
3695 wl_rssi_cache_t *node, **rssi_head;
3696 int j, rssi_sum, rssi=RSSI_MINVAL;
3697
3698 rssi_head = &rssi_cache_ctrl->m_cache_head;
3699
3700 node = *rssi_head;
3701 for (;node;) {
3702 if (!memcmp(&node->BSSID, addr, ETHER_ADDR_LEN)) {
3703 rssi_sum = 0;
3704 rssi = 0;
3705 for (j=0; j<RSSIAVG_LEN; j++)
3706 rssi_sum += node->RSSI[RSSIAVG_LEN-j-1];
3707 rssi = rssi_sum / j;
3708 break;
3709 }
3710 node = node->next;
3711 }
3712 rssi = MIN(rssi, RSSI_MAXVAL);
3713 if (rssi == RSSI_MINVAL) {
3714 ANDROID_ERROR(("%s: BSSID %pM does not in RSSI cache\n",
3715 __FUNCTION__, addr));
3716 }
3717 return (int16)rssi;
3718}
3719#endif
3720
3721#if defined(RSSIOFFSET)
3722int
3723wl_update_rssi_offset(struct net_device *net, int rssi)
3724{
3725#if defined(RSSIOFFSET_NEW)
3726 int j;
3727#endif
3728
3729 if (!g_wifi_on)
3730 return rssi;
3731
3732#if defined(RSSIOFFSET_NEW)
3733 for (j=0; j<RSSI_OFFSET; j++) {
3734 if (rssi - (RSSI_OFFSET_MINVAL+RSSI_OFFSET_INTVAL*(j+1)) < 0)
3735 break;
3736 }
3737 rssi += j;
3738#else
3739 rssi += RSSI_OFFSET;
3740#endif
3741 return MIN(rssi, RSSI_MAXVAL);
3742}
3743#endif
3744
3745#if defined(BSSCACHE)
3746void
3747wl_free_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
3748{
3749 wl_bss_cache_t *node, *cur, **bss_head;
3750 int i=0;
3751
3752 ANDROID_TRACE(("%s called\n", __FUNCTION__));
3753
3754 bss_head = &bss_cache_ctrl->m_cache_head;
3755 node = *bss_head;
3756
3757 for (;node;) {
3758 ANDROID_TRACE(("%s: Free %d with BSSID %pM\n",
3759 __FUNCTION__, i, &node->results.bss_info->BSSID));
3760 cur = node;
3761 node = cur->next;
3762 kfree(cur);
3763 i++;
3764 }
3765 *bss_head = NULL;
3766}
3767
3768void
3769wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
3770{
3771 wl_bss_cache_t *node, *prev, **bss_head;
3772 int i = -1, tmp = 0;
3773 struct timeval now;
3774
3775 do_gettimeofday(&now);
3776
3777 bss_head = &bss_cache_ctrl->m_cache_head;
3778 node = *bss_head;
3779 prev = node;
3780 for (;node;) {
3781 i++;
3782 if (now.tv_sec > node->tv.tv_sec) {
3783 if (node == *bss_head) {
3784 tmp = 1;
3785 *bss_head = node->next;
3786 } else {
3787 tmp = 0;
3788 prev->next = node->next;
3789 }
3790 ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
3791 __FUNCTION__, i, &node->results.bss_info->BSSID,
3792 dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID));
3793 kfree(node);
3794 if (tmp == 1) {
3795 node = *bss_head;
3796 prev = node;
3797 } else {
3798 node = prev->next;
3799 }
3800 continue;
3801 }
3802 prev = node;
3803 node = node->next;
3804 }
3805}
3806
3807void
d964ce36 3808wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
3809 u8 *bssid)
91a2c117
RC
3810{
3811 wl_bss_cache_t *node, *prev, **bss_head;
3812 int i = -1, tmp = 0;
3813
3814 bss_head = &bss_cache_ctrl->m_cache_head;
3815 node = *bss_head;
3816 prev = node;
3817 for (;node;) {
3818 i++;
3819 if (!memcmp(&node->results.bss_info->BSSID, bssid, ETHER_ADDR_LEN)) {
3820 if (node == *bss_head) {
3821 tmp = 1;
3822 *bss_head = node->next;
3823 } else {
3824 tmp = 0;
3825 prev->next = node->next;
3826 }
3827 ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
3828 __FUNCTION__, i, &node->results.bss_info->BSSID,
3829 dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID));
3830 kfree(node);
3831 if (tmp == 1) {
3832 node = *bss_head;
3833 prev = node;
3834 } else {
3835 node = prev->next;
3836 }
3837 continue;
3838 }
3839 prev = node;
3840 node = node->next;
3841 }
3842}
3843
3844void
3845wl_reset_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
3846{
3847 wl_bss_cache_t *node, **bss_head;
3848
3849 bss_head = &bss_cache_ctrl->m_cache_head;
3850
3851 /* reset dirty */
3852 node = *bss_head;
3853 for (;node;) {
3854 node->dirty += 1;
3855 node = node->next;
3856 }
3857}
3858
3859void dump_bss_cache(
3860#if defined(RSSIAVG)
3861 wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
3862#endif
3863 wl_bss_cache_t *node)
3864{
3865 int k = 0;
3866 int16 rssi;
3867
3868 for (;node;) {
3869#if defined(RSSIAVG)
3870 rssi = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID);
3871#else
3872 rssi = dtoh16(node->results.bss_info->RSSI);
3873#endif
3874 ANDROID_TRACE(("%s: dump %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
d964ce36 3875 __FUNCTION__, k, &node->results.bss_info->BSSID, rssi,
3876 node->results.bss_info->SSID));
91a2c117
RC
3877 k++;
3878 node = node->next;
3879 }
3880}
3881
3882void
3883wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
3884#if defined(RSSIAVG)
3885 wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
3886#endif
3887 wl_scan_results_t *ss_list)
3888{
3889 wl_bss_cache_t *node, *prev, *leaf, **bss_head;
3890 wl_bss_info_t *bi = NULL;
3891 int i, k=0;
3892#if defined(SORT_BSS_BY_RSSI)
3893 int16 rssi, rssi_node;
3894#endif
3895 struct timeval now, timeout;
3896
3897 if (!ss_list->count)
3898 return;
3899
3900 do_gettimeofday(&now);
3901 timeout.tv_sec = now.tv_sec + BSSCACHE_TIMEOUT;
3902 if (timeout.tv_sec < now.tv_sec) {
3903 /*
3904 * Integer overflow - assume long enough timeout to be assumed
3905 * to be infinite, i.e., the timeout would never happen.
3906 */
3907 ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu",
3908 __FUNCTION__, BSSCACHE_TIMEOUT, now.tv_sec, timeout.tv_sec));
3909 }
3910
3911 bss_head = &bss_cache_ctrl->m_cache_head;
3912
3913 for (i=0; i < ss_list->count; i++) {
3914 node = *bss_head;
3915 prev = NULL;
3916 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
3917
3918 for (;node;) {
3919 if (!memcmp(&node->results.bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
3920 if (node == *bss_head)
3921 *bss_head = node->next;
3922 else {
3923 prev->next = node->next;
3924 }
3925 break;
3926 }
3927 prev = node;
3928 node = node->next;
3929 }
3930
3931 leaf = kmalloc(dtoh32(bi->length) + sizeof(wl_bss_cache_t), GFP_KERNEL);
3932 if (!leaf) {
3933 ANDROID_ERROR(("%s: Memory alloc failure %d\n", __FUNCTION__,
3934 dtoh32(bi->length) + (int)sizeof(wl_bss_cache_t)));
3935 return;
3936 }
3937 if (node) {
3938 kfree(node);
3939 node = NULL;
3940 ANDROID_TRACE(("%s: Update %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
3941 __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
3942 } else
3943 ANDROID_TRACE(("%s: Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
3944 __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
3945
3946 memcpy(leaf->results.bss_info, bi, dtoh32(bi->length));
3947 leaf->next = NULL;
3948 leaf->dirty = 0;
3949 leaf->tv = timeout;
3950 leaf->results.count = 1;
3951 leaf->results.version = ss_list->version;
3952 k++;
3953
3954 if (*bss_head == NULL)
3955 *bss_head = leaf;
3956 else {
3957#if defined(SORT_BSS_BY_RSSI)
3958 node = *bss_head;
3959#if defined(RSSIAVG)
3960 rssi = wl_get_avg_rssi(rssi_cache_ctrl, &leaf->results.bss_info->BSSID);
3961#else
3962 rssi = dtoh16(leaf->results.bss_info->RSSI);
3963#endif
3964 for (;node;) {
3965#if defined(RSSIAVG)
d964ce36 3966 rssi_node = wl_get_avg_rssi(rssi_cache_ctrl,
3967 &node->results.bss_info->BSSID);
91a2c117
RC
3968#else
3969 rssi_node = dtoh16(node->results.bss_info->RSSI);
3970#endif
3971 if (rssi > rssi_node) {
3972 leaf->next = node;
3973 if (node == *bss_head)
3974 *bss_head = leaf;
3975 else
3976 prev->next = leaf;
3977 break;
3978 }
3979 prev = node;
3980 node = node->next;
3981 }
3982 if (node == NULL)
3983 prev->next = leaf;
3984#else
3985 leaf->next = *bss_head;
3986 *bss_head = leaf;
3987#endif
3988 }
3989 }
3990 dump_bss_cache(
3991#if defined(RSSIAVG)
3992 rssi_cache_ctrl,
3993#endif
3994 *bss_head);
3995}
3996
3997void
3998wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl)
3999{
4000 ANDROID_TRACE(("%s:\n", __FUNCTION__));
4001 wl_free_bss_cache(bss_cache_ctrl);
4002}
4003#endif
4004
4005