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