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