2 #include <linux/module.h>
3 #include <linux/netdevice.h>
4 #include <net/netlink.h>
10 #include <bcmendian.h>
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)
19 #endif /* WL_WIRELESS_EXT */
20 #include <wldev_common.h>
23 #include <linux_osl.h>
25 #include <dngl_stats.h>
27 #include <dhd_config.h>
29 #include <wl_cfg80211.h>
30 #endif /* WL_CFG80211 */
35 #define AEXT_ERROR(name, arg1, args...) \
37 if (android_msg_level & ANDROID_ERROR_LEVEL) { \
38 printk(KERN_ERR "[dhd-%s] AEXT-ERROR) %s : " arg1, name, __func__, ## args); \
41 #define AEXT_TRACE(name, arg1, args...) \
43 if (android_msg_level & ANDROID_TRACE_LEVEL) { \
44 printk(KERN_INFO "[dhd-%s] AEXT-TRACE) %s : " arg1, name, __func__, ## args); \
47 #define AEXT_INFO(name, arg1, args...) \
49 if (android_msg_level & ANDROID_INFO_LEVEL) { \
50 printk(KERN_INFO "[dhd-%s] AEXT-INFO) %s : " arg1, name, __func__, ## args); \
53 #define AEXT_DBG(name, arg1, args...) \
55 if (android_msg_level & ANDROID_DBG_LEVEL) { \
56 printk(KERN_INFO "[dhd-%s] AEXT-DBG) %s : " arg1, name, __func__, ## args); \
65 #define htodchanspec(i) i
66 #define dtohchanspec(i) i
67 #define IEEE80211_BAND_2GHZ 0
68 #define IEEE80211_BAND_5GHZ 1
69 #define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20
70 #define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
71 #define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
72 #endif /* WL_CFG80211 */
73 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
76 #define IW_CUSTOM_MAX 256 /* size of extra buffer used for translation of events */
77 #endif /* IW_CUSTOM_MAX */
79 #define CMD_CHANNEL "CHANNEL"
80 #define CMD_CHANNELS "CHANNELS"
81 #define CMD_ROAM_TRIGGER "ROAM_TRIGGER"
83 #define CMD_MONITOR "MONITOR"
84 #define CMD_SET_SUSPEND_BCN_LI_DTIM "SET_SUSPEND_BCN_LI_DTIM"
85 #define CMD_WLMSGLEVEL "WLMSGLEVEL"
88 #include <net/rtnetlink.h>
89 #define CMD_IAPSTA_INIT "IAPSTA_INIT"
90 #define CMD_IAPSTA_CONFIG "IAPSTA_CONFIG"
91 #define CMD_IAPSTA_ENABLE "IAPSTA_ENABLE"
92 #define CMD_IAPSTA_DISABLE "IAPSTA_DISABLE"
93 #define CMD_ISAM_INIT "ISAM_INIT"
94 #define CMD_ISAM_CONFIG "ISAM_CONFIG"
95 #define CMD_ISAM_ENABLE "ISAM_ENABLE"
96 #define CMD_ISAM_DISABLE "ISAM_DISABLE"
97 #define CMD_ISAM_STATUS "ISAM_STATUS"
98 #define CMD_ISAM_PEER_PATH "ISAM_PEER_PATH"
99 #define CMD_ISAM_PARAM "ISAM_PARAM"
101 #ifdef PROP_TXSTATUS_VSDB
102 #include <dhd_wlfc.h>
103 extern int disable_proptx
;
104 #endif /* PROP_TXSTATUS_VSDB */
105 #endif /* PROP_TXSTATUS */
106 #endif /* WL_EXT_IAPSTA */
107 #define CMD_AUTOCHANNEL "AUTOCHANNEL"
111 typedef enum APSTAMODE
{
123 ISTAAPMESH_MODE
= 11,
127 typedef enum IFMODE
{
135 typedef enum BGNMODE
{
143 typedef enum AUTHMODE
{
152 typedef enum ENCMODE
{
167 typedef enum WL_PRIO
{
173 typedef struct wl_if_info
{
174 struct net_device
*dev
;
176 unsigned long status
;
181 char ifname
[IFNAMSIZ
+1];
182 char ssid
[DOT11_MAX_SSID_LEN
];
183 struct ether_addr bssid
;
191 #if defined(WLMESH) && defined(WL_ESCAN)
192 struct wl_escan_info
*escan
;
193 timer_list_compat_t delay_scan
;
194 #endif /* WLMESH && WL_ESCAN */
195 struct delayed_work pm_enable_work
;
196 struct mutex pm_sync
;
197 #ifdef PROPTX_MAXCOUNT
198 int transit_maxcount
;
199 #endif /* PROP_TXSTATUS_VSDB */
202 #define CSA_FW_BIT (1<<0)
203 #define CSA_DRV_BIT (1<<1)
205 typedef struct wl_apsta_params
{
206 struct wl_if_info if_info
[MAX_IF_NUM
];
215 apstamode_t apstamode
;
216 wait_queue_head_t netif_change_event
;
217 struct mutex usr_sync
;
218 #if defined(WLMESH) && defined(WL_ESCAN)
220 struct wl_mesh_params mesh_info
;
221 #endif /* WLMESH && WL_ESCAN */
224 #define MAX_AP_LINK_WAIT_TIME 3000
225 #define MAX_STA_LINK_WAIT_TIME 15000
226 enum wifi_isam_status
{
227 ISAM_STATUS_IF_ADDING
= 0,
228 ISAM_STATUS_IF_READY
,
229 ISAM_STATUS_STA_CONNECTING
,
230 ISAM_STATUS_STA_CONNECTED
,
231 ISAM_STATUS_AP_CREATING
,
232 ISAM_STATUS_AP_CREATED
235 #define wl_get_isam_status(cur_if, stat) \
236 (test_bit(ISAM_STATUS_ ## stat, &(cur_if)->status))
237 #define wl_set_isam_status(cur_if, stat) \
238 (set_bit(ISAM_STATUS_ ## stat, &(cur_if)->status))
239 #define wl_clr_isam_status(cur_if, stat) \
240 (clear_bit(ISAM_STATUS_ ## stat, &(cur_if)->status))
241 #define wl_chg_isam_status(cur_if, stat) \
242 (change_bit(ISAM_STATUS_ ## stat, &(cur_if)->status))
244 static int wl_ext_enable_iface(struct net_device
*dev
, char *ifname
, int wait_up
);
245 static int wl_ext_disable_iface(struct net_device
*dev
, char *ifname
);
246 #if defined(WLMESH) && defined(WL_ESCAN)
247 static int wl_mesh_escan_attach(dhd_pub_t
*dhd
, struct wl_if_info
*cur_if
);
248 #endif /* WLMESH && WL_ESCAN */
249 #endif /* WL_EXT_IAPSTA */
252 typedef struct dhcpc_parameter
{
260 #define WL_WOWL_TCPFIN (1 << 26)
261 typedef struct wl_wowl_pattern2
{
263 wl_wowl_pattern_t wowl_pattern
;
264 } wl_wowl_pattern2_t
;
265 #endif /* WL_EXT_WOWL */
268 typedef struct tcpka_conn
{
270 struct ether_addr dst_mac
; /* Destinition Mac */
271 struct ipv4_addr src_ip
; /* Sorce IP */
272 struct ipv4_addr dst_ip
; /* Destinition IP */
273 uint16 ipid
; /* Ip Identification */
274 uint16 srcport
; /* Source Port Address */
275 uint16 dstport
; /* Destination Port Address */
276 uint32 seq
; /* TCP Sequence Number */
277 uint32 ack
; /* TCP Ack Number */
278 uint16 tcpwin
; /* TCP window */
279 uint32 tsval
; /* Timestamp Value */
280 uint32 tsecr
; /* Timestamp Echo Reply */
281 uint32 len
; /* last packet payload len */
282 uint32 ka_payload_len
; /* keep alive payload length */
283 uint8 ka_payload
[1]; /* keep alive payload */
286 typedef struct tcpka_conn_sess
{
287 uint32 sess_id
; /* session id */
288 uint32 flag
; /* enable/disable flag */
289 wl_mtcpkeep_alive_timers_pkt_t tcpka_timers
;
292 typedef struct tcpka_conn_info
{
296 } tcpka_conn_sess_info_t
;
297 #endif /* WL_EXT_TCPKA */
299 static int wl_ext_wl_iovar(struct net_device
*dev
, char *command
, int total_len
);
302 wl_ext_ioctl(struct net_device
*dev
, u32 cmd
, void *arg
, u32 len
, u32 set
)
306 ret
= wldev_ioctl(dev
, cmd
, arg
, len
, set
);
308 AEXT_ERROR(dev
->name
, "cmd=%d, ret=%d\n", cmd
, ret
);
313 wl_ext_iovar_getint(struct net_device
*dev
, s8
*iovar
, s32
*val
)
317 ret
= wldev_iovar_getint(dev
, iovar
, val
);
319 AEXT_ERROR(dev
->name
, "iovar=%s, ret=%d\n", iovar
, ret
);
325 wl_ext_iovar_setint(struct net_device
*dev
, s8
*iovar
, s32 val
)
329 ret
= wldev_iovar_setint(dev
, iovar
, val
);
331 AEXT_ERROR(dev
->name
, "iovar=%s, ret=%d\n", iovar
, ret
);
337 wl_ext_iovar_getbuf(struct net_device
*dev
, s8
*iovar_name
,
338 void *param
, s32 paramlen
, void *buf
, s32 buflen
, struct mutex
* buf_sync
)
342 ret
= wldev_iovar_getbuf(dev
, iovar_name
, param
, paramlen
, buf
, buflen
, buf_sync
);
344 AEXT_ERROR(dev
->name
, "iovar=%s, ret=%d\n", iovar_name
, ret
);
350 wl_ext_iovar_setbuf(struct net_device
*dev
, s8
*iovar_name
,
351 void *param
, s32 paramlen
, void *buf
, s32 buflen
, struct mutex
* buf_sync
)
355 ret
= wldev_iovar_setbuf(dev
, iovar_name
, param
, paramlen
, buf
, buflen
, buf_sync
);
357 AEXT_ERROR(dev
->name
, "iovar=%s, ret=%d\n", iovar_name
, ret
);
363 wl_ext_iovar_setbuf_bsscfg(struct net_device
*dev
, s8
*iovar_name
,
364 void *param
, s32 paramlen
, void *buf
, s32 buflen
, s32 bsscfg_idx
,
365 struct mutex
* buf_sync
)
369 ret
= wldev_iovar_setbuf_bsscfg(dev
, iovar_name
, param
, paramlen
,
370 buf
, buflen
, bsscfg_idx
, buf_sync
);
372 AEXT_ERROR(dev
->name
, "iovar=%s, ret=%d\n", iovar_name
, ret
);
378 wl_ext_chspec_to_legacy(chanspec_t chspec
)
382 if (wf_chspec_malformed(chspec
)) {
383 AEXT_ERROR("wlan", "input chanspec (0x%04X) malformed\n", chspec
);
387 /* get the channel number */
388 lchspec
= CHSPEC_CHANNEL(chspec
);
390 /* convert the band */
391 if (CHSPEC_IS2G(chspec
)) {
392 lchspec
|= WL_LCHANSPEC_BAND_2G
;
394 lchspec
|= WL_LCHANSPEC_BAND_5G
;
397 /* convert the bw and sideband */
398 if (CHSPEC_IS20(chspec
)) {
399 lchspec
|= WL_LCHANSPEC_BW_20
;
400 lchspec
|= WL_LCHANSPEC_CTL_SB_NONE
;
401 } else if (CHSPEC_IS40(chspec
)) {
402 lchspec
|= WL_LCHANSPEC_BW_40
;
403 if (CHSPEC_CTL_SB(chspec
) == WL_CHANSPEC_CTL_SB_L
) {
404 lchspec
|= WL_LCHANSPEC_CTL_SB_LOWER
;
406 lchspec
|= WL_LCHANSPEC_CTL_SB_UPPER
;
409 /* cannot express the bandwidth */
410 char chanbuf
[CHANSPEC_STR_LEN
];
411 AEXT_ERROR("wlan", "unable to convert chanspec %s (0x%04X) "
412 "to pre-11ac format\n",
413 wf_chspec_ntoa(chspec
, chanbuf
), chspec
);
421 wl_ext_chspec_host_to_driver(int ioctl_ver
, chanspec_t chanspec
)
423 if (ioctl_ver
== 1) {
424 chanspec
= wl_ext_chspec_to_legacy(chanspec
);
425 if (chanspec
== INVCHANSPEC
) {
429 chanspec
= htodchanspec(chanspec
);
435 wl_ext_ch_to_chanspec(int ioctl_ver
, int ch
,
436 struct wl_join_params
*join_params
, size_t *join_params_size
)
438 chanspec_t chanspec
= 0;
441 join_params
->params
.chanspec_num
= 1;
442 join_params
->params
.chanspec_list
[0] = ch
;
444 if (join_params
->params
.chanspec_list
[0] <= CH_MAX_2G_CHANNEL
)
445 chanspec
|= WL_CHANSPEC_BAND_2G
;
447 chanspec
|= WL_CHANSPEC_BAND_5G
;
449 chanspec
|= WL_CHANSPEC_BW_20
;
450 chanspec
|= WL_CHANSPEC_CTL_SB_NONE
;
452 *join_params_size
+= WL_ASSOC_PARAMS_FIXED_SIZE
+
453 join_params
->params
.chanspec_num
* sizeof(chanspec_t
);
455 join_params
->params
.chanspec_list
[0] &= WL_CHANSPEC_CHAN_MASK
;
456 join_params
->params
.chanspec_list
[0] |= chanspec
;
457 join_params
->params
.chanspec_list
[0] =
458 wl_ext_chspec_host_to_driver(ioctl_ver
,
459 join_params
->params
.chanspec_list
[0]);
461 join_params
->params
.chanspec_num
=
462 htod32(join_params
->params
.chanspec_num
);
466 #if defined(WL_EXT_IAPSTA) || defined(WL_CFG80211) || defined(WL_ESCAN)
468 wl_ext_chspec_from_legacy(chanspec_t legacy_chspec
)
472 /* get the channel number */
473 chspec
= LCHSPEC_CHANNEL(legacy_chspec
);
475 /* convert the band */
476 if (LCHSPEC_IS2G(legacy_chspec
)) {
477 chspec
|= WL_CHANSPEC_BAND_2G
;
479 chspec
|= WL_CHANSPEC_BAND_5G
;
482 /* convert the bw and sideband */
483 if (LCHSPEC_IS20(legacy_chspec
)) {
484 chspec
|= WL_CHANSPEC_BW_20
;
486 chspec
|= WL_CHANSPEC_BW_40
;
487 if (LCHSPEC_CTL_SB(legacy_chspec
) == WL_LCHANSPEC_CTL_SB_LOWER
) {
488 chspec
|= WL_CHANSPEC_CTL_SB_L
;
490 chspec
|= WL_CHANSPEC_CTL_SB_U
;
494 if (wf_chspec_malformed(chspec
)) {
495 AEXT_ERROR("wlan", "output chanspec (0x%04X) malformed\n", chspec
);
503 wl_ext_chspec_driver_to_host(int ioctl_ver
, chanspec_t chanspec
)
505 chanspec
= dtohchanspec(chanspec
);
506 if (ioctl_ver
== 1) {
507 chanspec
= wl_ext_chspec_from_legacy(chanspec
);
512 #endif /* WL_EXT_IAPSTA || WL_CFG80211 || WL_ESCAN */
515 wl_ext_check_scan(struct net_device
*dev
, dhd_pub_t
*dhdp
)
518 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
519 #endif /* WL_CFG80211 */
521 struct wl_escan_info
*escan
= dhdp
->escan
;
522 #endif /* WL_ESCAN */
525 if (wl_get_drv_status_all(cfg
, SCANNING
)) {
526 AEXT_ERROR(dev
->name
, "cfg80211 scanning...\n");
529 #endif /* WL_CFG80211 */
532 if (escan
->escan_state
== ESCAN_STATE_SCANING
) {
533 AEXT_ERROR(dev
->name
, "escan scanning...\n");
536 #endif /* WL_ESCAN */
541 #if defined(WL_CFG80211) || defined(WL_ESCAN)
543 wl_ext_user_sync(struct dhd_pub
*dhd
, int ifidx
, bool lock
)
545 struct net_device
*dev
= dhd_idx2net(dhd
, ifidx
);
547 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
548 #endif /* WL_CFG80211 */
550 struct wl_escan_info
*escan
= dhd
->escan
;
551 #endif /* WL_ESCAN */
553 AEXT_INFO(dev
->name
, "lock=%d\n", lock
);
556 #if defined(WL_CFG80211)
557 mutex_lock(&cfg
->usr_sync
);
559 #if defined(WL_ESCAN)
560 mutex_lock(&escan
->usr_sync
);
563 #if defined(WL_CFG80211)
564 mutex_unlock(&cfg
->usr_sync
);
566 #if defined(WL_ESCAN)
567 mutex_unlock(&escan
->usr_sync
);
573 wl_ext_event_complete(struct dhd_pub
*dhd
, int ifidx
)
575 struct net_device
*dev
= dhd_idx2net(dhd
, ifidx
);
577 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
578 #endif /* WL_CFG80211 */
580 struct wl_escan_info
*escan
= dhd
->escan
;
581 #endif /* WL_ESCAN */
582 bool complete
= TRUE
;
585 if (wl_get_drv_status_all(cfg
, SCANNING
)) {
586 AEXT_INFO(dev
->name
, "SCANNING\n");
589 if (wl_get_drv_status_all(cfg
, CONNECTING
)) {
590 AEXT_INFO(dev
->name
, "CONNECTING\n");
593 if (wl_get_drv_status_all(cfg
, DISCONNECTING
)) {
594 AEXT_INFO(dev
->name
, "DISCONNECTING\n");
597 #endif /* WL_CFG80211 */
599 if (escan
->escan_state
== ESCAN_STATE_SCANING
) {
600 AEXT_INFO(dev
->name
, "ESCAN_STATE_SCANING\n");
603 #endif /* WL_ESCAN */
604 if (dhd
->conf
->eapol_status
>= EAPOL_STATUS_4WAY_START
&&
605 dhd
->conf
->eapol_status
< EAPOL_STATUS_4WAY_DONE
) {
606 AEXT_INFO(dev
->name
, "4-WAY handshaking\n");
612 #endif /* WL_CFG80211 && WL_ESCAN */
615 wl_ext_get_ioctl_ver(struct net_device
*dev
, int *ioctl_ver
)
621 ret
= wl_ext_ioctl(dev
, WLC_GET_VERSION
, &val
, sizeof(val
), 0);
626 if (val
!= WLC_IOCTL_VERSION
&& val
!= 1) {
627 AEXT_ERROR(dev
->name
, "Version mismatch, please upgrade. Got %d, expected %d or 1\n",
628 val
, WLC_IOCTL_VERSION
);
637 wl_ext_bss_iovar_war(struct net_device
*ndev
, s32
*val
)
639 dhd_pub_t
*dhd
= dhd_get_pub(ndev
);
641 bool need_war
= false;
643 chip
= dhd_conf_get_chip(dhd
);
645 if (chip
== BCM43362_CHIP_ID
|| chip
== BCM4330_CHIP_ID
||
646 chip
== BCM43430_CHIP_ID
|| chip
== BCM43012_CHIP_ID
||
647 chip
== BCM4354_CHIP_ID
|| chip
== BCM4356_CHIP_ID
||
648 chip
== BCM4345_CHIP_ID
|| chip
== BCM4359_CHIP_ID
||
649 chip
== BCM43143_CHIP_ID
|| chip
== BCM43242_CHIP_ID
||
650 chip
== BCM43569_CHIP_ID
) {
655 /* Few firmware branches have issues in bss iovar handling and
656 * that can't be changed since they are in production.
658 if (*val
== WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE
) {
659 *val
= WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE
;
660 } else if (*val
== WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE
) {
661 *val
= WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE
;
663 /* Ignore for other bss enums */
666 AEXT_TRACE(ndev
->name
, "wl bss %d\n", *val
);
671 wl_ext_set_chanspec(struct net_device
*dev
, int ioctl_ver
,
672 uint16 channel
, chanspec_t
*ret_chspec
)
675 chanspec_t chspec
= 0;
676 chanspec_t fw_chspec
= 0;
677 u32 bw
= WL_CHANSPEC_BW_20
;
680 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
687 if (_chan
<= CH_MAX_2G_CHANNEL
)
688 band
= IEEE80211_BAND_2GHZ
;
690 band
= IEEE80211_BAND_5GHZ
;
692 if (band
== IEEE80211_BAND_5GHZ
) {
693 param
.band
= WLC_BAND_5G
;
694 err
= wl_ext_iovar_getbuf(dev
, "bw_cap", ¶m
, sizeof(param
),
695 iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
697 if (err
!= BCME_UNSUPPORTED
) {
698 AEXT_ERROR(dev
->name
, "bw_cap failed, %d\n", err
);
701 err
= wl_ext_iovar_getint(dev
, "mimo_bw_cap", &bw_cap
);
702 if (bw_cap
!= WLC_N_BW_20ALL
)
703 bw
= WL_CHANSPEC_BW_40
;
706 if (WL_BW_CAP_80MHZ(iovar_buf
[0]))
707 bw
= WL_CHANSPEC_BW_80
;
708 else if (WL_BW_CAP_40MHZ(iovar_buf
[0]))
709 bw
= WL_CHANSPEC_BW_40
;
711 bw
= WL_CHANSPEC_BW_20
;
715 else if (band
== IEEE80211_BAND_2GHZ
)
716 bw
= WL_CHANSPEC_BW_20
;
719 chspec
= wf_channel2chspec(_chan
, bw
);
720 if (wf_chspec_valid(chspec
)) {
721 fw_chspec
= wl_ext_chspec_host_to_driver(ioctl_ver
, chspec
);
722 if (fw_chspec
!= INVCHANSPEC
) {
723 if ((err
= wl_ext_iovar_setint(dev
, "chanspec", fw_chspec
)) == BCME_BADCHAN
) {
724 if (bw
== WL_CHANSPEC_BW_80
)
726 err
= wl_ext_ioctl(dev
, WLC_SET_CHANNEL
, &_chan
, sizeof(_chan
), 1);
727 WL_MSG(dev
->name
, "channel %d\n", _chan
);
729 AEXT_ERROR(dev
->name
, "failed to set chanspec error %d\n", err
);
731 WL_MSG(dev
->name
, "channel %d, 0x%x\n", channel
, chspec
);
733 AEXT_ERROR(dev
->name
, "failed to convert host chanspec to fw chanspec\n");
738 if (bw
== WL_CHANSPEC_BW_80
)
739 bw
= WL_CHANSPEC_BW_40
;
740 else if (bw
== WL_CHANSPEC_BW_40
)
741 bw
= WL_CHANSPEC_BW_20
;
746 AEXT_ERROR(dev
->name
, "Invalid chanspec 0x%x\n", chspec
);
749 *ret_chspec
= fw_chspec
;
755 wl_ext_channel(struct net_device
*dev
, char* command
, int total_len
)
760 int bytes_written
= 0;
761 chanspec_t fw_chspec
;
764 AEXT_TRACE(dev
->name
, "cmd %s", command
);
766 sscanf(command
, "%*s %d", &channel
);
769 wl_ext_get_ioctl_ver(dev
, &ioctl_ver
);
770 ret
= wl_ext_set_chanspec(dev
, ioctl_ver
, channel
, &fw_chspec
);
772 if (!(ret
= wl_ext_ioctl(dev
, WLC_GET_CHANNEL
, &ci
,
773 sizeof(channel_info_t
), FALSE
))) {
774 AEXT_TRACE(dev
->name
, "hw_channel %d\n", ci
.hw_channel
);
775 AEXT_TRACE(dev
->name
, "target_channel %d\n", ci
.target_channel
);
776 AEXT_TRACE(dev
->name
, "scan_channel %d\n", ci
.scan_channel
);
777 bytes_written
= snprintf(command
, sizeof(channel_info_t
)+2,
778 "channel %d", ci
.hw_channel
);
779 AEXT_TRACE(dev
->name
, "command result is %s\n", command
);
788 wl_ext_channels(struct net_device
*dev
, char* command
, int total_len
)
791 int bytes_written
= -1;
792 u8 valid_chan_list
[sizeof(u32
)*(WL_NUMCHANNELS
+ 1)];
793 wl_uint32_list_t
*list
;
795 AEXT_TRACE(dev
->name
, "cmd %s", command
);
797 memset(valid_chan_list
, 0, sizeof(valid_chan_list
));
798 list
= (wl_uint32_list_t
*)(void *) valid_chan_list
;
799 list
->count
= htod32(WL_NUMCHANNELS
);
800 ret
= wl_ext_ioctl(dev
, WLC_GET_VALID_CHANNELS
, valid_chan_list
,
801 sizeof(valid_chan_list
), 0);
803 AEXT_ERROR(dev
->name
, "get channels failed with %d\n", ret
);
805 bytes_written
= snprintf(command
, total_len
, "channels");
806 for (i
= 0; i
< dtoh32(list
->count
); i
++) {
807 bytes_written
+= snprintf(command
+bytes_written
, total_len
, " %d",
808 dtoh32(list
->element
[i
]));
810 AEXT_TRACE(dev
->name
, "command result is %s\n", command
);
818 wl_ext_roam_trigger(struct net_device
*dev
, char* command
, int total_len
)
821 int roam_trigger
[2] = {0, 0};
822 int trigger
[2]= {0, 0};
823 int bytes_written
=-1;
825 sscanf(command
, "%*s %10d", &roam_trigger
[0]);
827 if (roam_trigger
[0]) {
828 roam_trigger
[1] = WLC_BAND_ALL
;
829 ret
= wl_ext_ioctl(dev
, WLC_SET_ROAM_TRIGGER
, roam_trigger
,
830 sizeof(roam_trigger
), 1);
832 roam_trigger
[1] = WLC_BAND_2G
;
833 ret
= wl_ext_ioctl(dev
, WLC_GET_ROAM_TRIGGER
, roam_trigger
,
834 sizeof(roam_trigger
), 0);
836 trigger
[0] = roam_trigger
[0];
838 roam_trigger
[1] = WLC_BAND_5G
;
839 ret
= wl_ext_ioctl(dev
, WLC_GET_ROAM_TRIGGER
, &roam_trigger
,
840 sizeof(roam_trigger
), 0);
842 trigger
[1] = roam_trigger
[0];
844 AEXT_TRACE(dev
->name
, "roam_trigger %d %d\n", trigger
[0], trigger
[1]);
845 bytes_written
= snprintf(command
, total_len
, "%d %d", trigger
[0], trigger
[1]);
853 wl_ext_pm(struct net_device
*dev
, char *command
, int total_len
)
857 int bytes_written
=-1;
859 AEXT_TRACE(dev
->name
, "cmd %s", command
);
861 sscanf(command
, "%*s %d", &pm
);
864 ret
= wl_ext_ioctl(dev
, WLC_SET_PM
, &pm
, sizeof(pm
), 1);
866 ret
= wl_ext_ioctl(dev
, WLC_GET_PM
, &pm
, sizeof(pm
), 0);
868 AEXT_TRACE(dev
->name
, "PM = %d", pm
);
871 else if(pm
== PM_MAX
)
873 else if(pm
== PM_FAST
)
874 pm_local
= "PM_FAST";
877 pm_local
= "Invalid";
879 bytes_written
= snprintf(command
, total_len
, "PM %s", pm_local
);
880 AEXT_TRACE(dev
->name
, "command result is %s\n", command
);
889 wl_ext_monitor(struct net_device
*dev
, char *command
, int total_len
)
891 int val
= -1, ret
= -1;
892 int bytes_written
=-1;
894 sscanf(command
, "%*s %d", &val
);
897 ret
= wl_ext_ioctl(dev
, WLC_SET_MONITOR
, &val
, sizeof(val
), 1);
899 ret
= wl_ext_ioctl(dev
, WLC_GET_MONITOR
, &val
, sizeof(val
), 0);
901 AEXT_TRACE(dev
->name
, "monitor = %d\n", val
);
902 bytes_written
= snprintf(command
, total_len
, "monitor %d", val
);
903 AEXT_TRACE(dev
->name
, "command result is %s\n", command
);
912 wl_ext_connect(struct net_device
*dev
, struct wl_conn_info
*conn_info
)
914 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
915 wl_extjoin_params_t
*ext_join_params
= NULL
;
916 struct wl_join_params join_params
;
917 size_t join_params_size
;
920 s8
*iovar_buf
= NULL
;
924 wl_ext_get_ioctl_ver(dev
, &ioctl_ver
);
926 if (dhd
->conf
->chip
== BCM43362_CHIP_ID
)
929 if (conn_info
->channel
) {
933 iovar_buf
= kzalloc(WLC_IOCTL_MAXLEN
, GFP_KERNEL
);
934 if (iovar_buf
== NULL
) {
940 * Join with specific BSSID and cached SSID
941 * If SSID is zero join based on BSSID only
943 join_params_size
= WL_EXTJOIN_PARAMS_FIXED_SIZE
+
944 chan_cnt
* sizeof(chanspec_t
);
945 ext_join_params
= (wl_extjoin_params_t
*)kzalloc(join_params_size
, GFP_KERNEL
);
946 if (ext_join_params
== NULL
) {
950 ext_join_params
->ssid
.SSID_len
= min((uint32
)sizeof(ext_join_params
->ssid
.SSID
),
951 conn_info
->ssid
.SSID_len
);
952 memcpy(&ext_join_params
->ssid
.SSID
, conn_info
->ssid
.SSID
, ext_join_params
->ssid
.SSID_len
);
953 ext_join_params
->ssid
.SSID_len
= htod32(ext_join_params
->ssid
.SSID_len
);
954 /* increate dwell time to receive probe response or detect Beacon
955 * from target AP at a noisy air only during connect command
957 ext_join_params
->scan
.active_time
= chan_cnt
? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS
: -1;
958 ext_join_params
->scan
.passive_time
= chan_cnt
? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS
: -1;
959 /* Set up join scan parameters */
960 ext_join_params
->scan
.scan_type
= -1;
961 ext_join_params
->scan
.nprobes
= chan_cnt
?
962 (ext_join_params
->scan
.active_time
/WL_SCAN_JOIN_PROBE_INTERVAL_MS
) : -1;
963 ext_join_params
->scan
.home_time
= -1;
965 if (memcmp(ðer_null
, &conn_info
->bssid
, ETHER_ADDR_LEN
))
966 memcpy(&ext_join_params
->assoc
.bssid
, &conn_info
->bssid
, ETH_ALEN
);
968 memcpy(&ext_join_params
->assoc
.bssid
, ðer_bcast
, ETH_ALEN
);
969 ext_join_params
->assoc
.chanspec_num
= chan_cnt
;
971 u16 band
, bw
, ctl_sb
;
973 band
= (conn_info
->channel
<= CH_MAX_2G_CHANNEL
) ? WL_CHANSPEC_BAND_2G
974 : WL_CHANSPEC_BAND_5G
;
975 bw
= WL_CHANSPEC_BW_20
;
976 ctl_sb
= WL_CHANSPEC_CTL_SB_NONE
;
977 chspec
= (conn_info
->channel
| band
| bw
| ctl_sb
);
978 ext_join_params
->assoc
.chanspec_list
[0] &= WL_CHANSPEC_CHAN_MASK
;
979 ext_join_params
->assoc
.chanspec_list
[0] |= chspec
;
980 ext_join_params
->assoc
.chanspec_list
[0] =
981 wl_ext_chspec_host_to_driver(ioctl_ver
,
982 ext_join_params
->assoc
.chanspec_list
[0]);
984 ext_join_params
->assoc
.chanspec_num
= htod32(ext_join_params
->assoc
.chanspec_num
);
986 wl_ext_get_sec(dev
, 0, sec
, sizeof(sec
));
988 "Connecting with %pM channel (%d) ssid \"%s\", len (%d), sec=%s\n\n",
989 &ext_join_params
->assoc
.bssid
, conn_info
->channel
,
990 ext_join_params
->ssid
.SSID
, ext_join_params
->ssid
.SSID_len
, sec
);
991 err
= wl_ext_iovar_setbuf_bsscfg(dev
, "join", ext_join_params
,
992 join_params_size
, iovar_buf
, WLC_IOCTL_MAXLEN
, conn_info
->bssidx
, NULL
);
995 if (err
== BCME_UNSUPPORTED
) {
996 AEXT_TRACE(dev
->name
, "join iovar is not supported\n");
999 AEXT_ERROR(dev
->name
, "error (%d)\n", err
);
1006 memset(&join_params
, 0, sizeof(join_params
));
1007 join_params_size
= sizeof(join_params
.ssid
);
1009 join_params
.ssid
.SSID_len
= min((uint32
)sizeof(join_params
.ssid
.SSID
),
1010 conn_info
->ssid
.SSID_len
);
1011 memcpy(&join_params
.ssid
.SSID
, conn_info
->ssid
.SSID
, join_params
.ssid
.SSID_len
);
1012 join_params
.ssid
.SSID_len
= htod32(join_params
.ssid
.SSID_len
);
1013 if (memcmp(ðer_null
, &conn_info
->bssid
, ETHER_ADDR_LEN
))
1014 memcpy(&join_params
.params
.bssid
, &conn_info
->bssid
, ETH_ALEN
);
1016 memcpy(&join_params
.params
.bssid
, ðer_bcast
, ETH_ALEN
);
1018 wl_ext_ch_to_chanspec(ioctl_ver
, conn_info
->channel
, &join_params
, &join_params_size
);
1019 AEXT_TRACE(dev
->name
, "join_param_size %zu\n", join_params_size
);
1021 if (join_params
.ssid
.SSID_len
< IEEE80211_MAX_SSID_LEN
) {
1022 AEXT_INFO(dev
->name
, "ssid \"%s\", len (%d)\n", join_params
.ssid
.SSID
,
1023 join_params
.ssid
.SSID_len
);
1025 wl_ext_get_sec(dev
, 0, sec
, sizeof(sec
));
1027 "Connecting with %pM channel (%d) ssid \"%s\", len (%d), sec=%s\n\n",
1028 &join_params
.params
.bssid
, conn_info
->channel
,
1029 join_params
.ssid
.SSID
, join_params
.ssid
.SSID_len
, sec
);
1030 err
= wl_ext_ioctl(dev
, WLC_SET_SSID
, &join_params
, join_params_size
, 1);
1033 #ifdef WL_EXT_IAPSTA
1035 wl_ext_add_remove_pm_enable_work(dev
, TRUE
);
1036 #endif /* WL_EXT_IAPSTA */
1039 if (ext_join_params
)
1040 kfree(ext_join_params
);
1046 wl_ext_get_sec(struct net_device
*dev
, int ifmode
, char *sec
, int total_len
)
1048 int auth
=0, wpa_auth
=0, wsec
=0, mfp
=0;
1049 int bytes_written
=0;
1051 memset(sec
, 0, total_len
);
1052 wl_ext_iovar_getint(dev
, "auth", &auth
);
1053 wl_ext_iovar_getint(dev
, "wpa_auth", &wpa_auth
);
1054 wl_ext_iovar_getint(dev
, "wsec", &wsec
);
1055 wldev_iovar_getint(dev
, "mfp", &mfp
);
1057 #ifdef WL_EXT_IAPSTA
1058 if (ifmode
== IMESH_MODE
) {
1059 if (auth
== WL_AUTH_OPEN_SYSTEM
&& wpa_auth
== WPA_AUTH_DISABLED
) {
1060 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "open");
1061 } else if (auth
== WL_AUTH_OPEN_SYSTEM
&& wpa_auth
== WPA2_AUTH_PSK
) {
1062 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "sae");
1064 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "%d/0x%x",
1068 #endif /* WL_EXT_IAPSTA */
1070 if (auth
== WL_AUTH_OPEN_SYSTEM
&& wpa_auth
== WPA_AUTH_DISABLED
) {
1071 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "open");
1072 } else if (auth
== WL_AUTH_SHARED_KEY
&& wpa_auth
== WPA_AUTH_DISABLED
) {
1073 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "shared");
1074 } else if (auth
== WL_AUTH_OPEN_SYSTEM
&& wpa_auth
== WPA_AUTH_PSK
) {
1075 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "wpapsk");
1076 } else if (auth
== WL_AUTH_OPEN_SYSTEM
&& wpa_auth
== WPA2_AUTH_PSK
) {
1077 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "wpa2psk");
1078 } else if ((auth
== WL_AUTH_OPEN_SYSTEM
|| auth
== WL_AUTH_SAE_KEY
) &&
1079 wpa_auth
== WPA3_AUTH_SAE_PSK
) {
1080 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "wpa3");
1081 } else if ((auth
== WL_AUTH_OPEN_SYSTEM
|| auth
== WL_AUTH_SAE_KEY
) &&
1083 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "wpa3");
1085 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "%d/0x%x",
1090 if (mfp
== WL_MFP_NONE
) {
1091 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "/mfpn");
1092 } else if (mfp
== WL_MFP_CAPABLE
) {
1093 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "/mfpc");
1094 } else if (mfp
== WL_MFP_REQUIRED
) {
1095 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "/mfpr");
1097 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "/%d", mfp
);
1100 #ifdef WL_EXT_IAPSTA
1101 if (ifmode
== IMESH_MODE
) {
1102 if (wsec
== WSEC_NONE
) {
1103 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "/none");
1105 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "/aes");
1108 #endif /* WL_EXT_IAPSTA */
1110 if (wsec
== WSEC_NONE
) {
1111 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "/none");
1112 } else if (wsec
== WEP_ENABLED
) {
1113 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "/wep");
1114 } else if (wsec
== (TKIP_ENABLED
|AES_ENABLED
) ||
1115 wsec
== (WSEC_SWFLAG
|TKIP_ENABLED
|AES_ENABLED
)) {
1116 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "/tkipaes");
1117 } else if (wsec
== TKIP_ENABLED
|| wsec
== (WSEC_SWFLAG
|TKIP_ENABLED
)) {
1118 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "/tkip");
1119 } else if (wsec
== AES_ENABLED
|| wsec
== (WSEC_SWFLAG
|AES_ENABLED
)) {
1120 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "/aes");
1122 bytes_written
+= snprintf(sec
+bytes_written
, total_len
, "/0x%x", wsec
);
1129 wl_ext_dfs_chan(uint16 chan
)
1131 if (chan
>= 52 && chan
<= 144)
1137 wl_ext_get_default_chan(struct net_device
*dev
,
1138 uint16
*chan_2g
, uint16
*chan_5g
, bool nodfs
)
1140 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
1141 uint16 chan_tmp
= 0, chan
= 0;
1142 wl_uint32_list_t
*list
;
1143 u8 valid_chan_list
[sizeof(u32
)*(WL_NUMCHANNELS
+ 1)];
1149 memset(valid_chan_list
, 0, sizeof(valid_chan_list
));
1150 list
= (wl_uint32_list_t
*)(void *) valid_chan_list
;
1151 list
->count
= htod32(WL_NUMCHANNELS
);
1152 ret
= wl_ext_ioctl(dev
, WLC_GET_VALID_CHANNELS
, valid_chan_list
,
1153 sizeof(valid_chan_list
), 0);
1155 for (i
=0; i
<dtoh32(list
->count
); i
++) {
1156 chan_tmp
= dtoh32(list
->element
[i
]);
1157 if (!dhd_conf_match_channel(dhd
, chan_tmp
))
1159 if (chan_tmp
<= 13) {
1160 *chan_2g
= chan_tmp
;
1162 if (wl_ext_dfs_chan(chan_tmp
) && nodfs
)
1164 else if (chan_tmp
>= 36 && chan_tmp
<= 161)
1165 *chan_5g
= chan_tmp
;
1174 wl_ext_wlmsglevel(struct net_device
*dev
, char *command
, int total_len
)
1176 int val
= -1, ret
= 0;
1177 int bytes_written
= 0;
1179 sscanf(command
, "%*s %x", &val
);
1182 if (val
& DHD_ANDROID_VAL
) {
1183 android_msg_level
= (uint
)(val
& 0xFFFF);
1184 printf("android_msg_level=0x%x\n", android_msg_level
);
1186 #if defined(WL_WIRELESS_EXT)
1187 else if (val
& DHD_IW_VAL
) {
1188 iw_msg_level
= (uint
)(val
& 0xFFFF);
1189 printf("iw_msg_level=0x%x\n", iw_msg_level
);
1193 else if (val
& DHD_CFG_VAL
) {
1194 wl_cfg80211_enable_trace((u32
)(val
& 0xFFFF));
1197 else if (val
& DHD_CONFIG_VAL
) {
1198 config_msg_level
= (uint
)(val
& 0xFFFF);
1199 printf("config_msg_level=0x%x\n", config_msg_level
);
1201 else if (val
& DHD_DUMP_VAL
) {
1202 dump_msg_level
= (uint
)(val
& 0xFFFF);
1203 printf("dump_msg_level=0x%x\n", dump_msg_level
);
1207 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
1208 "android_msg_level=0x%x", android_msg_level
);
1209 #if defined(WL_WIRELESS_EXT)
1210 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
1211 "\niw_msg_level=0x%x", iw_msg_level
);
1214 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
1215 "\nwl_dbg_level=0x%x", wl_dbg_level
);
1217 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
1218 "\nconfig_msg_level=0x%x", config_msg_level
);
1219 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
1220 "\ndump_msg_level=0x%x", dump_msg_level
);
1221 AEXT_INFO(dev
->name
, "%s\n", command
);
1222 ret
= bytes_written
;
1228 #if defined(SENDPROB) || (defined(WLMESH) && defined(WL_ESCAN))
1230 wl_ext_add_del_ie(struct net_device
*dev
, uint pktflag
, char *ie_data
, const char* add_del_cmd
)
1232 vndr_ie_setbuf_t
*vndr_ie
= NULL
;
1233 char iovar_buf
[WLC_IOCTL_SMLEN
]="\0";
1234 int ie_data_len
= 0, tot_len
= 0, iecount
;
1237 if (!strlen(ie_data
)) {
1238 AEXT_ERROR(dev
->name
, "wrong ie %s\n", ie_data
);
1242 tot_len
= (int)(sizeof(vndr_ie_setbuf_t
) + ((strlen(ie_data
)-2)/2));
1243 vndr_ie
= (vndr_ie_setbuf_t
*) kzalloc(tot_len
, GFP_KERNEL
);
1245 AEXT_ERROR(dev
->name
, "IE memory alloc failed\n");
1250 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
1251 strncpy(vndr_ie
->cmd
, add_del_cmd
, VNDR_IE_CMD_LEN
- 1);
1252 vndr_ie
->cmd
[VNDR_IE_CMD_LEN
- 1] = '\0';
1254 /* Set the IE count - the buffer contains only 1 IE */
1255 iecount
= htod32(1);
1256 memcpy((void *)&vndr_ie
->vndr_ie_buffer
.iecount
, &iecount
, sizeof(s32
));
1258 /* Set packet flag to indicate that BEACON's will contain this IE */
1259 pktflag
= htod32(pktflag
);
1260 memcpy((void *)&vndr_ie
->vndr_ie_buffer
.vndr_ie_list
[0].pktflag
, &pktflag
,
1264 vndr_ie
->vndr_ie_buffer
.vndr_ie_list
[0].vndr_ie_data
.id
= (uchar
)DOT11_MNG_VS_ID
;
1266 /* Set the IE LEN */
1267 vndr_ie
->vndr_ie_buffer
.vndr_ie_list
[0].vndr_ie_data
.len
= (strlen(ie_data
)-2)/2;
1269 /* Set the IE OUI and DATA */
1270 ie_data_len
= wl_pattern_atoh(ie_data
,
1271 (char *)vndr_ie
->vndr_ie_buffer
.vndr_ie_list
[0].vndr_ie_data
.oui
);
1272 if (ie_data_len
<= 0) {
1273 AEXT_ERROR(dev
->name
, "wrong ie_data_len %d\n", (int)strlen(ie_data
)-2);
1277 err
= wl_ext_iovar_setbuf(dev
, "vndr_ie", vndr_ie
, tot_len
, iovar_buf
,
1278 sizeof(iovar_buf
), NULL
);
1286 #endif /* SENDPROB || (WLMESH && WL_ESCAN) */
1288 #ifdef WL_EXT_IAPSTA
1289 #define WL_PM_ENABLE_TIMEOUT 10000
1290 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
1291 4 && __GNUC_MINOR__ >= 6))
1292 #define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
1293 _Pragma("GCC diagnostic push") \
1294 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
1295 entry = container_of((ptr), type, member); \
1296 _Pragma("GCC diagnostic pop")
1298 #define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
1299 entry = container_of((ptr), type, member);
1300 #endif /* STRICT_GCC_WARNINGS */
1303 wl_ext_pm_work_handler(struct work_struct
*work
)
1305 struct wl_if_info
*cur_if
;
1309 BCM_SET_CONTAINER_OF(cur_if
, work
, struct wl_if_info
, pm_enable_work
.work
);
1311 AEXT_TRACE("wlan", "%s: Enter\n", __FUNCTION__
);
1313 if (cur_if
->dev
== NULL
)
1316 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
1317 4 && __GNUC_MINOR__ >= 6))
1318 _Pragma("GCC diagnostic push")
1319 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
1322 dhd
= dhd_get_pub(cur_if
->dev
);
1324 if (!dhd
|| !dhd
->up
) {
1325 AEXT_TRACE(cur_if
->ifname
, "dhd is null or not up\n");
1328 if (dhd_conf_get_pm(dhd
) >= 0)
1329 pm
= dhd_conf_get_pm(dhd
);
1330 wl_ext_ioctl(cur_if
->dev
, WLC_SET_PM
, &pm
, sizeof(pm
), 1);
1331 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
1332 4 && __GNUC_MINOR__ >= 6))
1333 _Pragma("GCC diagnostic pop")
1335 DHD_PM_WAKE_UNLOCK(dhd
);
1340 wl_ext_add_remove_pm_enable_work(struct net_device
*dev
, bool add
)
1342 dhd_pub_t
*dhd
= dhd_get_pub(dev
);
1343 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
1344 struct wl_if_info
*cur_if
= NULL
, *tmp_if
= NULL
;
1345 u16 wq_duration
= 0;
1349 for (i
=0; i
<MAX_IF_NUM
; i
++) {
1350 tmp_if
= &apsta_params
->if_info
[i
];
1351 if (tmp_if
->dev
&& tmp_if
->dev
== dev
) {
1360 mutex_lock(&cur_if
->pm_sync
);
1362 * Make cancel and schedule work part mutually exclusive
1363 * so that while cancelling, we are sure that there is no
1364 * work getting scheduled.
1367 if (delayed_work_pending(&cur_if
->pm_enable_work
)) {
1368 cancel_delayed_work_sync(&cur_if
->pm_enable_work
);
1369 DHD_PM_WAKE_UNLOCK(dhd
);
1373 wq_duration
= (WL_PM_ENABLE_TIMEOUT
);
1376 /* It should schedule work item only if driver is up */
1378 if (dhd_conf_get_pm(dhd
) >= 0)
1379 pm
= dhd_conf_get_pm(dhd
);
1380 wl_ext_ioctl(cur_if
->dev
, WLC_SET_PM
, &pm
, sizeof(pm
), 1);
1382 if (schedule_delayed_work(&cur_if
->pm_enable_work
,
1383 msecs_to_jiffies((const unsigned int)wq_duration
))) {
1384 DHD_PM_WAKE_LOCK_TIMEOUT(dhd
, wq_duration
);
1386 AEXT_ERROR(cur_if
->ifname
, "Can't schedule pm work handler\n");
1390 mutex_unlock(&cur_if
->pm_sync
);
1395 wl_ext_parse_wep(char *key
, struct wl_wsec_key
*wsec_key
)
1398 unsigned char *data
= wsec_key
->data
;
1401 switch (strlen(keystr
)) {
1405 wsec_key
->len
= strlen(keystr
);
1406 memcpy(data
, keystr
, wsec_key
->len
+ 1);
1412 /* strip leading 0x */
1413 if (!strnicmp(keystr
, "0x", 2))
1422 wsec_key
->len
= strlen(keystr
) / 2;
1424 strncpy(hex
, keystr
, 2);
1425 *data
++ = (char) strtoul(hex
, NULL
, 16);
1433 switch (wsec_key
->len
) {
1435 wsec_key
->algo
= CRYPTO_ALGO_WEP1
;
1438 wsec_key
->algo
= CRYPTO_ALGO_WEP128
;
1441 /* default to AES-CCM */
1442 wsec_key
->algo
= CRYPTO_ALGO_AES_CCM
;
1445 wsec_key
->algo
= CRYPTO_ALGO_TKIP
;
1451 /* Set as primary wsec_key by default */
1452 wsec_key
->flags
|= WL_PRIMARY_KEY
;
1458 wl_ext_set_bgnmode(struct wl_if_info
*cur_if
)
1460 struct net_device
*dev
= cur_if
->dev
;
1461 bgnmode_t bgnmode
= cur_if
->bgnmode
;
1467 wl_ext_ioctl(dev
, WLC_DOWN
, NULL
, 0, 1);
1468 if (bgnmode
== IEEE80211B
) {
1469 wl_ext_iovar_setint(dev
, "nmode", 0);
1471 wl_ext_ioctl(dev
, WLC_SET_GMODE
, &val
, sizeof(val
), 1);
1472 AEXT_TRACE(dev
->name
, "Network mode: B only\n");
1473 } else if (bgnmode
== IEEE80211G
) {
1474 wl_ext_iovar_setint(dev
, "nmode", 0);
1476 wl_ext_ioctl(dev
, WLC_SET_GMODE
, &val
, sizeof(val
), 1);
1477 AEXT_TRACE(dev
->name
, "Network mode: G only\n");
1478 } else if (bgnmode
== IEEE80211BG
) {
1479 wl_ext_iovar_setint(dev
, "nmode", 0);
1481 wl_ext_ioctl(dev
, WLC_SET_GMODE
, &val
, sizeof(val
), 1);
1482 AEXT_TRACE(dev
->name
, "Network mode: B/G mixed\n");
1483 } else if (bgnmode
== IEEE80211BGN
) {
1484 wl_ext_iovar_setint(dev
, "nmode", 0);
1485 wl_ext_iovar_setint(dev
, "nmode", 1);
1486 wl_ext_iovar_setint(dev
, "vhtmode", 0);
1488 wl_ext_ioctl(dev
, WLC_SET_GMODE
, &val
, sizeof(val
), 1);
1489 AEXT_TRACE(dev
->name
, "Network mode: B/G/N mixed\n");
1490 } else if (bgnmode
== IEEE80211BGNAC
) {
1491 wl_ext_iovar_setint(dev
, "nmode", 0);
1492 wl_ext_iovar_setint(dev
, "nmode", 1);
1493 wl_ext_iovar_setint(dev
, "vhtmode", 1);
1495 wl_ext_ioctl(dev
, WLC_SET_GMODE
, &val
, sizeof(val
), 1);
1496 AEXT_TRACE(dev
->name
, "Network mode: B/G/N/AC mixed\n");
1498 wl_ext_ioctl(dev
, WLC_UP
, NULL
, 0, 1);
1504 wl_ext_set_amode(struct wl_if_info
*cur_if
)
1506 struct net_device
*dev
= cur_if
->dev
;
1507 authmode_t amode
= cur_if
->amode
;
1508 int auth
=0, wpa_auth
=0;
1511 if (cur_if
->ifmode
== IMESH_MODE
) {
1512 if (amode
== AUTH_SAE
) {
1513 auth
= WL_AUTH_OPEN_SYSTEM
;
1514 wpa_auth
= WPA2_AUTH_PSK
;
1515 AEXT_INFO(dev
->name
, "SAE\n");
1517 auth
= WL_AUTH_OPEN_SYSTEM
;
1518 wpa_auth
= WPA_AUTH_DISABLED
;
1519 AEXT_INFO(dev
->name
, "Open System\n");
1523 if (amode
== AUTH_OPEN
) {
1524 auth
= WL_AUTH_OPEN_SYSTEM
;
1525 wpa_auth
= WPA_AUTH_DISABLED
;
1526 AEXT_INFO(dev
->name
, "Open System\n");
1527 } else if (amode
== AUTH_SHARED
) {
1528 auth
= WL_AUTH_SHARED_KEY
;
1529 wpa_auth
= WPA_AUTH_DISABLED
;
1530 AEXT_INFO(dev
->name
, "Shared Key\n");
1531 } else if (amode
== AUTH_WPAPSK
) {
1532 auth
= WL_AUTH_OPEN_SYSTEM
;
1533 wpa_auth
= WPA_AUTH_PSK
;
1534 AEXT_INFO(dev
->name
, "WPA-PSK\n");
1535 } else if (amode
== AUTH_WPA2PSK
) {
1536 auth
= WL_AUTH_OPEN_SYSTEM
;
1537 wpa_auth
= WPA2_AUTH_PSK
;
1538 AEXT_INFO(dev
->name
, "WPA2-PSK\n");
1539 } else if (amode
== AUTH_WPAWPA2PSK
) {
1540 auth
= WL_AUTH_OPEN_SYSTEM
;
1541 wpa_auth
= WPA2_AUTH_PSK
| WPA_AUTH_PSK
;
1542 AEXT_INFO(dev
->name
, "WPA/WPA2-PSK\n");
1545 if (cur_if
->ifmode
== IMESH_MODE
) {
1546 s32 val
= WL_BSSTYPE_MESH
;
1547 wl_ext_ioctl(dev
, WLC_SET_INFRA
, &val
, sizeof(val
), 1);
1550 if (cur_if
->ifmode
== ISTA_MODE
) {
1551 s32 val
= WL_BSSTYPE_INFRA
;
1552 wl_ext_ioctl(dev
, WLC_SET_INFRA
, &val
, sizeof(val
), 1);
1554 wl_ext_iovar_setint(dev
, "auth", auth
);
1556 wl_ext_iovar_setint(dev
, "wpa_auth", wpa_auth
);
1562 wl_ext_set_emode(struct wl_apsta_params
*apsta_params
,
1563 struct wl_if_info
*cur_if
)
1565 struct net_device
*dev
= cur_if
->dev
;
1567 struct wl_wsec_key wsec_key
;
1569 authmode_t amode
= cur_if
->amode
;
1570 encmode_t emode
= cur_if
->emode
;
1571 char *key
= cur_if
->key
;
1572 struct dhd_pub
*dhd
= apsta_params
->dhd
;
1574 memset(&wsec_key
, 0, sizeof(wsec_key
));
1575 memset(&psk
, 0, sizeof(psk
));
1578 if (cur_if
->ifmode
== IMESH_MODE
) {
1579 if (amode
== AUTH_SAE
) {
1586 if (emode
== ENC_NONE
) {
1588 AEXT_INFO(dev
->name
, "No securiy\n");
1589 } else if (emode
== ENC_WEP
) {
1591 wl_ext_parse_wep(key
, &wsec_key
);
1592 AEXT_INFO(dev
->name
, "WEP key \"%s\"\n", wsec_key
.data
);
1593 } else if (emode
== ENC_TKIP
) {
1594 wsec
= TKIP_ENABLED
;
1595 psk
.key_len
= strlen(key
);
1596 psk
.flags
= WSEC_PASSPHRASE
;
1597 memcpy(psk
.key
, key
, strlen(key
));
1598 AEXT_INFO(dev
->name
, "TKIP key \"%s\"\n", psk
.key
);
1599 } else if (emode
== ENC_AES
|| amode
== AUTH_SAE
) {
1601 psk
.key_len
= strlen(key
);
1602 psk
.flags
= WSEC_PASSPHRASE
;
1603 memcpy(psk
.key
, key
, strlen(key
));
1604 AEXT_INFO(dev
->name
, "AES key \"%s\"\n", psk
.key
);
1605 } else if (emode
== ENC_TKIPAES
) {
1606 wsec
= TKIP_ENABLED
| AES_ENABLED
;
1607 psk
.key_len
= strlen(key
);
1608 psk
.flags
= WSEC_PASSPHRASE
;
1609 memcpy(psk
.key
, key
, strlen(key
));
1610 AEXT_INFO(dev
->name
, "TKIP/AES key \"%s\"\n", psk
.key
);
1612 if (dhd
->conf
->chip
== BCM43430_CHIP_ID
&& cur_if
->ifidx
> 0 && wsec
>= 2 &&
1613 apsta_params
->apstamode
== ISTAAP_MODE
) {
1614 wsec
|= WSEC_SWFLAG
; // terence 20180628: fix me, this is a workaround
1617 wl_ext_iovar_setint(dev
, "wsec", wsec
);
1620 if (cur_if
->ifmode
== IMESH_MODE
) {
1621 if (amode
== AUTH_SAE
) {
1622 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
1623 AEXT_INFO(dev
->name
, "AES key \"%s\"\n", key
);
1624 wl_ext_iovar_setint(dev
, "mesh_auth_proto", 1);
1625 wl_ext_iovar_setint(dev
, "mfp", WL_MFP_REQUIRED
);
1626 wl_ext_iovar_setbuf(dev
, "sae_password", key
, strlen(key
),
1627 iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
1629 AEXT_INFO(dev
->name
, "No securiy\n");
1630 wl_ext_iovar_setint(dev
, "mesh_auth_proto", 0);
1631 wl_ext_iovar_setint(dev
, "mfp", WL_MFP_NONE
);
1635 if (emode
== ENC_WEP
) {
1636 wl_ext_ioctl(dev
, WLC_SET_KEY
, &wsec_key
, sizeof(wsec_key
), 1);
1637 } else if (emode
== ENC_TKIP
|| emode
== ENC_AES
|| emode
== ENC_TKIPAES
) {
1638 if (cur_if
->ifmode
== ISTA_MODE
)
1639 wl_ext_iovar_setint(dev
, "sup_wpa", 1);
1640 wl_ext_ioctl(dev
, WLC_SET_WSEC_PMK
, &psk
, sizeof(psk
), 1);
1647 wl_ext_get_chanspec(struct wl_apsta_params
*apsta_params
,
1648 struct net_device
*dev
)
1651 struct ether_addr bssid
;
1654 ret
= wldev_ioctl(dev
, WLC_GET_BSSID
, &bssid
, sizeof(bssid
), 0);
1655 if (ret
!= BCME_NOTASSOCIATED
&& memcmp(ðer_null
, &bssid
, ETHER_ADDR_LEN
)) {
1656 if (wl_ext_iovar_getint(dev
, "chanspec", (s32
*)&chanspec
) == BCME_OK
) {
1657 chanspec
= wl_ext_chspec_driver_to_host(apsta_params
->ioctl_ver
, chanspec
);
1666 wl_ext_get_chan(struct wl_apsta_params
*apsta_params
, struct net_device
*dev
)
1669 uint16 chan
= 0, ctl_chan
;
1670 struct ether_addr bssid
;
1673 ret
= wldev_ioctl(dev
, WLC_GET_BSSID
, &bssid
, sizeof(bssid
), 0);
1674 if (ret
!= BCME_NOTASSOCIATED
&& memcmp(ðer_null
, &bssid
, ETHER_ADDR_LEN
)) {
1675 if (wl_ext_iovar_getint(dev
, "chanspec", (s32
*)&chanspec
) == BCME_OK
) {
1676 chanspec
= wl_ext_chspec_driver_to_host(apsta_params
->ioctl_ver
, chanspec
);
1677 ctl_chan
= wf_chspec_ctlchan(chanspec
);
1678 chan
= (u16
)(ctl_chan
& 0x00FF);
1687 wl_ext_chan_to_chanspec(struct wl_apsta_params
*apsta_params
,
1688 struct net_device
*dev
, uint16 channel
)
1690 s32 _chan
= channel
;
1691 chanspec_t chspec
= 0;
1692 chanspec_t fw_chspec
= 0;
1693 u32 bw
= WL_CHANSPEC_BW_20
;
1696 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
1703 if (_chan
<= CH_MAX_2G_CHANNEL
)
1704 band
= IEEE80211_BAND_2GHZ
;
1706 band
= IEEE80211_BAND_5GHZ
;
1708 if (band
== IEEE80211_BAND_5GHZ
) {
1709 param
.band
= WLC_BAND_5G
;
1710 err
= wl_ext_iovar_getbuf(dev
, "bw_cap", ¶m
, sizeof(param
),
1711 iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
1713 if (err
!= BCME_UNSUPPORTED
) {
1714 AEXT_ERROR(dev
->name
, "bw_cap failed, %d\n", err
);
1717 err
= wl_ext_iovar_getint(dev
, "mimo_bw_cap", &bw_cap
);
1718 if (bw_cap
!= WLC_N_BW_20ALL
)
1719 bw
= WL_CHANSPEC_BW_40
;
1722 if (WL_BW_CAP_80MHZ(iovar_buf
[0]))
1723 bw
= WL_CHANSPEC_BW_80
;
1724 else if (WL_BW_CAP_40MHZ(iovar_buf
[0]))
1725 bw
= WL_CHANSPEC_BW_40
;
1727 bw
= WL_CHANSPEC_BW_20
;
1730 else if (band
== IEEE80211_BAND_2GHZ
)
1731 bw
= WL_CHANSPEC_BW_20
;
1734 chspec
= wf_channel2chspec(_chan
, bw
);
1735 if (wf_chspec_valid(chspec
)) {
1736 fw_chspec
= wl_ext_chspec_host_to_driver(apsta_params
->ioctl_ver
, chspec
);
1737 if (fw_chspec
== INVCHANSPEC
) {
1738 AEXT_ERROR(dev
->name
, "failed to convert host chanspec to fw chanspec\n");
1742 if (bw
== WL_CHANSPEC_BW_80
)
1743 bw
= WL_CHANSPEC_BW_40
;
1744 else if (bw
== WL_CHANSPEC_BW_40
)
1745 bw
= WL_CHANSPEC_BW_20
;
1750 AEXT_ERROR(dev
->name
, "Invalid chanspec 0x%x\n", chspec
);
1758 wl_ext_radar_detect(struct net_device
*dev
)
1764 if ((ret
= wldev_ioctl(dev
, WLC_GET_RADAR
, &val
, sizeof(int), false) == 0)) {
1771 static struct wl_if_info
*
1772 wl_ext_if_enabled(struct wl_apsta_params
*apsta_params
, ifmode_t ifmode
)
1774 struct wl_if_info
*tmp_if
, *target_if
= NULL
;
1777 for (i
=0; i
<MAX_IF_NUM
; i
++) {
1778 tmp_if
= &apsta_params
->if_info
[i
];
1779 if (tmp_if
&& tmp_if
->ifmode
== ifmode
&&
1780 wl_get_isam_status(tmp_if
, IF_READY
)) {
1781 if (wl_ext_get_chan(apsta_params
, tmp_if
->dev
)) {
1791 #ifndef WL_STATIC_IF
1793 wl_ext_add_del_bss(struct net_device
*ndev
, s32 bsscfg_idx
,
1794 int iftype
, s32 del
, u8
*addr
)
1798 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
1802 struct ether_addr ea
;
1805 AEXT_TRACE(ndev
->name
, "wl_iftype:%d del:%d \n", iftype
, del
);
1807 bzero(&bss_setbuf
, sizeof(bss_setbuf
));
1809 /* AP=2, STA=3, up=1, down=0, val=-1 */
1811 val
= WLC_AP_IOV_OP_DELETE
;
1812 } else if (iftype
== WL_INTERFACE_CREATE_AP
) {
1813 /* Add/role change to AP Interface */
1814 AEXT_TRACE(ndev
->name
, "Adding AP Interface\n");
1815 val
= WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE
;
1816 } else if (iftype
== WL_INTERFACE_CREATE_STA
) {
1817 /* Add/role change to STA Interface */
1818 AEXT_TRACE(ndev
->name
, "Adding STA Interface\n");
1819 val
= WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE
;
1821 AEXT_ERROR(ndev
->name
, "add_del_bss NOT supported for IFACE type:0x%x", iftype
);
1826 wl_ext_bss_iovar_war(ndev
, &val
);
1829 bss_setbuf
.cfg
= htod32(bsscfg_idx
);
1830 bss_setbuf
.val
= htod32(val
);
1833 memcpy(&bss_setbuf
.ea
.octet
, addr
, ETH_ALEN
);
1836 AEXT_INFO(ndev
->name
, "wl bss %d bssidx:%d\n", val
, bsscfg_idx
);
1837 ret
= wl_ext_iovar_setbuf(ndev
, "bss", &bss_setbuf
, sizeof(bss_setbuf
),
1838 ioctl_buf
, WLC_IOCTL_SMLEN
, NULL
);
1840 AEXT_ERROR(ndev
->name
, "'bss %d' failed with %d\n", val
, ret
);
1846 wl_ext_interface_ops(struct net_device
*dev
,
1847 struct wl_apsta_params
*apsta_params
, int iftype
, u8
*addr
)
1850 struct wl_interface_create_v2 iface
;
1851 wl_interface_create_v3_t iface_v3
;
1852 struct wl_interface_info_v1
*info
;
1853 wl_interface_info_v2_t
*info_v2
;
1855 bool use_iface_info_v2
= false;
1856 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
1857 wl_wlc_version_t wlc_ver
;
1859 /* Interface create */
1860 bzero(&iface
, sizeof(iface
));
1863 ifflags
|= WL_INTERFACE_MAC_USE
;
1866 ret
= wldev_iovar_getbuf(dev
, "wlc_ver", NULL
, 0,
1867 &wlc_ver
, sizeof(wl_wlc_version_t
), NULL
);
1868 if ((ret
== BCME_OK
) && (wlc_ver
.wlc_ver_major
>= 5)) {
1869 ret
= wldev_iovar_getbuf(dev
, "interface_create",
1870 &iface
, sizeof(struct wl_interface_create_v2
),
1871 ioctl_buf
, sizeof(ioctl_buf
), NULL
);
1872 if ((ret
== BCME_OK
) && (*((uint32
*)ioctl_buf
) == WL_INTERFACE_CREATE_VER_3
)) {
1873 use_iface_info_v2
= true;
1874 bzero(&iface_v3
, sizeof(wl_interface_create_v3_t
));
1875 iface_v3
.ver
= WL_INTERFACE_CREATE_VER_3
;
1876 iface_v3
.iftype
= iftype
;
1877 iface_v3
.flags
= ifflags
;
1879 memcpy(&iface_v3
.mac_addr
.octet
, addr
, ETH_ALEN
);
1881 ret
= wl_ext_iovar_getbuf(dev
, "interface_create",
1882 &iface_v3
, sizeof(wl_interface_create_v3_t
),
1883 ioctl_buf
, sizeof(ioctl_buf
), NULL
);
1884 if (unlikely(ret
)) {
1885 AEXT_ERROR(dev
->name
, "Interface v3 create failed!! ret %d\n", ret
);
1892 if (use_iface_info_v2
== true) {
1893 info_v2
= (wl_interface_info_v2_t
*)ioctl_buf
;
1894 ret
= info_v2
->bsscfgidx
;
1897 iface
.ver
= WL_INTERFACE_CREATE_VER_2
;
1898 iface
.iftype
= iftype
;
1899 iface
.flags
= ifflags
;
1901 memcpy(&iface
.mac_addr
.octet
, addr
, ETH_ALEN
);
1903 ret
= wldev_iovar_getbuf(dev
, "interface_create",
1904 &iface
, sizeof(struct wl_interface_create_v2
),
1905 ioctl_buf
, sizeof(ioctl_buf
), NULL
);
1906 if (ret
== BCME_OK
) {
1907 info
= (struct wl_interface_info_v1
*)ioctl_buf
;
1908 ret
= info
->bsscfgidx
;
1912 AEXT_INFO(dev
->name
, "wl interface create success!! bssidx:%d \n", ret
);
1917 wl_ext_wait_netif_change(struct wl_apsta_params
*apsta_params
,
1918 struct wl_if_info
*cur_if
)
1921 wait_event_interruptible_timeout(apsta_params
->netif_change_event
,
1922 wl_get_isam_status(cur_if
, IF_READY
),
1923 msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME
));
1928 wl_ext_interface_create(struct net_device
*dev
, struct wl_apsta_params
*apsta_params
,
1929 struct wl_if_info
*cur_if
, int iftype
, u8
*addr
)
1933 wl_set_isam_status(cur_if
, IF_ADDING
);
1934 ret
= wl_ext_interface_ops(dev
, apsta_params
, iftype
, addr
);
1935 if (ret
== BCME_UNSUPPORTED
) {
1936 wl_ext_add_del_bss(dev
, 1, iftype
, 0, addr
);
1938 wl_ext_wait_netif_change(apsta_params
, cur_if
);
1942 wl_ext_iapsta_intf_add(struct net_device
*dev
, struct wl_apsta_params
*apsta_params
)
1944 struct dhd_pub
*dhd
;
1945 apstamode_t apstamode
= apsta_params
->apstamode
;
1946 struct wl_if_info
*cur_if
;
1947 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
1949 struct ether_addr mac_addr
;
1951 dhd
= dhd_get_pub(dev
);
1952 bzero(&mac_addr
, sizeof(mac_addr
));
1954 if (apstamode
== ISTAAP_MODE
) {
1955 cur_if
= &apsta_params
->if_info
[IF_VIF
];
1956 wl_ext_interface_create(dev
, apsta_params
, cur_if
, WL_INTERFACE_CREATE_AP
, NULL
);
1958 else if (apstamode
== ISTAGO_MODE
) {
1959 bzero(&ifreq
, sizeof(wl_p2p_if_t
));
1960 ifreq
.type
= htod32(WL_P2P_IF_GO
);
1961 cur_if
= &apsta_params
->if_info
[IF_VIF
];
1962 wl_set_isam_status(cur_if
, IF_ADDING
);
1963 wl_ext_iovar_setbuf(dev
, "p2p_ifadd", &ifreq
, sizeof(ifreq
),
1964 iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
1965 wl_ext_wait_netif_change(apsta_params
, cur_if
);
1967 else if (apstamode
== ISTASTA_MODE
) {
1968 cur_if
= &apsta_params
->if_info
[IF_VIF
];
1969 memcpy(&mac_addr
, dev
->dev_addr
, ETHER_ADDR_LEN
);
1970 mac_addr
.octet
[0] |= 0x02;
1971 wl_ext_interface_create(dev
, apsta_params
, cur_if
, WL_INTERFACE_CREATE_STA
,
1974 else if (apstamode
== IDUALAP_MODE
) {
1975 cur_if
= &apsta_params
->if_info
[IF_VIF
];
1976 wl_ext_interface_create(dev
, apsta_params
, cur_if
, WL_INTERFACE_CREATE_AP
, NULL
);
1978 else if (apstamode
== ISTAAPAP_MODE
) {
1979 u8 rand_bytes
[2] = {0, };
1980 get_random_bytes(&rand_bytes
, sizeof(rand_bytes
));
1981 cur_if
= &apsta_params
->if_info
[IF_VIF
];
1982 memcpy(&mac_addr
, dev
->dev_addr
, ETHER_ADDR_LEN
);
1983 mac_addr
.octet
[0] |= 0x02;
1984 mac_addr
.octet
[5] += 0x01;
1985 memcpy(&mac_addr
.octet
[3], rand_bytes
, sizeof(rand_bytes
));
1986 wl_ext_interface_create(dev
, apsta_params
, cur_if
, WL_INTERFACE_CREATE_AP
,
1988 cur_if
= &apsta_params
->if_info
[IF_VIF2
];
1989 memcpy(&mac_addr
, dev
->dev_addr
, ETHER_ADDR_LEN
);
1990 mac_addr
.octet
[0] |= 0x02;
1991 mac_addr
.octet
[5] += 0x02;
1992 memcpy(&mac_addr
.octet
[3], rand_bytes
, sizeof(rand_bytes
));
1993 wl_ext_interface_create(dev
, apsta_params
, cur_if
, WL_INTERFACE_CREATE_AP
,
1997 else if (apstamode
== ISTAMESH_MODE
) {
1998 cur_if
= &apsta_params
->if_info
[IF_VIF
];
1999 wl_ext_interface_create(dev
, apsta_params
, cur_if
, WL_INTERFACE_CREATE_STA
, NULL
);
2001 else if (apstamode
== IMESHAP_MODE
) {
2002 cur_if
= &apsta_params
->if_info
[IF_VIF
];
2003 wl_ext_interface_create(dev
, apsta_params
, cur_if
, WL_INTERFACE_CREATE_AP
, NULL
);
2005 else if (apstamode
== ISTAAPMESH_MODE
) {
2006 cur_if
= &apsta_params
->if_info
[IF_VIF
];
2007 wl_ext_interface_create(dev
, apsta_params
, cur_if
, WL_INTERFACE_CREATE_AP
, NULL
);
2008 cur_if
= &apsta_params
->if_info
[IF_VIF2
];
2009 wl_ext_interface_create(dev
, apsta_params
, cur_if
, WL_INTERFACE_CREATE_STA
, NULL
);
2011 else if (apstamode
== IMESHAPAP_MODE
) {
2012 cur_if
= &apsta_params
->if_info
[IF_VIF
];
2013 wl_ext_interface_create(dev
, apsta_params
, cur_if
, WL_INTERFACE_CREATE_AP
, NULL
);
2014 cur_if
= &apsta_params
->if_info
[IF_VIF2
];
2015 wl_ext_interface_create(dev
, apsta_params
, cur_if
, WL_INTERFACE_CREATE_AP
, NULL
);
2020 #endif /* WL_STATIC_IF */
2023 wl_ext_iapsta_preinit(struct net_device
*dev
, struct wl_apsta_params
*apsta_params
)
2025 struct dhd_pub
*dhd
;
2026 apstamode_t apstamode
= apsta_params
->apstamode
;
2027 struct wl_if_info
*cur_if
;
2028 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
2032 dhd
= dhd_get_pub(dev
);
2034 for (i
=0; i
<MAX_IF_NUM
; i
++) {
2035 cur_if
= &apsta_params
->if_info
[i
];
2036 if (i
>= 1 && !strlen(cur_if
->ifname
))
2037 snprintf(cur_if
->ifname
, IFNAMSIZ
, "wlan%d", i
);
2038 if (cur_if
->ifmode
== ISTA_MODE
) {
2039 cur_if
->channel
= 0;
2040 cur_if
->maxassoc
= -1;
2041 cur_if
->prio
= PRIO_STA
;
2042 cur_if
->prefix
= 'S';
2043 snprintf(cur_if
->ssid
, DOT11_MAX_SSID_LEN
, "ttt_sta");
2044 } else if (cur_if
->ifmode
== IAP_MODE
) {
2045 cur_if
->channel
= 1;
2046 cur_if
->maxassoc
= -1;
2047 cur_if
->prio
= PRIO_AP
;
2048 cur_if
->prefix
= 'A';
2049 snprintf(cur_if
->ssid
, DOT11_MAX_SSID_LEN
, "ttt_ap");
2051 } else if (cur_if
->ifmode
== IMESH_MODE
) {
2052 cur_if
->channel
= 1;
2053 cur_if
->maxassoc
= -1;
2054 cur_if
->prio
= PRIO_MESH
;
2055 cur_if
->prefix
= 'M';
2056 snprintf(cur_if
->ssid
, DOT11_MAX_SSID_LEN
, "ttt_mesh");
2058 if (i
== 0 && apsta_params
->macs
)
2059 wl_mesh_escan_attach(dhd
, cur_if
);
2060 #endif /* WL_ESCAN */
2065 if (FW_SUPPORTED(dhd
, rsdb
)) {
2066 if (apstamode
== IDUALAP_MODE
)
2067 apsta_params
->rsdb
= -1;
2068 else if (apstamode
== ISTAAPAP_MODE
)
2069 apsta_params
->rsdb
= 0;
2070 if (apstamode
== ISTAAPAP_MODE
|| apstamode
== IDUALAP_MODE
||
2071 apstamode
== IMESHONLY_MODE
|| apstamode
== ISTAMESH_MODE
||
2072 apstamode
== IMESHAP_MODE
|| apstamode
== ISTAAPMESH_MODE
||
2073 apstamode
== IMESHAPAP_MODE
) {
2074 wl_config_t rsdb_mode_cfg
= {0, 0};
2075 rsdb_mode_cfg
.config
= apsta_params
->rsdb
;
2076 AEXT_INFO(dev
->name
, "set rsdb_mode %d\n", rsdb_mode_cfg
.config
);
2077 wl_ext_ioctl(dev
, WLC_DOWN
, NULL
, 0, 1);
2078 wl_ext_iovar_setbuf(dev
, "rsdb_mode", &rsdb_mode_cfg
,
2079 sizeof(rsdb_mode_cfg
), iovar_buf
, sizeof(iovar_buf
), NULL
);
2080 wl_ext_ioctl(dev
, WLC_UP
, NULL
, 0, 1);
2083 apsta_params
->rsdb
= 0;
2086 if (apstamode
== ISTAONLY_MODE
) {
2087 wl_ext_ioctl(dev
, WLC_DOWN
, NULL
, 0, 1);
2088 wl_ext_iovar_setint(dev
, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
2089 // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
2090 wl_ext_ioctl(dev
, WLC_UP
, NULL
, 0, 1);
2091 } else if (apstamode
== IAPONLY_MODE
) {
2092 wl_ext_ioctl(dev
, WLC_DOWN
, NULL
, 0, 1);
2093 #ifdef ARP_OFFLOAD_SUPPORT
2094 /* IF SoftAP is enabled, disable arpoe */
2095 dhd_arp_offload_set(dhd
, 0);
2096 dhd_arp_offload_enable(dhd
, FALSE
);
2097 #endif /* ARP_OFFLOAD_SUPPORT */
2098 wl_ext_iovar_setint(dev
, "mpc", 0);
2099 wl_ext_iovar_setint(dev
, "apsta", 0);
2101 wl_ext_ioctl(dev
, WLC_SET_AP
, &val
, sizeof(val
), 1);
2102 #ifdef PROP_TXSTATUS_VSDB
2103 #if defined(BCMSDIO)
2104 if (!(FW_SUPPORTED(dhd
, rsdb
)) && !disable_proptx
) {
2106 dhd_wlfc_get_enable(dhd
, &enabled
);
2109 wl_ext_ioctl(dev
, WLC_UP
, NULL
, 0, 1);
2112 #endif /* BCMSDIO */
2113 #endif /* PROP_TXSTATUS_VSDB */
2115 else if (apstamode
== ISTAAP_MODE
) {
2116 wl_ext_ioctl(dev
, WLC_DOWN
, NULL
, 0, 1);
2117 wl_ext_iovar_setint(dev
, "mpc", 0);
2118 wl_ext_iovar_setint(dev
, "apsta", 1);
2119 wl_ext_ioctl(dev
, WLC_UP
, NULL
, 0, 1);
2121 else if (apstamode
== ISTAGO_MODE
) {
2122 wl_ext_ioctl(dev
, WLC_DOWN
, NULL
, 0, 1);
2123 wl_ext_iovar_setint(dev
, "apsta", 1);
2124 wl_ext_ioctl(dev
, WLC_UP
, NULL
, 0, 1);
2126 else if (apstamode
== ISTASTA_MODE
) {
2128 else if (apstamode
== IDUALAP_MODE
) {
2129 wl_ext_ioctl(dev
, WLC_DOWN
, NULL
, 0, 1);
2130 /* IF SoftAP is enabled, disable arpoe or wlan1 will ping fail */
2131 #ifdef ARP_OFFLOAD_SUPPORT
2132 /* IF SoftAP is enabled, disable arpoe */
2133 dhd_arp_offload_set(dhd
, 0);
2134 dhd_arp_offload_enable(dhd
, FALSE
);
2135 #endif /* ARP_OFFLOAD_SUPPORT */
2136 wl_ext_iovar_setint(dev
, "mpc", 0);
2137 wl_ext_iovar_setint(dev
, "mbcn", 1);
2138 wl_ext_iovar_setint(dev
, "apsta", 0);
2139 wl_ext_ioctl(dev
, WLC_UP
, NULL
, 0, 1);
2141 wl_ext_ioctl(dev
, WLC_SET_AP
, &val
, sizeof(val
), 1);
2143 else if (apstamode
== ISTAAPAP_MODE
) {
2144 wl_ext_ioctl(dev
, WLC_DOWN
, NULL
, 0, 1);
2145 wl_ext_iovar_setint(dev
, "mpc", 0);
2146 wl_ext_iovar_setint(dev
, "mbss", 1);
2147 wl_ext_iovar_setint(dev
, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
2148 wl_ext_ioctl(dev
, WLC_UP
, NULL
, 0, 1);
2149 // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
2152 else if (apstamode
== IMESHONLY_MODE
|| apstamode
== ISTAMESH_MODE
||
2153 apstamode
== IMESHAP_MODE
|| apstamode
== ISTAAPMESH_MODE
||
2154 apstamode
== IMESHAPAP_MODE
) {
2156 wl_ext_ioctl(dev
, WLC_DOWN
, NULL
, 0, 1);
2157 wl_ext_iovar_setint(dev
, "mpc", 0);
2158 if (apstamode
== IMESHONLY_MODE
)
2159 wl_ext_ioctl(dev
, WLC_SET_PM
, &pm
, sizeof(pm
), 1);
2161 wl_ext_iovar_setint(dev
, "mbcn", 1);
2162 wl_ext_iovar_setint(dev
, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
2163 wl_ext_ioctl(dev
, WLC_UP
, NULL
, 0, 1);
2164 // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
2168 wl_ext_get_ioctl_ver(dev
, &apsta_params
->ioctl_ver
);
2169 apsta_params
->init
= TRUE
;
2171 WL_MSG(dev
->name
, "apstamode=%d\n", apstamode
);
2175 wl_ext_isam_param(struct net_device
*dev
, char *command
, int total_len
)
2177 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
2178 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
2180 char *pick_tmp
, *data
, *param
;
2181 int bytes_written
=-1;
2183 AEXT_TRACE(dev
->name
, "command=%s, len=%d\n", command
, total_len
);
2186 param
= bcmstrtok(&pick_tmp
, " ", 0); // pick isam_param
2187 param
= bcmstrtok(&pick_tmp
, " ", 0); // pick cmd
2188 while (param
!= NULL
) {
2189 data
= bcmstrtok(&pick_tmp
, " ", 0); // pick data
2190 if (!strcmp(param
, "acs")) {
2192 apsta_params
->acs
= simple_strtol(data
, NULL
, 0);
2195 bytes_written
= snprintf(command
, total_len
, "%d", apsta_params
->acs
);
2196 ret
= bytes_written
;
2200 param
= bcmstrtok(&pick_tmp
, " ", 0); // pick cmd
2208 wl_ext_isam_init(struct net_device
*dev
, char *command
, int total_len
)
2210 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
2211 char *pch
, *pick_tmp
, *pick_tmp2
, *param
;
2212 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
2215 if (apsta_params
->init
) {
2216 AEXT_ERROR(dev
->name
, "don't init twice\n");
2219 AEXT_TRACE(dev
->name
, "command=%s, len=%d\n", command
, total_len
);
2222 param
= bcmstrtok(&pick_tmp
, " ", 0); // skip iapsta_init
2223 param
= bcmstrtok(&pick_tmp
, " ", 0);
2224 while (param
!= NULL
) {
2225 pick_tmp2
= bcmstrtok(&pick_tmp
, " ", 0);
2227 AEXT_ERROR(dev
->name
, "wrong param %s\n", param
);
2230 if (!strcmp(param
, "mode")) {
2232 if (!strcmp(pick_tmp2
, "sta")) {
2233 apsta_params
->apstamode
= ISTAONLY_MODE
;
2234 } else if (!strcmp(pick_tmp2
, "ap")) {
2235 apsta_params
->apstamode
= IAPONLY_MODE
;
2236 } else if (!strcmp(pick_tmp2
, "sta-ap")) {
2237 apsta_params
->apstamode
= ISTAAP_MODE
;
2238 } else if (!strcmp(pick_tmp2
, "sta-sta")) {
2239 apsta_params
->apstamode
= ISTASTA_MODE
;
2240 apsta_params
->vsdb
= TRUE
;
2241 } else if (!strcmp(pick_tmp2
, "ap-ap")) {
2242 apsta_params
->apstamode
= IDUALAP_MODE
;
2243 } else if (!strcmp(pick_tmp2
, "sta-ap-ap")) {
2244 apsta_params
->apstamode
= ISTAAPAP_MODE
;
2245 } else if (!strcmp(pick_tmp2
, "apsta")) {
2246 apsta_params
->apstamode
= ISTAAP_MODE
;
2247 apsta_params
->if_info
[IF_PIF
].ifmode
= ISTA_MODE
;
2248 apsta_params
->if_info
[IF_VIF
].ifmode
= IAP_MODE
;
2249 } else if (!strcmp(pick_tmp2
, "dualap")) {
2250 apsta_params
->apstamode
= IDUALAP_MODE
;
2251 apsta_params
->if_info
[IF_PIF
].ifmode
= IAP_MODE
;
2252 apsta_params
->if_info
[IF_VIF
].ifmode
= IAP_MODE
;
2253 } else if (!strcmp(pick_tmp2
, "sta-go") ||
2254 !strcmp(pick_tmp2
, "gosta")) {
2255 if (!FW_SUPPORTED(dhd
, p2p
)) {
2258 apsta_params
->apstamode
= ISTAGO_MODE
;
2259 apsta_params
->if_info
[IF_PIF
].ifmode
= ISTA_MODE
;
2260 apsta_params
->if_info
[IF_VIF
].ifmode
= IAP_MODE
;
2262 } else if (!strcmp(pick_tmp2
, "mesh")) {
2263 apsta_params
->apstamode
= IMESHONLY_MODE
;
2264 } else if (!strcmp(pick_tmp2
, "sta-mesh")) {
2265 apsta_params
->apstamode
= ISTAMESH_MODE
;
2266 } else if (!strcmp(pick_tmp2
, "sta-ap-mesh")) {
2267 apsta_params
->apstamode
= ISTAAPMESH_MODE
;
2268 } else if (!strcmp(pick_tmp2
, "mesh-ap")) {
2269 apsta_params
->apstamode
= IMESHAP_MODE
;
2270 } else if (!strcmp(pick_tmp2
, "mesh-ap-ap")) {
2271 apsta_params
->apstamode
= IMESHAPAP_MODE
;
2274 AEXT_ERROR(dev
->name
, "mode [sta|ap|sta-ap|ap-ap]\n");
2277 pch
= bcmstrtok(&pick_tmp2
, " -", 0);
2278 for (i
=0; i
<MAX_IF_NUM
&& pch
; i
++) {
2279 if (!strcmp(pch
, "sta"))
2280 apsta_params
->if_info
[i
].ifmode
= ISTA_MODE
;
2281 else if (!strcmp(pch
, "ap"))
2282 apsta_params
->if_info
[i
].ifmode
= IAP_MODE
;
2284 else if (!strcmp(pch
, "mesh")) {
2285 if (dhd
->conf
->fw_type
!= FW_TYPE_MESH
) {
2286 AEXT_ERROR(dev
->name
, "wrong fw type\n");
2289 apsta_params
->if_info
[i
].ifmode
= IMESH_MODE
;
2292 pch
= bcmstrtok(&pick_tmp2
, " -", 0);
2295 else if (!strcmp(param
, "rsdb")) {
2296 apsta_params
->rsdb
= (int)simple_strtol(pick_tmp2
, NULL
, 0);
2297 } else if (!strcmp(param
, "vsdb")) {
2298 if (!strcmp(pick_tmp2
, "y")) {
2299 apsta_params
->vsdb
= TRUE
;
2300 } else if (!strcmp(pick_tmp2
, "n")) {
2301 apsta_params
->vsdb
= FALSE
;
2303 AEXT_ERROR(dev
->name
, "vsdb [y|n]\n");
2306 } else if (!strcmp(param
, "csa")) {
2307 apsta_params
->csa
= (int)simple_strtol(pick_tmp2
, NULL
, 0);
2308 } else if (!strcmp(param
, "acs")) {
2309 apsta_params
->acs
= (int)simple_strtol(pick_tmp2
, NULL
, 0);
2310 #if defined(WLMESH) && defined(WL_ESCAN)
2311 } else if (!strcmp(param
, "macs")) {
2312 apsta_params
->macs
= (int)simple_strtol(pick_tmp2
, NULL
, 0);
2313 #endif /* WLMESH && WL_ESCAN */
2314 } else if (!strcmp(param
, "ifname")) {
2316 pch
= bcmstrtok(&pick_tmp2
, " -", 0);
2317 for (i
=0; i
<MAX_IF_NUM
&& pch
; i
++) {
2318 strcpy(apsta_params
->if_info
[i
].ifname
, pch
);
2319 pch
= bcmstrtok(&pick_tmp2
, " -", 0);
2321 } else if (!strcmp(param
, "vifname")) {
2322 strcpy(apsta_params
->if_info
[IF_VIF
].ifname
, pick_tmp2
);
2324 param
= bcmstrtok(&pick_tmp
, " ", 0);
2327 if (apsta_params
->apstamode
== 0) {
2328 AEXT_ERROR(dev
->name
, "mode [sta|ap|sta-ap|ap-ap]\n");
2332 wl_ext_iapsta_preinit(dev
, apsta_params
);
2333 #ifndef WL_STATIC_IF
2334 wl_ext_iapsta_intf_add(dev
, apsta_params
);
2335 #endif /* WL_STATIC_IF */
2341 wl_ext_parse_config(struct wl_if_info
*cur_if
, char *command
, char **pick_next
)
2343 char *pch
, *pick_tmp
;
2344 char name
[20], data
[100];
2346 char *ifname_head
= NULL
;
2348 typedef struct config_map_t
{
2354 config_map_t config_map
[] = {
2355 {" ifname ", NULL
, NULL
},
2356 {" ssid ", NULL
, NULL
},
2357 {" bssid ", NULL
, NULL
},
2358 {" bgnmode ", NULL
, NULL
},
2359 {" hidden ", NULL
, NULL
},
2360 {" maxassoc ", NULL
, NULL
},
2361 {" chan ", NULL
, NULL
},
2362 {" amode ", NULL
, NULL
},
2363 {" emode ", NULL
, NULL
},
2364 {" key ", NULL
, NULL
},
2366 config_map_t
*row
, *row_prev
;
2370 // reset head and tail
2371 for (i
= 0; i
< sizeof(config_map
)/sizeof(config_map
[0]); i
++) {
2372 row
= &config_map
[i
];
2374 row
->tail
= pick_tmp
+ strlen(pick_tmp
);
2378 for (i
= 0; i
< sizeof(config_map
)/sizeof(config_map
[0]); i
++) {
2379 row
= &config_map
[i
];
2380 pch
= strstr(pick_tmp
, row
->name
);
2387 for (i
= 0; i
< sizeof(config_map
)/sizeof(config_map
[0]) - 1; i
++) {
2388 row_prev
= &config_map
[i
];
2389 for (j
= i
+1; j
< sizeof(config_map
)/sizeof(config_map
[0]); j
++) {
2390 row
= &config_map
[j
];
2391 if (row
->head
< row_prev
->head
) {
2392 strcpy(name
, row_prev
->name
);
2393 strcpy(row_prev
->name
, row
->name
);
2394 strcpy(row
->name
, name
);
2395 pch
= row_prev
->head
;
2396 row_prev
->head
= row
->head
;
2403 for (i
= 0; i
< sizeof(config_map
)/sizeof(config_map
[0]) - 1; i
++) {
2404 row_prev
= &config_map
[i
];
2405 row
= &config_map
[i
+1];
2406 if (row_prev
->head
) {
2407 row_prev
->tail
= row
->head
;
2411 // remove name from head
2412 for (i
= 0; i
< sizeof(config_map
)/sizeof(config_map
[0]); i
++) {
2413 row
= &config_map
[i
];
2415 if (!strcmp(row
->name
, " ifname ")) {
2416 ifname_head
= row
->head
+ 1;
2419 row
->head
+= strlen(row
->name
);
2423 for (i
= 0; i
< sizeof(config_map
)/sizeof(config_map
[0]); i
++) {
2424 row
= &config_map
[i
];
2426 memset(data
, 0, sizeof(data
));
2427 if (row
->tail
&& row
->tail
> row
->head
) {
2428 strncpy(data
, row
->head
, row
->tail
-row
->head
);
2430 strcpy(data
, row
->head
);
2434 if (!strcmp(row
->name
, " ifname ")) {
2436 } else if (!strcmp(row
->name
, " ssid ")) {
2437 len
= strlen(pick_tmp
);
2438 memset(cur_if
->ssid
, 0, sizeof(cur_if
->ssid
));
2439 if (pick_tmp
[0] == '"' && pick_tmp
[len
-1] == '"')
2440 strncpy(cur_if
->ssid
, &pick_tmp
[1], len
-2);
2442 strcpy(cur_if
->ssid
, pick_tmp
);
2443 } else if (!strcmp(row
->name
, " bssid ")) {
2444 pch
= bcmstrtok(&pick_tmp
, ": ", 0);
2445 for (j
=0; j
<6 && pch
; j
++) {
2446 ((u8
*)&cur_if
->bssid
)[j
] = (int)simple_strtol(pch
, NULL
, 16);
2447 pch
= bcmstrtok(&pick_tmp
, ": ", 0);
2449 } else if (!strcmp(row
->name
, " bgnmode ")) {
2450 if (!strcmp(pick_tmp
, "b"))
2451 cur_if
->bgnmode
= IEEE80211B
;
2452 else if (!strcmp(pick_tmp
, "g"))
2453 cur_if
->bgnmode
= IEEE80211G
;
2454 else if (!strcmp(pick_tmp
, "bg"))
2455 cur_if
->bgnmode
= IEEE80211BG
;
2456 else if (!strcmp(pick_tmp
, "bgn"))
2457 cur_if
->bgnmode
= IEEE80211BGN
;
2458 else if (!strcmp(pick_tmp
, "bgnac"))
2459 cur_if
->bgnmode
= IEEE80211BGNAC
;
2461 AEXT_ERROR(cur_if
->dev
->name
, "bgnmode [b|g|bg|bgn|bgnac]\n");
2464 } else if (!strcmp(row
->name
, " hidden ")) {
2465 if (!strcmp(pick_tmp
, "n"))
2467 else if (!strcmp(pick_tmp
, "y"))
2470 AEXT_ERROR(cur_if
->dev
->name
, "hidden [y|n]\n");
2473 } else if (!strcmp(row
->name
, " maxassoc ")) {
2474 cur_if
->maxassoc
= (int)simple_strtol(pick_tmp
, NULL
, 10);
2475 } else if (!strcmp(row
->name
, " chan ")) {
2476 cur_if
->channel
= (int)simple_strtol(pick_tmp
, NULL
, 10);
2477 } else if (!strcmp(row
->name
, " amode ")) {
2478 if (!strcmp(pick_tmp
, "open"))
2479 cur_if
->amode
= AUTH_OPEN
;
2480 else if (!strcmp(pick_tmp
, "shared"))
2481 cur_if
->amode
= AUTH_SHARED
;
2482 else if (!strcmp(pick_tmp
, "wpapsk"))
2483 cur_if
->amode
= AUTH_WPAPSK
;
2484 else if (!strcmp(pick_tmp
, "wpa2psk"))
2485 cur_if
->amode
= AUTH_WPA2PSK
;
2486 else if (!strcmp(pick_tmp
, "wpawpa2psk"))
2487 cur_if
->amode
= AUTH_WPAWPA2PSK
;
2488 else if (!strcmp(pick_tmp
, "sae"))
2489 cur_if
->amode
= AUTH_SAE
;
2491 AEXT_ERROR(cur_if
->dev
->name
, "amode [open|shared|wpapsk|wpa2psk|wpawpa2psk]\n");
2494 } else if (!strcmp(row
->name
, " emode ")) {
2495 if (!strcmp(pick_tmp
, "none"))
2496 cur_if
->emode
= ENC_NONE
;
2497 else if (!strcmp(pick_tmp
, "wep"))
2498 cur_if
->emode
= ENC_WEP
;
2499 else if (!strcmp(pick_tmp
, "tkip"))
2500 cur_if
->emode
= ENC_TKIP
;
2501 else if (!strcmp(pick_tmp
, "aes"))
2502 cur_if
->emode
= ENC_AES
;
2503 else if (!strcmp(pick_tmp
, "tkipaes"))
2504 cur_if
->emode
= ENC_TKIPAES
;
2506 AEXT_ERROR(cur_if
->dev
->name
, "emode [none|wep|tkip|aes|tkipaes]\n");
2509 } else if (!strcmp(row
->name
, " key ")) {
2510 len
= strlen(pick_tmp
);
2511 memset(cur_if
->key
, 0, sizeof(cur_if
->key
));
2512 if (pick_tmp
[0] == '"' && pick_tmp
[len
-1] == '"')
2513 strncpy(cur_if
->key
, &pick_tmp
[1], len
-2);
2515 strcpy(cur_if
->key
, pick_tmp
);
2520 *pick_next
= ifname_head
;
2525 wl_ext_iapsta_config(struct net_device
*dev
, char *command
, int total_len
)
2527 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
2529 char *pch
, *pch2
, *pick_tmp
, *pick_next
=NULL
, *param
;
2530 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
2531 char ifname
[IFNAMSIZ
+1];
2532 struct wl_if_info
*cur_if
= NULL
, *tmp_if
= NULL
;
2534 if (!apsta_params
->init
) {
2535 AEXT_ERROR(dev
->name
, "please init first\n");
2539 AEXT_TRACE(dev
->name
, "command=%s, len=%d\n", command
, total_len
);
2542 param
= bcmstrtok(&pick_tmp
, " ", 0); // skip iapsta_config
2544 mutex_lock(&apsta_params
->usr_sync
);
2546 while (pick_tmp
!= NULL
) {
2547 memset(ifname
, 0, IFNAMSIZ
+1);
2548 if (!strncmp(pick_tmp
, "ifname ", strlen("ifname "))) {
2549 pch
= pick_tmp
+ strlen("ifname ");
2550 pch2
= strchr(pch
, ' ');
2552 strncpy(ifname
, pch
, pch2
-pch
);
2554 AEXT_ERROR(dev
->name
, "ifname [wlanX]\n");
2558 for (i
=0; i
<MAX_IF_NUM
; i
++) {
2559 tmp_if
= &apsta_params
->if_info
[i
];
2560 if (tmp_if
->dev
&& !strcmp(tmp_if
->dev
->name
, ifname
)) {
2566 AEXT_ERROR(dev
->name
, "wrong ifname=%s in apstamode=%d\n",
2567 ifname
, apsta_params
->apstamode
);
2571 ret
= wl_ext_parse_config(cur_if
, pick_tmp
, &pick_next
);
2574 pick_tmp
= pick_next
;
2576 AEXT_ERROR(dev
->name
, "first arg must be ifname\n");
2583 mutex_unlock(&apsta_params
->usr_sync
);
2589 wl_ext_assoclist(struct net_device
*dev
, char *data
, char *command
,
2592 int ret
= 0, i
, maxassoc
= 0, bytes_written
= 0;
2593 char mac_buf
[MAX_NUM_OF_ASSOCLIST
*
2594 sizeof(struct ether_addr
) + sizeof(uint
)] = {0};
2595 struct maclist
*assoc_maclist
= (struct maclist
*)mac_buf
;
2597 assoc_maclist
->count
= htod32(MAX_NUM_OF_ASSOCLIST
);
2598 ret
= wl_ext_ioctl(dev
, WLC_GET_ASSOCLIST
, assoc_maclist
, sizeof(mac_buf
), 0);
2601 maxassoc
= dtoh32(assoc_maclist
->count
);
2602 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
2604 "no", "------addr------");
2605 for (i
=0; i
<maxassoc
; i
++) {
2606 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
2607 "\n%2d: %pM", i
, &assoc_maclist
->ea
[i
]);
2610 return bytes_written
;
2615 wl_mesh_print_peer_info(mesh_peer_info_ext_t
*mpi_ext
,
2616 uint32 peer_results_count
, char *command
, int total_len
)
2618 char *peering_map
[] = MESH_PEERING_STATE_STRINGS
;
2620 int bytes_written
= 0;
2622 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
2623 "%2s: %12s : %6s : %-6s : %6s :"
2624 " %5s : %4s : %4s : %11s : %4s",
2625 "no", "------addr------ ", "l.aid", "state", "p.aid",
2626 "mppid", "llid", "plid", "entry_state", "rssi");
2627 for (count
=0; count
< peer_results_count
; count
++) {
2628 if (mpi_ext
->entry_state
!= MESH_SELF_PEER_ENTRY_STATE_TIMEDOUT
) {
2629 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
2630 "\n%2d: %pM : 0x%4x : %6s : 0x%4x :"
2631 " %5d : %4d : %4d : %11s : %4d",
2632 count
, &mpi_ext
->ea
, mpi_ext
->local_aid
,
2633 peering_map
[mpi_ext
->peer_info
.state
],
2634 mpi_ext
->peer_info
.peer_aid
,
2635 mpi_ext
->peer_info
.mesh_peer_prot_id
,
2636 mpi_ext
->peer_info
.local_link_id
,
2637 mpi_ext
->peer_info
.peer_link_id
,
2638 (mpi_ext
->entry_state
== MESH_SELF_PEER_ENTRY_STATE_ACTIVE
) ?
2643 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
2644 "\n%2d: %pM : %6s : %5s : %6s :"
2645 " %5s : %4s : %4s : %11s : %4s",
2646 count
, &mpi_ext
->ea
, " NA ", " NA ", " NA ",
2647 " NA ", " NA ", " NA ", " TIMEDOUT ", " NA ");
2652 return bytes_written
;
2656 wl_mesh_get_peer_results(struct net_device
*dev
, char *buf
, int len
)
2659 mesh_peer_info_dump_t
*peer_results
;
2662 memset(buf
, 0, len
);
2663 peer_results
= (mesh_peer_info_dump_t
*)buf
;
2664 indata
= htod32(len
);
2666 ret
= wl_ext_iovar_getbuf(dev
, "mesh_peer_status", &indata
, inlen
, buf
, len
, NULL
);
2668 peer_results
= (mesh_peer_info_dump_t
*)buf
;
2669 ret
= peer_results
->count
;
2676 wl_ext_mesh_peer_status(struct net_device
*dev
, char *data
, char *command
,
2679 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
2680 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
2682 struct wl_if_info
*cur_if
;
2683 mesh_peer_info_dump_t
*peer_results
;
2684 mesh_peer_info_ext_t
*mpi_ext
;
2685 char *peer_buf
= NULL
;
2686 int peer_len
= WLC_IOCTL_MAXLEN
;
2687 int dump_written
= 0, ret
;
2690 peer_buf
= kmalloc(peer_len
, GFP_KERNEL
);
2691 if (peer_buf
== NULL
) {
2692 AEXT_ERROR(dev
->name
, "Failed to allocate buffer of %d bytes\n",
2696 for (i
=0; i
<MAX_IF_NUM
; i
++) {
2697 cur_if
= &apsta_params
->if_info
[i
];
2698 if (cur_if
&& dev
== cur_if
->dev
&& cur_if
->ifmode
== IMESH_MODE
) {
2699 memset(peer_buf
, 0, peer_len
);
2700 ret
= wl_mesh_get_peer_results(dev
, peer_buf
, peer_len
);
2702 peer_results
= (mesh_peer_info_dump_t
*)peer_buf
;
2703 mpi_ext
= (mesh_peer_info_ext_t
*)peer_results
->mpi_ext
;
2704 dump_written
+= wl_mesh_print_peer_info(mpi_ext
,
2705 peer_results
->count
, command
+dump_written
,
2706 total_len
-dump_written
);
2708 } else if (cur_if
&& dev
== cur_if
->dev
) {
2709 AEXT_ERROR(dev
->name
, "[%s][%c] is not mesh interface\n",
2710 cur_if
->ifname
, cur_if
->prefix
);
2717 return dump_written
;
2721 #define WL_MESH_DELAY_SCAN_MS 3000
2723 wl_mesh_timer(unsigned long data
)
2726 struct wl_if_info
*mesh_if
= (struct wl_if_info
*)data
;
2727 struct dhd_pub
*dhd
;
2730 AEXT_ERROR("wlan", "mesh_if is not ready\n");
2734 if (!mesh_if
->dev
) {
2735 AEXT_ERROR("wlan", "ifidx %d is not ready\n", mesh_if
->ifidx
);
2738 dhd
= dhd_get_pub(mesh_if
->dev
);
2740 bzero(&msg
, sizeof(wl_event_msg_t
));
2741 AEXT_TRACE(mesh_if
->dev
->name
, "timer expired\n");
2743 msg
.ifidx
= mesh_if
->ifidx
;
2744 msg
.event_type
= hton32(WLC_E_RESERVED
);
2745 msg
.reason
= 0xFFFFFFFF;
2746 wl_ext_event_send(dhd
->event_params
, &msg
, NULL
);
2750 wl_mesh_set_timer(struct wl_if_info
*mesh_if
, uint timeout
)
2752 AEXT_TRACE(mesh_if
->dev
->name
, "timeout=%d\n", timeout
);
2754 if (timer_pending(&mesh_if
->delay_scan
))
2755 del_timer_sync(&mesh_if
->delay_scan
);
2758 if (timer_pending(&mesh_if
->delay_scan
))
2759 del_timer_sync(&mesh_if
->delay_scan
);
2760 mod_timer(&mesh_if
->delay_scan
, jiffies
+ msecs_to_jiffies(timeout
));
2765 wl_mesh_clear_vndr_ie(struct net_device
*dev
, uchar
*oui
)
2767 char *vndr_ie_buf
= NULL
;
2768 vndr_ie_setbuf_t
*vndr_ie
= NULL
;
2769 ie_getbuf_t vndr_ie_tmp
;
2770 char *iovar_buf
= NULL
;
2772 vndr_ie_buf_t
*vndr_ie_dump
= NULL
;
2774 vndr_ie_info_t
*ie_info
;
2777 vndr_ie_buf
= kzalloc(WLC_IOCTL_SMLEN
, GFP_KERNEL
);
2779 AEXT_ERROR(dev
->name
, "IE memory alloc failed\n");
2784 iovar_buf
= kzalloc(WLC_IOCTL_MEDLEN
, GFP_KERNEL
);
2786 AEXT_ERROR(dev
->name
, "iovar_buf alloc failed\n");
2791 memset(iovar_buf
, 0, WLC_IOCTL_MEDLEN
);
2792 vndr_ie_tmp
.pktflag
= (uint32
) -1;
2793 vndr_ie_tmp
.id
= (uint8
) DOT11_MNG_PROPR_ID
;
2794 err
= wl_ext_iovar_getbuf(dev
, "vndr_ie", &vndr_ie_tmp
, sizeof(vndr_ie_tmp
),
2795 iovar_buf
, WLC_IOCTL_MEDLEN
, NULL
);
2799 vndr_ie_dump
= (vndr_ie_buf_t
*)iovar_buf
;
2800 if (!vndr_ie_dump
->iecount
)
2803 iebuf
= (uchar
*)&vndr_ie_dump
->vndr_ie_list
[0];
2804 for (i
=0; i
<vndr_ie_dump
->iecount
; i
++) {
2805 ie_info
= (vndr_ie_info_t
*) iebuf
;
2806 ie
= &ie_info
->vndr_ie_data
;
2807 if (memcmp(ie
->oui
, oui
, 3))
2808 memset(ie
->oui
, 0, 3);
2809 iebuf
+= sizeof(uint32
) + ie
->len
+ VNDR_IE_HDR_LEN
;
2812 vndr_ie
= (vndr_ie_setbuf_t
*) vndr_ie_buf
;
2813 strncpy(vndr_ie
->cmd
, "del", VNDR_IE_CMD_LEN
- 1);
2814 vndr_ie
->cmd
[VNDR_IE_CMD_LEN
- 1] = '\0';
2815 memcpy(&vndr_ie
->vndr_ie_buffer
, vndr_ie_dump
, WLC_IOCTL_SMLEN
-VNDR_IE_CMD_LEN
-1);
2817 memset(iovar_buf
, 0, WLC_IOCTL_MEDLEN
);
2818 err
= wl_ext_iovar_setbuf(dev
, "vndr_ie", vndr_ie
, WLC_IOCTL_SMLEN
, iovar_buf
,
2819 WLC_IOCTL_MEDLEN
, NULL
);
2832 wl_mesh_clear_mesh_info(struct wl_apsta_params
*apsta_params
,
2833 struct wl_if_info
*mesh_if
, bool scan
)
2835 struct wl_mesh_params
*mesh_info
= &apsta_params
->mesh_info
;
2836 uchar mesh_oui
[]={0x00, 0x22, 0xf4};
2839 AEXT_TRACE(mesh_if
->dev
->name
, "Enter\n");
2841 ret
= wl_mesh_clear_vndr_ie(mesh_if
->dev
, mesh_oui
);
2842 memset(mesh_info
, 0, sizeof(struct wl_mesh_params
));
2844 mesh_info
->scan_channel
= wl_ext_get_chan(apsta_params
, mesh_if
->dev
);
2845 wl_mesh_set_timer(mesh_if
, 100);
2852 wl_mesh_update_vndr_ie(struct wl_apsta_params
*apsta_params
,
2853 struct wl_if_info
*mesh_if
)
2855 struct wl_mesh_params
*mesh_info
= &apsta_params
->mesh_info
;
2857 uchar mesh_oui
[]={0x00, 0x22, 0xf4};
2858 int bytes_written
= 0;
2859 int ret
= 0, i
, vndr_ie_len
;
2862 wl_mesh_clear_vndr_ie(mesh_if
->dev
, mesh_oui
);
2864 vndr_ie_len
= WLC_IOCTL_MEDLEN
;
2865 vndr_ie
= kmalloc(vndr_ie_len
, GFP_KERNEL
);
2866 if (vndr_ie
== NULL
) {
2867 AEXT_ERROR(mesh_if
->dev
->name
, "Failed to allocate buffer of %d bytes\n",
2873 bytes_written
+= snprintf(vndr_ie
+bytes_written
, vndr_ie_len
,
2874 "0x%02x%02x%02x", mesh_oui
[0], mesh_oui
[1], mesh_oui
[2]);
2876 bytes_written
+= snprintf(vndr_ie
+bytes_written
, vndr_ie_len
,
2877 "%02x%02x%02x%02x%02x%02x%02x%02x", MESH_INFO_MASTER_BSSID
, ETHER_ADDR_LEN
,
2878 ((u8
*)(&mesh_info
->master_bssid
))[0], ((u8
*)(&mesh_info
->master_bssid
))[1],
2879 ((u8
*)(&mesh_info
->master_bssid
))[2], ((u8
*)(&mesh_info
->master_bssid
))[3],
2880 ((u8
*)(&mesh_info
->master_bssid
))[4], ((u8
*)(&mesh_info
->master_bssid
))[5]);
2882 bytes_written
+= snprintf(vndr_ie
+bytes_written
, vndr_ie_len
,
2883 "%02x%02x%02x", MESH_INFO_MASTER_CHANNEL
, 1, mesh_info
->master_channel
);
2885 bytes_written
+= snprintf(vndr_ie
+bytes_written
, vndr_ie_len
,
2886 "%02x%02x%02x", MESH_INFO_HOP_CNT
, 1, mesh_info
->hop_cnt
);
2888 bytes_written
+= snprintf(vndr_ie
+bytes_written
, vndr_ie_len
,
2889 "%02x%02x", MESH_INFO_PEER_BSSID
, mesh_info
->hop_cnt
*ETHER_ADDR_LEN
);
2890 for (i
=0; i
<mesh_info
->hop_cnt
&& i
<MAX_HOP_LIST
; i
++) {
2891 peer_bssid
= (uint8
*)&mesh_info
->peer_bssid
[i
];
2892 bytes_written
+= snprintf(vndr_ie
+bytes_written
, vndr_ie_len
,
2893 "%02x%02x%02x%02x%02x%02x",
2894 peer_bssid
[0], peer_bssid
[1], peer_bssid
[2],
2895 peer_bssid
[3], peer_bssid
[4], peer_bssid
[5]);
2898 ret
= wl_ext_add_del_ie(mesh_if
->dev
, VNDR_IE_BEACON_FLAG
|VNDR_IE_PRBRSP_FLAG
,
2901 AEXT_INFO(mesh_if
->dev
->name
, "mbssid=%pM, mchannel=%d, hop=%d, pbssid=%pM\n",
2902 &mesh_info
->master_bssid
, mesh_info
->master_channel
, mesh_info
->hop_cnt
,
2903 mesh_info
->peer_bssid
);
2913 wl_mesh_update_master_info(struct wl_apsta_params
*apsta_params
,
2914 struct wl_if_info
*mesh_if
)
2916 struct wl_mesh_params
*mesh_info
= &apsta_params
->mesh_info
;
2917 struct wl_if_info
*sta_if
= NULL
;
2918 bool updated
= FALSE
;
2920 sta_if
= wl_ext_if_enabled(apsta_params
, ISTA_MODE
);
2922 wldev_ioctl(mesh_if
->dev
, WLC_GET_BSSID
, &mesh_info
->master_bssid
,
2924 mesh_info
->master_channel
= wl_ext_get_chan(apsta_params
, mesh_if
->dev
);
2925 mesh_info
->hop_cnt
= 0;
2926 memset(mesh_info
->peer_bssid
, 0, MAX_HOP_LIST
*ETHER_ADDR_LEN
);
2927 if (!wl_mesh_update_vndr_ie(apsta_params
, mesh_if
))
2935 wl_mesh_update_mesh_info(struct wl_apsta_params
*apsta_params
,
2936 struct wl_if_info
*mesh_if
)
2938 struct wl_mesh_params
*mesh_info
= &apsta_params
->mesh_info
, peer_mesh_info
;
2940 char *dump_buf
= NULL
;
2941 mesh_peer_info_dump_t
*peer_results
;
2942 mesh_peer_info_ext_t
*mpi_ext
;
2943 struct ether_addr bssid
;
2944 bool updated
= FALSE
, bss_found
= FALSE
;
2947 dump_buf
= kmalloc(WLC_IOCTL_MAXLEN
, GFP_KERNEL
);
2948 if (dump_buf
== NULL
) {
2949 AEXT_ERROR(mesh_if
->dev
->name
, "Failed to allocate buffer of %d bytes\n",
2953 count
= wl_mesh_get_peer_results(mesh_if
->dev
, dump_buf
, WLC_IOCTL_MAXLEN
);
2955 memset(&bssid
, 0, ETHER_ADDR_LEN
);
2956 wldev_ioctl(mesh_if
->dev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
, 0);
2957 peer_results
= (mesh_peer_info_dump_t
*)dump_buf
;
2958 mpi_ext
= (mesh_peer_info_ext_t
*)peer_results
->mpi_ext
;
2959 for (count
= 0; count
< peer_results
->count
; count
++) {
2960 if (mpi_ext
->entry_state
!= MESH_SELF_PEER_ENTRY_STATE_TIMEDOUT
&&
2961 mpi_ext
->peer_info
.state
== MESH_PEERING_ESTAB
) {
2962 memset(&peer_mesh_info
, 0, sizeof(struct wl_mesh_params
));
2963 bss_found
= wl_escan_mesh_info(mesh_if
->dev
, mesh_if
->escan
,
2964 &mpi_ext
->ea
, &peer_mesh_info
);
2965 if (bss_found
&& (mesh_info
->master_channel
== 0 ||
2966 peer_mesh_info
.hop_cnt
<= mesh_info
->hop_cnt
) &&
2967 memcmp(&peer_mesh_info
.peer_bssid
, &bssid
, ETHER_ADDR_LEN
)) {
2968 memcpy(&mesh_info
->master_bssid
, &peer_mesh_info
.master_bssid
,
2970 mesh_info
->master_channel
= peer_mesh_info
.master_channel
;
2971 mesh_info
->hop_cnt
= peer_mesh_info
.hop_cnt
+1;
2972 memset(mesh_info
->peer_bssid
, 0, MAX_HOP_LIST
*ETHER_ADDR_LEN
);
2973 memcpy(&mesh_info
->peer_bssid
, &mpi_ext
->ea
, ETHER_ADDR_LEN
);
2974 memcpy(&mesh_info
->peer_bssid
[1], peer_mesh_info
.peer_bssid
,
2975 (MAX_HOP_LIST
-1)*ETHER_ADDR_LEN
);
2982 if (wl_mesh_update_vndr_ie(apsta_params
, mesh_if
)) {
2983 AEXT_ERROR(mesh_if
->dev
->name
, "update failed\n");
2984 mesh_info
->master_channel
= 0;
2991 if (!mesh_info
->master_channel
) {
2992 wlc_ssid_t cur_ssid
;
2995 memset(&peer_mesh_info
, 0, sizeof(struct wl_mesh_params
));
2996 wl_ext_ioctl(mesh_if
->dev
, WLC_GET_SSID
, &cur_ssid
, sizeof(cur_ssid
), 0);
2997 wl_ext_get_sec(mesh_if
->dev
, mesh_if
->ifmode
, sec
, sizeof(sec
));
2998 if (strnicmp(sec
, "sae/sae", strlen("sae/sae")) == 0)
3000 cur_chan
= wl_ext_get_chan(apsta_params
, mesh_if
->dev
);
3001 bss_found
= wl_escan_mesh_peer(mesh_if
->dev
, mesh_if
->escan
, &cur_ssid
, cur_chan
,
3002 sae
, &peer_mesh_info
);
3004 if (bss_found
&& peer_mesh_info
.master_channel
&&
3005 (cur_chan
!= peer_mesh_info
.master_channel
)) {
3006 WL_MSG(mesh_if
->ifname
, "moving channel %d -> %d\n",
3007 cur_chan
, peer_mesh_info
.master_channel
);
3008 wl_ext_disable_iface(mesh_if
->dev
, mesh_if
->ifname
);
3009 mesh_if
->channel
= peer_mesh_info
.master_channel
;
3010 wl_ext_enable_iface(mesh_if
->dev
, mesh_if
->ifname
, 500);
3021 wl_mesh_event_handler( struct wl_apsta_params
*apsta_params
,
3022 struct wl_if_info
*mesh_if
, const wl_event_msg_t
*e
, void *data
)
3024 struct wl_mesh_params
*mesh_info
= &apsta_params
->mesh_info
;
3025 uint32 event_type
= ntoh32(e
->event_type
);
3026 uint32 status
= ntoh32(e
->status
);
3027 uint32 reason
= ntoh32(e
->reason
);
3031 if (wl_get_isam_status(mesh_if
, AP_CREATED
) &&
3032 ((event_type
== WLC_E_SET_SSID
&& status
== WLC_E_STATUS_SUCCESS
) ||
3033 (event_type
== WLC_E_LINK
&& status
== WLC_E_STATUS_SUCCESS
&&
3034 reason
== WLC_E_REASON_INITIAL_ASSOC
))) {
3035 if (!wl_mesh_update_master_info(apsta_params
, mesh_if
)) {
3036 mesh_info
->scan_channel
= wl_ext_get_chan(apsta_params
, mesh_if
->dev
);
3037 wl_mesh_set_timer(mesh_if
, WL_MESH_DELAY_SCAN_MS
);
3040 else if ((event_type
== WLC_E_LINK
&& reason
== WLC_E_LINK_BSSCFG_DIS
) ||
3041 (event_type
== WLC_E_LINK
&& status
== WLC_E_STATUS_SUCCESS
&&
3042 reason
== WLC_E_REASON_DEAUTH
)) {
3043 wl_mesh_clear_mesh_info(apsta_params
, mesh_if
, FALSE
);
3045 else if (wl_get_isam_status(mesh_if
, AP_CREATED
) &&
3046 (event_type
== WLC_E_ASSOC_IND
|| event_type
== WLC_E_REASSOC_IND
) &&
3047 reason
== DOT11_SC_SUCCESS
) {
3048 mesh_info
->scan_channel
= wl_ext_get_chan(apsta_params
, mesh_if
->dev
);
3049 wl_mesh_set_timer(mesh_if
, 100);
3051 else if (event_type
== WLC_E_DISASSOC_IND
|| event_type
== WLC_E_DEAUTH_IND
||
3052 (event_type
== WLC_E_DEAUTH
&& reason
!= DOT11_RC_RESERVED
)) {
3053 if (!memcmp(&mesh_info
->peer_bssid
, &e
->addr
, ETHER_ADDR_LEN
))
3054 wl_mesh_clear_mesh_info(apsta_params
, mesh_if
, TRUE
);
3056 else if (wl_get_isam_status(mesh_if
, AP_CREATED
) &&
3057 event_type
== WLC_E_RESERVED
&& reason
== 0xFFFFFFFF) {
3058 if (!wl_mesh_update_master_info(apsta_params
, mesh_if
)) {
3059 wl_ext_ioctl(mesh_if
->dev
, WLC_GET_SSID
, &ssid
, sizeof(ssid
), 0);
3060 ret
= wl_escan_set_scan(mesh_if
->dev
, apsta_params
->dhd
, &ssid
,
3061 mesh_info
->scan_channel
, FALSE
);
3063 wl_mesh_set_timer(mesh_if
, WL_MESH_DELAY_SCAN_MS
);
3066 else if (wl_get_isam_status(mesh_if
, AP_CREATED
) &&
3067 ((event_type
== WLC_E_ESCAN_RESULT
&& status
== WLC_E_STATUS_SUCCESS
) ||
3068 (event_type
== WLC_E_ESCAN_RESULT
&&
3069 (status
== WLC_E_STATUS_ABORT
|| status
== WLC_E_STATUS_NEWSCAN
||
3070 status
== WLC_E_STATUS_11HQUIET
|| status
== WLC_E_STATUS_CS_ABORT
||
3071 status
== WLC_E_STATUS_NEWASSOC
|| status
== WLC_E_STATUS_TIMEOUT
)))) {
3072 if (!wl_mesh_update_master_info(apsta_params
, mesh_if
)) {
3073 if (!wl_mesh_update_mesh_info(apsta_params
, mesh_if
)) {
3074 mesh_info
->scan_channel
= 0;
3075 wl_mesh_set_timer(mesh_if
, WL_MESH_DELAY_SCAN_MS
);
3082 wl_mesh_escan_detach(dhd_pub_t
*dhd
, struct wl_if_info
*mesh_if
)
3084 AEXT_TRACE(mesh_if
->dev
->name
, "Enter\n");
3086 del_timer_sync(&mesh_if
->delay_scan
);
3088 if (mesh_if
->escan
) {
3089 mesh_if
->escan
= NULL
;
3094 wl_mesh_escan_attach(dhd_pub_t
*dhd
, struct wl_if_info
*mesh_if
)
3096 AEXT_TRACE(mesh_if
->dev
->name
, "Enter\n");
3098 mesh_if
->escan
= dhd
->escan
;
3099 init_timer_compat(&mesh_if
->delay_scan
, wl_mesh_timer
, mesh_if
);
3105 wl_mesh_update_peer_path(struct wl_if_info
*mesh_if
, char *command
,
3108 struct wl_mesh_params peer_mesh_info
;
3110 char *dump_buf
= NULL
;
3111 mesh_peer_info_dump_t
*peer_results
;
3112 mesh_peer_info_ext_t
*mpi_ext
;
3113 int bytes_written
= 0, j
, k
;
3114 bool bss_found
= FALSE
;
3116 dump_buf
= kmalloc(WLC_IOCTL_MAXLEN
, GFP_KERNEL
);
3117 if (dump_buf
== NULL
) {
3118 AEXT_ERROR(mesh_if
->dev
->name
, "Failed to allocate buffer of %d bytes\n",
3122 count
= wl_mesh_get_peer_results(mesh_if
->dev
, dump_buf
, WLC_IOCTL_MAXLEN
);
3124 peer_results
= (mesh_peer_info_dump_t
*)dump_buf
;
3125 mpi_ext
= (mesh_peer_info_ext_t
*)peer_results
->mpi_ext
;
3126 for (count
= 0; count
< peer_results
->count
; count
++) {
3127 if (mpi_ext
->entry_state
!= MESH_SELF_PEER_ENTRY_STATE_TIMEDOUT
&&
3128 mpi_ext
->peer_info
.state
== MESH_PEERING_ESTAB
) {
3129 memset(&peer_mesh_info
, 0, sizeof(struct wl_mesh_params
));
3130 bss_found
= wl_escan_mesh_info(mesh_if
->dev
, mesh_if
->escan
,
3131 &mpi_ext
->ea
, &peer_mesh_info
);
3133 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
3134 "\npeer=%pM, hop=%d",
3135 &mpi_ext
->ea
, peer_mesh_info
.hop_cnt
);
3136 for (j
=1; j
<peer_mesh_info
.hop_cnt
; j
++) {
3137 bytes_written
+= snprintf(command
+bytes_written
,
3139 for (k
=0; k
<j
; k
++) {
3140 bytes_written
+= snprintf(command
+bytes_written
,
3143 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
3144 "%pM", &peer_mesh_info
.peer_bssid
[j
]);
3154 return bytes_written
;
3158 wl_ext_isam_peer_path(struct net_device
*dev
, char *command
, int total_len
)
3160 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
3161 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
3162 struct wl_mesh_params
*mesh_info
= &apsta_params
->mesh_info
;
3163 struct wl_if_info
*tmp_if
;
3165 char *dump_buf
= NULL
;
3166 int dump_len
= WLC_IOCTL_MEDLEN
;
3167 int dump_written
= 0;
3170 if (command
|| android_msg_level
& ANDROID_INFO_LEVEL
) {
3173 dump_len
= total_len
;
3175 dump_buf
= kmalloc(dump_len
, GFP_KERNEL
);
3176 if (dump_buf
== NULL
) {
3177 AEXT_ERROR(dev
->name
, "Failed to allocate buffer of %d bytes\n",
3182 for (i
=0; i
<MAX_IF_NUM
; i
++) {
3183 tmp_if
= &apsta_params
->if_info
[i
];
3184 if (tmp_if
->dev
&& tmp_if
->ifmode
== IMESH_MODE
&& apsta_params
->macs
) {
3185 chan
= wl_ext_get_chan(apsta_params
, tmp_if
->dev
);
3187 dump_written
+= snprintf(dump_buf
+dump_written
, dump_len
,
3188 "[dhd-%s-%c] mbssid=%pM, mchan=%d, hop=%d, pbssid=%pM",
3189 tmp_if
->ifname
, tmp_if
->prefix
, &mesh_info
->master_bssid
,
3190 mesh_info
->master_channel
, mesh_info
->hop_cnt
,
3191 &mesh_info
->peer_bssid
);
3192 dump_written
+= wl_mesh_update_peer_path(tmp_if
,
3193 dump_buf
+dump_written
, dump_len
-dump_written
);
3197 AEXT_INFO(dev
->name
, "%s\n", dump_buf
);
3200 if (!command
&& dump_buf
)
3202 return dump_written
;
3204 #endif /* WL_ESCAN */
3208 wl_ext_isam_status(struct net_device
*dev
, char *command
, int total_len
)
3210 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
3211 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
3213 struct wl_if_info
*tmp_if
;
3215 wlc_ssid_t ssid
= { 0, {0} };
3216 struct ether_addr bssid
;
3220 char *dump_buf
= NULL
;
3221 int dump_len
= WLC_IOCTL_MEDLEN
;
3222 int dump_written
= 0;
3224 if (command
|| android_msg_level
& ANDROID_INFO_LEVEL
) {
3227 dump_len
= total_len
;
3229 dump_buf
= kmalloc(dump_len
, GFP_KERNEL
);
3230 if (dump_buf
== NULL
) {
3231 AEXT_ERROR(dev
->name
, "Failed to allocate buffer of %d bytes\n",
3236 dump_written
+= snprintf(dump_buf
+dump_written
, dump_len
,
3237 "apstamode=%d", apsta_params
->apstamode
);
3238 for (i
=0; i
<MAX_IF_NUM
; i
++) {
3239 memset(&ssid
, 0, sizeof(ssid
));
3240 memset(&bssid
, 0, sizeof(bssid
));
3241 memset(&scb_val
, 0, sizeof(scb_val
));
3242 tmp_if
= &apsta_params
->if_info
[i
];
3244 chan
= wl_ext_get_chan(apsta_params
, tmp_if
->dev
);
3246 wl_ext_ioctl(tmp_if
->dev
, WLC_GET_SSID
, &ssid
, sizeof(ssid
), 0);
3247 wldev_ioctl(tmp_if
->dev
, WLC_GET_BSSID
, &bssid
, sizeof(bssid
), 0);
3248 wldev_ioctl(tmp_if
->dev
, WLC_GET_RSSI
, &scb_val
,
3249 sizeof(scb_val_t
), 0);
3250 chanspec
= wl_ext_get_chanspec(apsta_params
, tmp_if
->dev
);
3251 wl_ext_get_sec(tmp_if
->dev
, tmp_if
->ifmode
, sec
, sizeof(sec
));
3252 dump_written
+= snprintf(dump_buf
+dump_written
, dump_len
,
3253 "\n[dhd-%s-%c]: bssid=%pM, chan=%3d(0x%x %sMHz), "
3254 "rssi=%3d, sec=%-15s, SSID=\"%s\"",
3255 tmp_if
->ifname
, tmp_if
->prefix
, &bssid
, chan
, chanspec
,
3256 CHSPEC_IS20(chanspec
)?"20":
3257 CHSPEC_IS40(chanspec
)?"40":
3258 CHSPEC_IS80(chanspec
)?"80":"160",
3259 dtoh32(scb_val
.val
), sec
, ssid
.SSID
);
3260 if (tmp_if
->ifmode
== IAP_MODE
) {
3261 dump_written
+= snprintf(dump_buf
+dump_written
, dump_len
, "\n");
3262 dump_written
+= wl_ext_assoclist(tmp_if
->dev
, NULL
,
3263 dump_buf
+dump_written
, dump_len
-dump_written
);
3266 else if (tmp_if
->ifmode
== IMESH_MODE
) {
3267 dump_written
+= snprintf(dump_buf
+dump_written
, dump_len
, "\n");
3268 dump_written
+= wl_ext_mesh_peer_status(tmp_if
->dev
, NULL
,
3269 dump_buf
+dump_written
, dump_len
-dump_written
);
3273 dump_written
+= snprintf(dump_buf
+dump_written
, dump_len
,
3274 "\n[dhd-%s-%c]:", tmp_if
->ifname
, tmp_if
->prefix
);
3278 AEXT_INFO(dev
->name
, "%s\n", dump_buf
);
3281 if (!command
&& dump_buf
)
3283 return dump_written
;
3287 wl_ext_master_if(struct wl_if_info
*cur_if
)
3289 if (cur_if
->ifmode
== IAP_MODE
|| cur_if
->ifmode
== IMESH_MODE
)
3296 wl_ext_if_down(struct wl_apsta_params
*apsta_params
, struct wl_if_info
*cur_if
)
3298 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
3304 apstamode_t apstamode
= apsta_params
->apstamode
;
3306 WL_MSG(cur_if
->ifname
, "[%c] Turning off...\n", cur_if
->prefix
);
3308 if (cur_if
->ifmode
== ISTA_MODE
) {
3309 wl_ext_ioctl(cur_if
->dev
, WLC_DISASSOC
, NULL
, 0, 1);
3310 } else if (cur_if
->ifmode
== IAP_MODE
|| cur_if
->ifmode
== IMESH_MODE
) {
3311 // deauthenticate all STA first
3312 memcpy(scbval
.ea
.octet
, ðer_bcast
, ETHER_ADDR_LEN
);
3313 wl_ext_ioctl(cur_if
->dev
, WLC_SCB_DEAUTHENTICATE
, &scbval
.ea
, ETHER_ADDR_LEN
, 1);
3316 if (apstamode
== IAPONLY_MODE
|| apstamode
== IMESHONLY_MODE
) {
3317 wl_ext_ioctl(cur_if
->dev
, WLC_DOWN
, NULL
, 0, 1);
3319 bss_setbuf
.cfg
= 0xffffffff;
3320 bss_setbuf
.val
= htod32(0);
3321 wl_ext_iovar_setbuf(cur_if
->dev
, "bss", &bss_setbuf
, sizeof(bss_setbuf
),
3322 iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
3324 wl_clr_isam_status(cur_if
, AP_CREATED
);
3330 wl_ext_if_up(struct wl_apsta_params
*apsta_params
, struct wl_if_info
*cur_if
)
3332 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
3337 apstamode_t apstamode
= apsta_params
->apstamode
;
3338 chanspec_t fw_chspec
;
3340 wlc_ssid_t ssid
= { 0, {0} };
3343 if (cur_if
->ifmode
!= IAP_MODE
) {
3344 AEXT_ERROR(cur_if
->ifname
, "Wrong ifmode\n");
3348 if (wl_ext_dfs_chan(cur_if
->channel
) && !apsta_params
->radar
) {
3349 WL_MSG(cur_if
->ifname
, "[%c] skip DFS channel %d\n",
3350 cur_if
->prefix
, cur_if
->channel
);
3352 } else if (!cur_if
->channel
) {
3353 WL_MSG(cur_if
->ifname
, "[%c] no valid channel\n", cur_if
->prefix
);
3357 WL_MSG(cur_if
->ifname
, "[%c] Turning on...\n", cur_if
->prefix
);
3359 wl_ext_set_chanspec(cur_if
->dev
, apsta_params
->ioctl_ver
, cur_if
->channel
,
3362 wl_clr_isam_status(cur_if
, AP_CREATED
);
3363 wl_set_isam_status(cur_if
, AP_CREATING
);
3364 if (apstamode
== IAPONLY_MODE
) {
3365 wl_ext_ioctl(cur_if
->dev
, WLC_UP
, NULL
, 0, 1);
3367 bss_setbuf
.cfg
= 0xffffffff;
3368 bss_setbuf
.val
= htod32(1);
3369 wl_ext_iovar_setbuf(cur_if
->dev
, "bss", &bss_setbuf
,
3370 sizeof(bss_setbuf
), iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
3373 timeout
= wait_event_interruptible_timeout(apsta_params
->netif_change_event
,
3374 wl_get_isam_status(cur_if
, AP_CREATED
),
3375 msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME
));
3376 if (timeout
<= 0 || !wl_get_isam_status(cur_if
, AP_CREATED
)) {
3377 wl_ext_if_down(apsta_params
, cur_if
);
3378 WL_MSG(cur_if
->ifname
, "[%c] failed to up with SSID: \"%s\"\n",
3379 cur_if
->prefix
, cur_if
->ssid
);
3381 wl_ext_ioctl(cur_if
->dev
, WLC_GET_SSID
, &ssid
, sizeof(ssid
), 0);
3382 chan
= wl_ext_get_chan(apsta_params
, cur_if
->dev
);
3383 WL_MSG(cur_if
->ifname
, "[%c] enabled with SSID: \"%s\" on channel %d\n",
3384 cur_if
->prefix
, ssid
.SSID
, chan
);
3386 wl_clr_isam_status(cur_if
, AP_CREATING
);
3388 wl_ext_isam_status(cur_if
->dev
, NULL
, 0);
3394 wl_ext_disable_iface(struct net_device
*dev
, char *ifname
)
3396 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
3398 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
3399 wlc_ssid_t ssid
= { 0, {0} };
3405 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
3406 apstamode_t apstamode
= apsta_params
->apstamode
;
3407 struct wl_if_info
*cur_if
= NULL
, *tmp_if
= NULL
;
3409 for (i
=0; i
<MAX_IF_NUM
; i
++) {
3410 tmp_if
= &apsta_params
->if_info
[i
];
3411 if (tmp_if
->dev
&& !strcmp(tmp_if
->dev
->name
, ifname
)) {
3417 AEXT_ERROR(dev
->name
, "wrong ifname=%s or dev not ready\n", ifname
);
3421 mutex_lock(&apsta_params
->usr_sync
);
3422 WL_MSG(ifname
, "[%c] Disabling...\n", cur_if
->prefix
);
3424 if (cur_if
->ifmode
== ISTA_MODE
) {
3425 wl_ext_ioctl(cur_if
->dev
, WLC_DISASSOC
, NULL
, 0, 1);
3426 wl_ext_add_remove_pm_enable_work(dev
, FALSE
);
3427 } else if (cur_if
->ifmode
== IAP_MODE
|| cur_if
->ifmode
== IMESH_MODE
) {
3428 // deauthenticate all STA first
3429 memcpy(scbval
.ea
.octet
, ðer_bcast
, ETHER_ADDR_LEN
);
3430 wl_ext_ioctl(cur_if
->dev
, WLC_SCB_DEAUTHENTICATE
, &scbval
.ea
, ETHER_ADDR_LEN
, 1);
3433 if (apstamode
== IAPONLY_MODE
|| apstamode
== IMESHONLY_MODE
) {
3434 wl_ext_ioctl(dev
, WLC_DOWN
, NULL
, 0, 1);
3435 wl_ext_ioctl(dev
, WLC_SET_SSID
, &ssid
, sizeof(ssid
), 1); // reset ssid
3436 wl_ext_iovar_setint(dev
, "mpc", 1);
3437 } else if ((apstamode
==ISTAAP_MODE
|| apstamode
==ISTAGO_MODE
) &&
3438 cur_if
->ifmode
== IAP_MODE
) {
3439 bss_setbuf
.cfg
= 0xffffffff;
3440 bss_setbuf
.val
= htod32(0);
3441 wl_ext_iovar_setbuf(cur_if
->dev
, "bss", &bss_setbuf
, sizeof(bss_setbuf
),
3442 iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
3443 wl_ext_iovar_setint(dev
, "mpc", 1);
3444 #ifdef ARP_OFFLOAD_SUPPORT
3445 /* IF SoftAP is disabled, enable arpoe back for STA mode. */
3446 dhd_arp_offload_set(dhd
, dhd_arp_mode
);
3447 dhd_arp_offload_enable(dhd
, TRUE
);
3448 #endif /* ARP_OFFLOAD_SUPPORT */
3449 #ifdef PROP_TXSTATUS_VSDB
3450 #if defined(BCMSDIO)
3451 if (dhd
->conf
->disable_proptx
!=0) {
3453 dhd_wlfc_get_enable(dhd
, &enabled
);
3455 dhd_wlfc_deinit(dhd
);
3458 #endif /* BCMSDIO */
3459 #endif /* PROP_TXSTATUS_VSDB */
3461 else if (apstamode
== IDUALAP_MODE
|| apstamode
== ISTAAPAP_MODE
) {
3462 bss_setbuf
.cfg
= 0xffffffff;
3463 bss_setbuf
.val
= htod32(0);
3464 wl_ext_iovar_setbuf(cur_if
->dev
, "bss", &bss_setbuf
, sizeof(bss_setbuf
),
3465 iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
3467 } else if (apstamode
== ISTAMESH_MODE
|| apstamode
== IMESHAP_MODE
||
3468 apstamode
== ISTAAPMESH_MODE
|| apstamode
== IMESHAPAP_MODE
) {
3469 bss_setbuf
.cfg
= 0xffffffff;
3470 bss_setbuf
.val
= htod32(0);
3471 wl_ext_iovar_setbuf(cur_if
->dev
, "bss", &bss_setbuf
, sizeof(bss_setbuf
),
3472 iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
3473 if (cur_if
->ifmode
== IMESH_MODE
) {
3474 int scan_assoc_time
= DHD_SCAN_ASSOC_ACTIVE_TIME
;
3475 for (i
=0; i
<MAX_IF_NUM
; i
++) {
3476 tmp_if
= &apsta_params
->if_info
[i
];
3477 if (tmp_if
->dev
&& tmp_if
->ifmode
== ISTA_MODE
) {
3478 wl_ext_ioctl(tmp_if
->dev
, WLC_SET_SCAN_CHANNEL_TIME
,
3479 &scan_assoc_time
, sizeof(scan_assoc_time
), 1);
3486 wl_clr_isam_status(cur_if
, AP_CREATED
);
3488 WL_MSG(ifname
, "[%c] Exit\n", cur_if
->prefix
);
3489 mutex_unlock(&apsta_params
->usr_sync
);
3494 wl_ext_iapsta_disable(struct net_device
*dev
, char *command
, int total_len
)
3497 char *pch
, *pick_tmp
, *param
;
3498 char ifname
[IFNAMSIZ
+1];
3500 AEXT_TRACE(dev
->name
, "command=%s, len=%d\n", command
, total_len
);
3503 param
= bcmstrtok(&pick_tmp
, " ", 0); // skip iapsta_disable
3504 param
= bcmstrtok(&pick_tmp
, " ", 0);
3505 while (param
!= NULL
) {
3506 if (!strcmp(param
, "ifname")) {
3507 pch
= bcmstrtok(&pick_tmp
, " ", 0);
3509 strcpy(ifname
, pch
);
3510 ret
= wl_ext_disable_iface(dev
, ifname
);
3515 AEXT_ERROR(dev
->name
, "ifname [wlanX]\n");
3519 param
= bcmstrtok(&pick_tmp
, " ", 0);
3526 wl_ext_diff_band(uint16 chan1
, uint16 chan2
)
3528 if ((chan1
<= CH_MAX_2G_CHANNEL
&& chan2
> CH_MAX_2G_CHANNEL
) ||
3529 (chan1
> CH_MAX_2G_CHANNEL
&& chan2
<= CH_MAX_2G_CHANNEL
)) {
3536 wl_ext_same_band(struct wl_apsta_params
*apsta_params
,
3537 struct wl_if_info
*cur_if
, bool nodfs
)
3539 struct wl_if_info
*tmp_if
;
3540 uint16 tmp_chan
, target_chan
= 0;
3544 // find the max prio
3545 max_prio
= cur_if
->prio
;
3546 for (i
=0; i
<MAX_IF_NUM
; i
++) {
3547 tmp_if
= &apsta_params
->if_info
[i
];
3548 if (cur_if
!= tmp_if
&& wl_get_isam_status(tmp_if
, IF_READY
) &&
3549 tmp_if
->prio
> max_prio
) {
3550 tmp_chan
= wl_ext_get_chan(apsta_params
, tmp_if
->dev
);
3551 if (wl_ext_dfs_chan(tmp_chan
) && nodfs
)
3553 if (tmp_chan
&& !wl_ext_diff_band(cur_if
->channel
, tmp_chan
)) {
3554 target_chan
= tmp_chan
;
3555 max_prio
= tmp_if
->prio
;
3564 wl_ext_get_vsdb_chan(struct wl_apsta_params
*apsta_params
,
3565 struct wl_if_info
*cur_if
, struct wl_if_info
*target_if
)
3567 uint16 target_chan
= 0, cur_chan
= cur_if
->channel
;
3569 target_chan
= wl_ext_get_chan(apsta_params
, target_if
->dev
);
3571 AEXT_INFO(cur_if
->ifname
, "cur_chan=%d, target_chan=%d\n",
3572 cur_chan
, target_chan
);
3573 if (wl_ext_diff_band(cur_chan
, target_chan
)) {
3574 if (!apsta_params
->rsdb
)
3577 if (cur_chan
!= target_chan
)
3586 wl_ext_rsdb_core_conflict(struct wl_apsta_params
*apsta_params
,
3587 struct wl_if_info
*cur_if
)
3589 struct wl_if_info
*tmp_if
;
3590 uint16 cur_chan
, tmp_chan
;
3593 if (apsta_params
->rsdb
) {
3594 cur_chan
= wl_ext_get_chan(apsta_params
, cur_if
->dev
);
3595 for (i
=0; i
<MAX_IF_NUM
; i
++) {
3596 tmp_if
= &apsta_params
->if_info
[i
];
3597 if (tmp_if
!= cur_if
&& wl_get_isam_status(tmp_if
, IF_READY
) &&
3598 tmp_if
->prio
> cur_if
->prio
) {
3599 tmp_chan
= wl_ext_get_chan(apsta_params
, tmp_if
->dev
);
3602 if (wl_ext_diff_band(cur_chan
, tmp_chan
) &&
3603 wl_ext_diff_band(cur_chan
, cur_if
->channel
))
3605 else if (!wl_ext_diff_band(cur_chan
, tmp_chan
) &&
3606 wl_ext_diff_band(cur_chan
, cur_if
->channel
))
3615 wl_ext_trigger_csa(struct wl_apsta_params
*apsta_params
, struct wl_if_info
*cur_if
)
3617 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
3618 bool core_conflict
= FALSE
;
3620 if (wl_ext_master_if(cur_if
) && (apsta_params
->csa
& CSA_DRV_BIT
)) {
3621 if (!cur_if
->channel
) {
3622 WL_MSG(cur_if
->ifname
, "[%c] no valid channel\n", cur_if
->prefix
);
3623 } else if (wl_ext_dfs_chan(cur_if
->channel
) && !apsta_params
->radar
) {
3624 WL_MSG(cur_if
->ifname
, "[%c] skip DFS channel %d\n",
3625 cur_if
->prefix
, cur_if
->channel
);
3626 wl_ext_if_down(apsta_params
, cur_if
);
3628 wl_chan_switch_t csa_arg
;
3629 memset(&csa_arg
, 0, sizeof(csa_arg
));
3632 csa_arg
.chspec
= wl_ext_chan_to_chanspec(apsta_params
, cur_if
->dev
,
3634 core_conflict
= wl_ext_rsdb_core_conflict(apsta_params
, cur_if
);
3635 if (core_conflict
) {
3636 WL_MSG(cur_if
->ifname
, "[%c] Skip CSA due to rsdb core conflict\n",
3638 } else if (csa_arg
.chspec
) {
3639 WL_MSG(cur_if
->ifname
, "[%c] Trigger CSA to channel %d(0x%x)\n",
3640 cur_if
->prefix
, cur_if
->channel
, csa_arg
.chspec
);
3641 wl_set_isam_status(cur_if
, AP_CREATING
);
3642 wl_ext_iovar_setbuf(cur_if
->dev
, "csa", &csa_arg
, sizeof(csa_arg
),
3643 iovar_buf
, sizeof(iovar_buf
), NULL
);
3645 wl_clr_isam_status(cur_if
, AP_CREATING
);
3646 wl_ext_isam_status(cur_if
->dev
, NULL
, 0);
3648 AEXT_ERROR(cur_if
->ifname
, "fail to get chanspec\n");
3657 wl_ext_move_cur_dfs_channel(struct wl_apsta_params
*apsta_params
,
3658 struct wl_if_info
*cur_if
)
3660 uint16 other_chan
= 0, cur_chan
= cur_if
->channel
;
3661 uint16 chan_2g
= 0, chan_5g
= 0;
3662 uint32 auto_band
= WLC_BAND_2G
;
3664 if (wl_ext_master_if(cur_if
) && wl_ext_dfs_chan(cur_if
->channel
) &&
3665 !apsta_params
->radar
) {
3667 wl_ext_get_default_chan(cur_if
->dev
, &chan_2g
, &chan_5g
, TRUE
);
3668 if (!chan_2g
&& !chan_5g
) {
3669 cur_if
->channel
= 0;
3670 WL_MSG(cur_if
->ifname
, "[%c] no valid channel\n", cur_if
->prefix
);
3674 if (apsta_params
->vsdb
) {
3676 cur_if
->channel
= chan_5g
;
3677 auto_band
= WLC_BAND_5G
;
3678 other_chan
= wl_ext_same_band(apsta_params
, cur_if
, TRUE
);
3680 cur_if
->channel
= chan_2g
;
3681 auto_band
= WLC_BAND_2G
;
3682 other_chan
= wl_ext_same_band(apsta_params
, cur_if
, TRUE
);
3685 other_chan
= wl_ext_autochannel(cur_if
->dev
, ACS_FW_BIT
|ACS_DRV_BIT
,
3689 cur_if
->channel
= other_chan
;
3690 } else if (apsta_params
->rsdb
) {
3692 cur_if
->channel
= chan_5g
;
3693 auto_band
= WLC_BAND_5G
;
3694 other_chan
= wl_ext_same_band(apsta_params
, cur_if
, FALSE
);
3695 if (wl_ext_dfs_chan(other_chan
) && chan_2g
) {
3696 cur_if
->channel
= chan_2g
;
3697 auto_band
= WLC_BAND_2G
;
3698 other_chan
= wl_ext_same_band(apsta_params
, cur_if
, TRUE
);
3701 cur_if
->channel
= chan_2g
;
3702 auto_band
= WLC_BAND_2G
;
3703 other_chan
= wl_ext_same_band(apsta_params
, cur_if
, TRUE
);
3706 other_chan
= wl_ext_autochannel(cur_if
->dev
, ACS_FW_BIT
|ACS_DRV_BIT
,
3710 cur_if
->channel
= other_chan
;
3712 cur_if
->channel
= chan_5g
;
3713 auto_band
= WLC_BAND_5G
;
3714 other_chan
= wl_ext_same_band(apsta_params
, cur_if
, FALSE
);
3715 if (wl_ext_dfs_chan(other_chan
)) {
3716 cur_if
->channel
= 0;
3718 else if (!other_chan
) {
3719 other_chan
= wl_ext_autochannel(cur_if
->dev
, ACS_FW_BIT
|ACS_DRV_BIT
,
3723 cur_if
->channel
= other_chan
;
3725 WL_MSG(cur_if
->ifname
, "[%c] move channel %d => %d\n",
3726 cur_if
->prefix
, cur_chan
, cur_if
->channel
);
3731 wl_ext_move_other_dfs_channel(struct wl_apsta_params
*apsta_params
,
3732 struct wl_if_info
*cur_if
)
3734 uint16 other_chan
= 0, cur_chan
= cur_if
->channel
;
3735 uint16 chan_2g
= 0, chan_5g
= 0;
3736 uint32 auto_band
= WLC_BAND_2G
;
3738 if (wl_ext_master_if(cur_if
) && wl_ext_dfs_chan(cur_if
->channel
) &&
3739 !apsta_params
->radar
) {
3741 wl_ext_get_default_chan(cur_if
->dev
, &chan_2g
, &chan_5g
, TRUE
);
3742 if (!chan_2g
&& !chan_5g
) {
3743 cur_if
->channel
= 0;
3744 WL_MSG(cur_if
->ifname
, "[%c] no valid channel\n", cur_if
->prefix
);
3748 if (apsta_params
->vsdb
) {
3750 cur_if
->channel
= chan_5g
;
3751 auto_band
= WLC_BAND_5G
;
3752 other_chan
= wl_ext_same_band(apsta_params
, cur_if
, TRUE
);
3754 cur_if
->channel
= chan_2g
;
3755 auto_band
= WLC_BAND_2G
;
3756 other_chan
= wl_ext_same_band(apsta_params
, cur_if
, TRUE
);
3759 other_chan
= wl_ext_autochannel(cur_if
->dev
, ACS_FW_BIT
|ACS_DRV_BIT
,
3763 cur_if
->channel
= other_chan
;
3764 } else if (apsta_params
->rsdb
) {
3766 cur_if
->channel
= chan_2g
;
3767 auto_band
= WLC_BAND_2G
;
3768 other_chan
= wl_ext_same_band(apsta_params
, cur_if
, TRUE
);
3770 other_chan
= wl_ext_autochannel(cur_if
->dev
, ACS_FW_BIT
|ACS_DRV_BIT
,
3774 cur_if
->channel
= 0;
3777 cur_if
->channel
= other_chan
;
3779 cur_if
->channel
= 0;
3781 WL_MSG(cur_if
->ifname
, "[%c] move channel %d => %d\n",
3782 cur_if
->prefix
, cur_chan
, cur_if
->channel
);
3787 wl_ext_move_cur_channel(struct wl_apsta_params
*apsta_params
,
3788 struct wl_if_info
*cur_if
)
3790 struct wl_if_info
*tmp_if
, *target_if
= NULL
;
3791 uint16 tmp_chan
, target_chan
= 0;
3795 if (apsta_params
->vsdb
) {
3796 target_chan
= cur_if
->channel
;
3800 // find the max prio
3801 max_prio
= cur_if
->prio
;
3802 for (i
=0; i
<MAX_IF_NUM
; i
++) {
3803 tmp_if
= &apsta_params
->if_info
[i
];
3804 if (cur_if
!= tmp_if
&& wl_get_isam_status(tmp_if
, IF_READY
) &&
3805 tmp_if
->prio
> max_prio
) {
3806 tmp_chan
= wl_ext_get_vsdb_chan(apsta_params
, cur_if
, tmp_if
);
3809 target_chan
= tmp_chan
;
3810 max_prio
= tmp_if
->prio
;
3816 tmp_chan
= wl_ext_get_chan(apsta_params
, cur_if
->dev
);
3817 if (apsta_params
->rsdb
&& tmp_chan
&&
3818 wl_ext_diff_band(tmp_chan
, target_chan
)) {
3819 WL_MSG(cur_if
->ifname
, "[%c] keep on current channel %d\n",
3820 cur_if
->prefix
, tmp_chan
);
3821 cur_if
->channel
= 0;
3823 WL_MSG(cur_if
->ifname
, "[%c] channel=%d => %s[%c] channel=%d\n",
3824 cur_if
->prefix
, cur_if
->channel
,
3825 target_if
->ifname
, target_if
->prefix
, target_chan
);
3826 cur_if
->channel
= target_chan
;
3831 wl_ext_move_cur_dfs_channel(apsta_params
, cur_if
);
3833 return cur_if
->channel
;
3837 wl_ext_move_other_channel(struct wl_apsta_params
*apsta_params
,
3838 struct wl_if_info
*cur_if
)
3840 struct wl_if_info
*tmp_if
, *target_if
=NULL
;
3841 uint16 tmp_chan
, target_chan
= 0;
3842 wl_prio_t max_prio
= 0, cur_prio
;
3845 if (apsta_params
->vsdb
|| !cur_if
->channel
) {
3849 // find the max prio, but lower than cur_if
3850 cur_prio
= cur_if
->prio
;
3851 for (i
=0; i
<MAX_IF_NUM
; i
++) {
3852 tmp_if
= &apsta_params
->if_info
[i
];
3853 if (cur_if
!= tmp_if
&& wl_get_isam_status(tmp_if
, IF_READY
) &&
3854 tmp_if
->prio
>= max_prio
&& tmp_if
->prio
<= cur_prio
) {
3855 tmp_chan
= wl_ext_get_vsdb_chan(apsta_params
, cur_if
, tmp_if
);
3858 target_chan
= tmp_chan
;
3859 max_prio
= tmp_if
->prio
;
3865 WL_MSG(target_if
->ifname
, "channel=%d => %s channel=%d\n",
3866 target_chan
, cur_if
->ifname
, cur_if
->channel
);
3867 target_if
->channel
= cur_if
->channel
;
3868 wl_ext_move_other_dfs_channel(apsta_params
, target_if
);
3869 if (apsta_params
->csa
== 0) {
3870 wl_ext_if_down(apsta_params
, target_if
);
3871 wl_ext_move_other_channel(apsta_params
, cur_if
);
3872 if (target_if
->ifmode
== ISTA_MODE
|| target_if
->ifmode
== IMESH_MODE
) {
3873 wl_ext_enable_iface(target_if
->dev
, target_if
->ifname
, 0);
3874 } else if (target_if
->ifmode
== IAP_MODE
) {
3875 wl_ext_if_up(apsta_params
, target_if
);
3878 wl_ext_trigger_csa(apsta_params
, target_if
);
3885 wl_ext_wait_other_enabling(struct wl_apsta_params
*apsta_params
,
3886 struct wl_if_info
*cur_if
)
3888 struct wl_if_info
*tmp_if
;
3889 bool enabling
= FALSE
;
3893 for (i
=0; i
<MAX_IF_NUM
; i
++) {
3894 tmp_if
= &apsta_params
->if_info
[i
];
3895 if (tmp_if
->dev
&& tmp_if
->dev
!= cur_if
->dev
) {
3896 if (tmp_if
->ifmode
== ISTA_MODE
)
3897 enabling
= wl_get_isam_status(tmp_if
, STA_CONNECTING
);
3898 else if (tmp_if
->ifmode
== IAP_MODE
|| tmp_if
->ifmode
== IMESH_MODE
)
3899 enabling
= wl_get_isam_status(tmp_if
, AP_CREATING
);
3901 WL_MSG(cur_if
->ifname
, "waiting for %s[%c] enabling...\n",
3902 tmp_if
->ifname
, tmp_if
->prefix
);
3903 if (enabling
&& tmp_if
->ifmode
== ISTA_MODE
) {
3904 timeout
= wait_event_interruptible_timeout(
3905 apsta_params
->netif_change_event
,
3906 !wl_get_isam_status(tmp_if
, STA_CONNECTING
),
3907 msecs_to_jiffies(MAX_STA_LINK_WAIT_TIME
));
3908 } else if (enabling
&&
3909 (tmp_if
->ifmode
== IAP_MODE
|| tmp_if
->ifmode
== IMESH_MODE
)) {
3910 timeout
= wait_event_interruptible_timeout(
3911 apsta_params
->netif_change_event
,
3912 !wl_get_isam_status(tmp_if
, AP_CREATING
),
3913 msecs_to_jiffies(MAX_STA_LINK_WAIT_TIME
));
3915 if (tmp_if
->ifmode
== ISTA_MODE
)
3916 enabling
= wl_get_isam_status(tmp_if
, STA_CONNECTING
);
3917 else if (tmp_if
->ifmode
== IAP_MODE
|| tmp_if
->ifmode
== IMESH_MODE
)
3918 enabling
= wl_get_isam_status(tmp_if
, AP_CREATING
);
3919 if (timeout
<= 0 || enabling
) {
3920 WL_MSG(cur_if
->ifname
, "%s[%c] is still enabling...\n",
3921 tmp_if
->ifname
, tmp_if
->prefix
);
3930 wl_ext_enable_iface(struct net_device
*dev
, char *ifname
, int wait_up
)
3932 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
3934 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
3935 wlc_ssid_t ssid
= { 0, {0} };
3936 chanspec_t fw_chspec
;
3941 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
3942 apstamode_t apstamode
= apsta_params
->apstamode
;
3943 struct wl_if_info
*cur_if
= NULL
, *tmp_if
= NULL
;
3945 struct wl_conn_info conn_info
;
3948 for (i
=0; i
<MAX_IF_NUM
; i
++) {
3949 tmp_if
= &apsta_params
->if_info
[i
];
3950 if (tmp_if
->dev
&& !strcmp(tmp_if
->dev
->name
, ifname
)) {
3956 AEXT_ERROR(dev
->name
, "wrong ifname=%s or dev not ready\n", ifname
);
3960 mutex_lock(&apsta_params
->usr_sync
);
3962 if (cur_if
->ifmode
== ISTA_MODE
) {
3963 wl_set_isam_status(cur_if
, STA_CONNECTING
);
3964 } else if (cur_if
->ifmode
== IAP_MODE
|| cur_if
->ifmode
== IMESH_MODE
) {
3965 wl_set_isam_status(cur_if
, AP_CREATING
);
3968 wl_ext_isam_status(cur_if
->dev
, NULL
, 0);
3969 WL_MSG(ifname
, "[%c] Enabling...\n", cur_if
->prefix
);
3971 wl_ext_wait_other_enabling(apsta_params
, cur_if
);
3973 if (wl_ext_master_if(cur_if
) && apsta_params
->acs
) {
3974 uint16 chan_2g
, chan_5g
;
3976 auto_band
= WL_GET_BAND(cur_if
->channel
);
3977 wl_ext_get_default_chan(cur_if
->dev
, &chan_2g
, &chan_5g
, TRUE
);
3978 if ((chan_2g
&& auto_band
== WLC_BAND_2G
) ||
3979 (chan_5g
&& auto_band
== WLC_BAND_5G
)) {
3980 cur_if
->channel
= wl_ext_autochannel(cur_if
->dev
, apsta_params
->acs
,
3983 AEXT_ERROR(ifname
, "invalid channel\n");
3989 wl_ext_move_cur_channel(apsta_params
, cur_if
);
3991 if (wl_ext_master_if(cur_if
) && !cur_if
->channel
) {
3992 AEXT_ERROR(ifname
, "skip channel 0\n");
3997 cur_chan
= wl_ext_get_chan(apsta_params
, cur_if
->dev
);
3999 AEXT_INFO(cur_if
->ifname
, "Associated\n");
4000 if (cur_chan
!= cur_if
->channel
) {
4001 wl_ext_trigger_csa(apsta_params
, cur_if
);
4005 if (cur_if
->ifmode
== ISTA_MODE
) {
4006 wl_clr_isam_status(cur_if
, STA_CONNECTED
);
4007 } else if (cur_if
->ifmode
== IAP_MODE
|| cur_if
->ifmode
== IMESH_MODE
) {
4008 wl_clr_isam_status(cur_if
, AP_CREATED
);
4011 wl_ext_move_other_channel(apsta_params
, cur_if
);
4013 if (cur_if
->ifidx
> 0) {
4014 wl_ext_iovar_setbuf(cur_if
->dev
, "cur_etheraddr", (u8
*)cur_if
->dev
->dev_addr
,
4015 ETHER_ADDR_LEN
, iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
4019 ssid
.SSID_len
= strlen(cur_if
->ssid
);
4020 memcpy(ssid
.SSID
, cur_if
->ssid
, ssid
.SSID_len
);
4021 if (cur_if
->ifmode
== IAP_MODE
|| cur_if
->ifmode
== IMESH_MODE
) {
4022 wl_ext_iovar_setint(dev
, "mpc", 0);
4023 if (apstamode
== IAPONLY_MODE
|| apstamode
== IMESHONLY_MODE
) {
4024 wl_ext_ioctl(dev
, WLC_UP
, NULL
, 0, 1);
4025 } else if (apstamode
==ISTAAP_MODE
|| apstamode
==ISTAGO_MODE
) {
4026 wl_ext_iovar_setbuf_bsscfg(cur_if
->dev
, "ssid", &ssid
, sizeof(ssid
),
4027 iovar_buf
, WLC_IOCTL_SMLEN
, cur_if
->bssidx
, NULL
);
4031 if (wl_ext_master_if(cur_if
)) {
4032 wl_ext_set_bgnmode(cur_if
);
4033 if (!cur_if
->channel
) {
4034 cur_if
->channel
= 1;
4036 ret
= wl_ext_set_chanspec(cur_if
->dev
, apsta_params
->ioctl_ver
,
4037 cur_if
->channel
, &fw_chspec
);
4042 wl_ext_set_amode(cur_if
);
4043 wl_ext_set_emode(apsta_params
, cur_if
);
4045 if (cur_if
->ifmode
== ISTA_MODE
) {
4046 conn_info
.bssidx
= cur_if
->bssidx
;
4047 conn_info
.channel
= cur_if
->channel
;
4048 memcpy(conn_info
.ssid
.SSID
, cur_if
->ssid
, strlen(cur_if
->ssid
));
4049 conn_info
.ssid
.SSID_len
= strlen(cur_if
->ssid
);
4050 memcpy(&conn_info
.bssid
, &cur_if
->bssid
, ETHER_ADDR_LEN
);
4052 if (cur_if
->ifmode
== IAP_MODE
) {
4053 if (cur_if
->maxassoc
>= 0)
4054 wl_ext_iovar_setint(dev
, "maxassoc", cur_if
->maxassoc
);
4055 // terence: fix me, hidden does not work in dualAP mode
4056 if (cur_if
->hidden
> 0) {
4057 wl_ext_ioctl(cur_if
->dev
, WLC_SET_CLOSED
, &cur_if
->hidden
,
4058 sizeof(cur_if
->hidden
), 1);
4059 WL_MSG(ifname
, "[%c] Broadcast SSID: %s\n",
4060 cur_if
->prefix
, cur_if
->hidden
? "OFF":"ON");
4064 if (apstamode
== ISTAONLY_MODE
) {
4065 wl_ext_connect(cur_if
->dev
, &conn_info
);
4066 } else if (apstamode
== IAPONLY_MODE
) {
4067 wl_ext_ioctl(cur_if
->dev
, WLC_SET_SSID
, &ssid
, sizeof(ssid
), 1);
4068 wl_ext_ioctl(dev
, WLC_UP
, NULL
, 0, 1);
4069 } else if (apstamode
== ISTAAP_MODE
|| apstamode
== ISTAGO_MODE
) {
4070 if (cur_if
->ifmode
== ISTA_MODE
) {
4071 wl_ext_connect(cur_if
->dev
, &conn_info
);
4073 if (FW_SUPPORTED(dhd
, rsdb
)) {
4074 wl_ext_ioctl(cur_if
->dev
, WLC_SET_SSID
, &ssid
, sizeof(ssid
), 1);
4076 bss_setbuf
.cfg
= htod32(cur_if
->bssidx
);
4077 bss_setbuf
.val
= htod32(1);
4078 wl_ext_iovar_setbuf(cur_if
->dev
, "bss", &bss_setbuf
,
4079 sizeof(bss_setbuf
), iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
4081 #ifdef ARP_OFFLOAD_SUPPORT
4082 /* IF SoftAP is enabled, disable arpoe */
4083 dhd_arp_offload_set(dhd
, 0);
4084 dhd_arp_offload_enable(dhd
, FALSE
);
4085 #endif /* ARP_OFFLOAD_SUPPORT */
4086 #ifdef PROP_TXSTATUS_VSDB
4087 #if defined(BCMSDIO)
4088 if (!(FW_SUPPORTED(dhd
, rsdb
)) && !disable_proptx
) {
4090 dhd_wlfc_get_enable(dhd
, &enabled
);
4093 wl_ext_ioctl(dev
, WLC_UP
, NULL
, 0, 1);
4096 #endif /* BCMSDIO */
4097 #endif /* PROP_TXSTATUS_VSDB */
4100 else if (apstamode
== IDUALAP_MODE
) {
4101 wl_ext_ioctl(cur_if
->dev
, WLC_SET_SSID
, &ssid
, sizeof(ssid
), 1);
4102 } else if (apstamode
== ISTAAPAP_MODE
) {
4103 if (cur_if
->ifmode
== ISTA_MODE
) {
4104 wl_ext_connect(cur_if
->dev
, &conn_info
);
4105 } else if (cur_if
->ifmode
== IAP_MODE
) {
4106 wl_ext_ioctl(cur_if
->dev
, WLC_SET_SSID
, &ssid
, sizeof(ssid
), 1);
4108 AEXT_ERROR(cur_if
->ifname
, "wrong ifmode %d\n", cur_if
->ifmode
);
4111 } else if (apstamode
== IMESHONLY_MODE
||
4112 apstamode
== ISTAMESH_MODE
|| apstamode
== IMESHAP_MODE
||
4113 apstamode
== ISTAAPMESH_MODE
|| apstamode
== IMESHAPAP_MODE
) {
4114 if (cur_if
->ifmode
== ISTA_MODE
) {
4115 wl_ext_connect(cur_if
->dev
, &conn_info
);
4116 } else if (cur_if
->ifmode
== IAP_MODE
) {
4117 wl_ext_ioctl(cur_if
->dev
, WLC_SET_SSID
, &ssid
, sizeof(ssid
), 1);
4118 } else if (cur_if
->ifmode
== IMESH_MODE
) {
4119 struct wl_join_params join_params
;
4120 // need to up before setting ssid
4121 memset(&join_params
, 0, sizeof(join_params
));
4122 join_params
.ssid
.SSID_len
= strlen(cur_if
->ssid
);
4123 memcpy((void *)join_params
.ssid
.SSID
, cur_if
->ssid
, strlen(cur_if
->ssid
));
4124 join_params
.params
.chanspec_list
[0] = fw_chspec
;
4125 join_params
.params
.chanspec_num
= 1;
4126 wl_ext_ioctl(cur_if
->dev
, WLC_SET_SSID
, &join_params
, sizeof(join_params
), 1);
4128 AEXT_ERROR(cur_if
->ifname
, "wrong ifmode %d\n", cur_if
->ifmode
);
4135 } else if (cur_if
->ifmode
== IAP_MODE
|| cur_if
->ifmode
== IMESH_MODE
) {
4136 timeout
= wait_event_interruptible_timeout(apsta_params
->netif_change_event
,
4137 wl_get_isam_status(cur_if
, AP_CREATED
),
4138 msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME
));
4139 if (timeout
<= 0 || !wl_get_isam_status(cur_if
, AP_CREATED
)) {
4140 mutex_unlock(&apsta_params
->usr_sync
);
4141 wl_ext_disable_iface(dev
, cur_if
->ifname
);
4142 WL_MSG(ifname
, "[%c] failed to enable with SSID: \"%s\"\n",
4143 cur_if
->prefix
, cur_if
->ssid
);
4148 if (wl_get_isam_status(cur_if
, AP_CREATED
) &&
4149 (cur_if
->ifmode
== IMESH_MODE
|| cur_if
->ifmode
== IAP_MODE
) &&
4150 (apstamode
== ISTAAP_MODE
|| apstamode
== ISTAAPAP_MODE
||
4151 apstamode
== ISTAMESH_MODE
|| apstamode
== IMESHAP_MODE
||
4152 apstamode
== ISTAAPMESH_MODE
|| apstamode
== IMESHAPAP_MODE
)) {
4153 int scan_assoc_time
= 80;
4154 for (i
=0; i
<MAX_IF_NUM
; i
++) {
4155 tmp_if
= &apsta_params
->if_info
[i
];
4156 if (tmp_if
->dev
&& tmp_if
->ifmode
== ISTA_MODE
) {
4157 wl_ext_ioctl(tmp_if
->dev
, WLC_SET_SCAN_CHANNEL_TIME
,
4158 &scan_assoc_time
, sizeof(scan_assoc_time
), 1);
4163 wl_ext_isam_status(cur_if
->dev
, NULL
, 0);
4166 if (cur_if
->ifmode
== IAP_MODE
|| cur_if
->ifmode
== IMESH_MODE
) {
4167 wl_clr_isam_status(cur_if
, AP_CREATING
);
4169 WL_MSG(ifname
, "[%c] Exit ret=%d\n", cur_if
->prefix
, ret
);
4170 mutex_unlock(&apsta_params
->usr_sync
);
4175 wl_ext_iapsta_enable(struct net_device
*dev
, char *command
, int total_len
)
4178 char *pch
, *pick_tmp
, *param
;
4179 char ifname
[IFNAMSIZ
+1];
4181 AEXT_TRACE(dev
->name
, "command=%s, len=%d\n", command
, total_len
);
4184 param
= bcmstrtok(&pick_tmp
, " ", 0); // skip iapsta_enable
4185 param
= bcmstrtok(&pick_tmp
, " ", 0);
4186 while (param
!= NULL
) {
4187 if (!strcmp(param
, "ifname")) {
4188 pch
= bcmstrtok(&pick_tmp
, " ", 0);
4190 strcpy(ifname
, pch
);
4191 ret
= wl_ext_enable_iface(dev
, ifname
, 0);
4195 AEXT_ERROR(dev
->name
, "ifname [wlanX]\n");
4199 param
= bcmstrtok(&pick_tmp
, " ", 0);
4205 #ifdef PROPTX_MAXCOUNT
4207 wl_ext_get_wlfc_maxcount(struct dhd_pub
*dhd
, int ifidx
)
4209 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4210 struct wl_if_info
*tmp_if
, *cur_if
= NULL
;
4211 int i
, maxcount
= WL_TXSTATUS_FREERUNCTR_MASK
;
4213 if (!apsta_params
->rsdb
)
4216 for (i
=0; i
<MAX_IF_NUM
; i
++) {
4217 tmp_if
= &apsta_params
->if_info
[i
];
4218 if (tmp_if
->dev
&& tmp_if
->ifidx
== ifidx
) {
4220 maxcount
= cur_if
->transit_maxcount
;
4225 AEXT_INFO(cur_if
->ifname
, "update maxcount %d\n", maxcount
);
4227 AEXT_INFO("wlan", "update maxcount %d for ifidx %d\n", maxcount
, ifidx
);
4232 wl_ext_update_wlfc_maxcount(struct dhd_pub
*dhd
)
4234 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4235 struct wl_if_info
*tmp_if
;
4236 bool band_5g
= FALSE
;
4240 if (!apsta_params
->rsdb
)
4243 for (i
=0; i
<MAX_IF_NUM
; i
++) {
4244 tmp_if
= &apsta_params
->if_info
[i
];
4246 chan
= wl_ext_get_chan(apsta_params
, tmp_if
->dev
);
4247 if (chan
> CH_MAX_2G_CHANNEL
) {
4248 tmp_if
->transit_maxcount
= dhd
->conf
->proptx_maxcnt_5g
;
4249 ret
= dhd_wlfc_update_maxcount(dhd
, tmp_if
->ifidx
,
4250 tmp_if
->transit_maxcount
);
4252 AEXT_INFO(tmp_if
->ifname
, "updated maxcount %d\n",
4253 tmp_if
->transit_maxcount
);
4259 for (i
=0; i
<MAX_IF_NUM
; i
++) {
4260 tmp_if
= &apsta_params
->if_info
[i
];
4262 chan
= wl_ext_get_chan(apsta_params
, tmp_if
->dev
);
4263 if ((chan
== 0) || (chan
<= CH_MAX_2G_CHANNEL
&& chan
>= CH_MIN_2G_CHANNEL
)) {
4265 tmp_if
->transit_maxcount
= WL_TXSTATUS_FREERUNCTR_MASK
;
4266 } else if (band_5g
) {
4267 tmp_if
->transit_maxcount
= dhd
->conf
->proptx_maxcnt_2g
;
4269 tmp_if
->transit_maxcount
= dhd
->conf
->proptx_maxcnt_5g
;
4271 ret
= dhd_wlfc_update_maxcount(dhd
, tmp_if
->ifidx
,
4272 tmp_if
->transit_maxcount
);
4274 AEXT_INFO(tmp_if
->ifname
, "updated maxcount %d\n",
4275 tmp_if
->transit_maxcount
);
4280 #endif /* PROPTX_MAXCOUNT */
4283 wl_ext_iapsta_event(struct net_device
*dev
,
4284 struct wl_apsta_params
*apsta_params
, wl_event_msg_t
*e
, void* data
)
4286 struct wl_if_info
*cur_if
= NULL
, *tmp_if
= NULL
;
4287 #if defined(WLMESH) && defined(WL_ESCAN)
4288 struct wl_if_info
*mesh_if
= NULL
;
4289 #endif /* WLMESH && WL_ESCAN */
4291 uint32 event_type
= ntoh32(e
->event_type
);
4292 uint32 status
= ntoh32(e
->status
);
4293 uint32 reason
= ntoh32(e
->reason
);
4294 uint16 flags
= ntoh16(e
->flags
);
4296 for (i
=0; i
<MAX_IF_NUM
; i
++) {
4297 tmp_if
= &apsta_params
->if_info
[i
];
4298 if (tmp_if
->dev
== dev
) {
4303 #if defined(WLMESH) && defined(WL_ESCAN)
4304 for (i
=0; i
<MAX_IF_NUM
; i
++) {
4305 tmp_if
= &apsta_params
->if_info
[i
];
4306 if (tmp_if
->dev
&& tmp_if
->ifmode
== IMESH_MODE
) {
4311 #endif /* WLMESH && WL_ESCAN */
4312 if (!cur_if
|| !cur_if
->dev
) {
4313 AEXT_DBG(dev
->name
, "ifidx %d is not ready\n", e
->ifidx
);
4317 if (cur_if
->ifmode
== ISTA_MODE
|| cur_if
->ifmode
== IGC_MODE
) {
4318 if (event_type
== WLC_E_LINK
) {
4319 if (!(flags
& WLC_EVENT_MSG_LINK
)) {
4320 WL_MSG(cur_if
->ifname
,
4321 "[%c] Link down with %pM, %s(%d), reason %d\n",
4322 cur_if
->prefix
, &e
->addr
, bcmevent_get_name(event_type
),
4323 event_type
, reason
);
4324 wl_clr_isam_status(cur_if
, STA_CONNECTED
);
4325 #if defined(WLMESH) && defined(WL_ESCAN)
4326 if (mesh_if
&& apsta_params
->macs
)
4327 wl_mesh_clear_mesh_info(apsta_params
, mesh_if
, TRUE
);
4328 #endif /* WLMESH && WL_ESCAN */
4330 WL_MSG(cur_if
->ifname
, "[%c] Link UP with %pM\n",
4331 cur_if
->prefix
, &e
->addr
);
4332 wl_set_isam_status(cur_if
, STA_CONNECTED
);
4333 #if defined(WLMESH) && defined(WL_ESCAN)
4334 if (mesh_if
&& apsta_params
->macs
)
4335 wl_mesh_update_master_info(apsta_params
, mesh_if
);
4336 #endif /* WLMESH && WL_ESCAN */
4338 wl_clr_isam_status(cur_if
, STA_CONNECTING
);
4339 wake_up_interruptible(&apsta_params
->netif_change_event
);
4340 #ifdef PROPTX_MAXCOUNT
4341 wl_ext_update_wlfc_maxcount(apsta_params
->dhd
);
4342 #endif /* PROPTX_MAXCOUNT */
4343 } else if (event_type
== WLC_E_SET_SSID
&& status
!= WLC_E_STATUS_SUCCESS
) {
4344 WL_MSG(cur_if
->ifname
,
4345 "connect failed event=%d, reason=%d, status=%d\n",
4346 event_type
, reason
, status
);
4347 wl_clr_isam_status(cur_if
, STA_CONNECTING
);
4348 wake_up_interruptible(&apsta_params
->netif_change_event
);
4349 #if defined(WLMESH) && defined(WL_ESCAN)
4350 if (mesh_if
&& apsta_params
->macs
)
4351 wl_mesh_clear_mesh_info(apsta_params
, mesh_if
, TRUE
);
4352 #endif /* WLMESH && WL_ESCAN */
4353 #ifdef PROPTX_MAXCOUNT
4354 wl_ext_update_wlfc_maxcount(apsta_params
->dhd
);
4355 #endif /* PROPTX_MAXCOUNT */
4356 } else if (event_type
== WLC_E_DEAUTH
|| event_type
== WLC_E_DEAUTH_IND
||
4357 event_type
== WLC_E_DISASSOC
|| event_type
== WLC_E_DISASSOC_IND
) {
4358 WL_MSG(cur_if
->ifname
, "[%c] Link down with %pM, %s(%d), reason %d\n",
4359 cur_if
->prefix
, &e
->addr
, bcmevent_get_name(event_type
),
4360 event_type
, reason
);
4361 #if defined(WLMESH) && defined(WL_ESCAN)
4362 if (mesh_if
&& apsta_params
->macs
)
4363 wl_mesh_clear_mesh_info(apsta_params
, mesh_if
, TRUE
);
4364 #endif /* WLMESH && WL_ESCAN */
4367 else if (cur_if
->ifmode
== IAP_MODE
|| cur_if
->ifmode
== IMESH_MODE
) {
4368 if ((event_type
== WLC_E_SET_SSID
&& status
== WLC_E_STATUS_SUCCESS
) ||
4369 (event_type
== WLC_E_LINK
&& status
== WLC_E_STATUS_SUCCESS
&&
4370 reason
== WLC_E_REASON_INITIAL_ASSOC
)) {
4371 if (wl_get_isam_status(cur_if
, AP_CREATING
)) {
4372 WL_MSG(cur_if
->ifname
, "[%c] Link up (etype=%d)\n",
4373 cur_if
->prefix
, event_type
);
4374 wl_set_isam_status(cur_if
, AP_CREATED
);
4375 wake_up_interruptible(&apsta_params
->netif_change_event
);
4377 wl_set_isam_status(cur_if
, AP_CREATED
);
4378 WL_MSG(cur_if
->ifname
, "[%c] Link up w/o creating? (etype=%d)\n",
4379 cur_if
->prefix
, event_type
);
4381 #ifdef PROPTX_MAXCOUNT
4382 wl_ext_update_wlfc_maxcount(apsta_params
->dhd
);
4383 #endif /* PROPTX_MAXCOUNT */
4385 else if ((event_type
== WLC_E_LINK
&& reason
== WLC_E_LINK_BSSCFG_DIS
) ||
4386 (event_type
== WLC_E_LINK
&& status
== WLC_E_STATUS_SUCCESS
&&
4387 reason
== WLC_E_REASON_DEAUTH
)) {
4388 wl_clr_isam_status(cur_if
, AP_CREATED
);
4389 WL_MSG(cur_if
->ifname
, "[%c] Link down, reason=%d\n",
4390 cur_if
->prefix
, reason
);
4391 #ifdef PROPTX_MAXCOUNT
4392 wl_ext_update_wlfc_maxcount(apsta_params
->dhd
);
4393 #endif /* PROPTX_MAXCOUNT */
4395 else if ((event_type
== WLC_E_ASSOC_IND
|| event_type
== WLC_E_REASSOC_IND
) &&
4396 reason
== DOT11_SC_SUCCESS
) {
4397 WL_MSG(cur_if
->ifname
, "[%c] connected device %pM\n",
4398 cur_if
->prefix
, &e
->addr
);
4399 wl_ext_isam_status(cur_if
->dev
, NULL
, 0);
4401 else if (event_type
== WLC_E_DISASSOC_IND
||
4402 event_type
== WLC_E_DEAUTH_IND
||
4403 (event_type
== WLC_E_DEAUTH
&& reason
!= DOT11_RC_RESERVED
)) {
4404 WL_MSG_RLMT(cur_if
->ifname
, &e
->addr
, ETHER_ADDR_LEN
,
4405 "[%c] disconnected device %pM, %s(%d), reason=%d\n",
4406 cur_if
->prefix
, &e
->addr
, bcmevent_get_name(event_type
),
4407 event_type
, reason
);
4408 wl_ext_isam_status(cur_if
->dev
, NULL
, 0);
4410 #if defined(WLMESH) && defined(WL_ESCAN)
4411 if (cur_if
->ifmode
== IMESH_MODE
&& apsta_params
->macs
)
4412 wl_mesh_event_handler(apsta_params
, cur_if
, e
, data
);
4413 #endif /* WLMESH && WL_ESCAN */
4421 wl_ext_iapsta_update_channel(dhd_pub_t
*dhd
, struct net_device
*dev
,
4424 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4425 struct wl_if_info
*cur_if
= NULL
, *tmp_if
= NULL
;
4428 for (i
=0; i
<MAX_IF_NUM
; i
++) {
4429 tmp_if
= &apsta_params
->if_info
[i
];
4430 if (tmp_if
->dev
&& tmp_if
->dev
== dev
) {
4437 wl_ext_isam_status(cur_if
->dev
, NULL
, 0);
4438 cur_if
->channel
= channel
;
4439 if (wl_ext_master_if(cur_if
) && apsta_params
->acs
) {
4440 uint auto_band
= WL_GET_BAND(channel
);
4441 cur_if
->channel
= wl_ext_autochannel(cur_if
->dev
, apsta_params
->acs
,
4444 channel
= wl_ext_move_cur_channel(apsta_params
, cur_if
);
4446 wl_ext_move_other_channel(apsta_params
, cur_if
);
4447 if (cur_if
->ifmode
== ISTA_MODE
)
4448 wl_set_isam_status(cur_if
, STA_CONNECTING
);
4455 wl_ext_iftype_to_ifmode(struct net_device
*net
, int wl_iftype
, ifmode_t
*ifmode
)
4457 switch (wl_iftype
) {
4458 case WL_IF_TYPE_STA
:
4459 *ifmode
= ISTA_MODE
;
4464 case WL_IF_TYPE_P2P_GO
:
4467 case WL_IF_TYPE_P2P_GC
:
4471 AEXT_ERROR(net
->name
, "Unknown interface wl_iftype:0x%x\n", wl_iftype
);
4478 wl_ext_iapsta_update_iftype(struct net_device
*net
, int ifidx
, int wl_iftype
)
4480 struct dhd_pub
*dhd
= dhd_get_pub(net
);
4481 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4482 struct wl_if_info
*cur_if
= NULL
;
4484 AEXT_TRACE(net
->name
, "ifidx=%d, wl_iftype=%d\n", ifidx
, wl_iftype
);
4486 if (ifidx
< MAX_IF_NUM
) {
4487 cur_if
= &apsta_params
->if_info
[ifidx
];
4491 if (wl_iftype
== WL_IF_TYPE_STA
) {
4492 cur_if
->ifmode
= ISTA_MODE
;
4493 cur_if
->prio
= PRIO_STA
;
4494 cur_if
->prefix
= 'S';
4495 } else if (wl_iftype
== WL_IF_TYPE_AP
&& cur_if
->ifmode
!= IMESH_MODE
) {
4496 cur_if
->ifmode
= IAP_MODE
;
4497 cur_if
->prio
= PRIO_AP
;
4498 cur_if
->prefix
= 'A';
4499 } else if (wl_iftype
== WL_IF_TYPE_P2P_GO
) {
4500 cur_if
->ifmode
= IGO_MODE
;
4501 cur_if
->prio
= PRIO_AP
;
4502 cur_if
->prefix
= 'P';
4503 apsta_params
->vsdb
= TRUE
;
4504 } else if (wl_iftype
== WL_IF_TYPE_P2P_GC
) {
4505 cur_if
->ifmode
= IGC_MODE
;
4506 cur_if
->prio
= PRIO_STA
;
4507 cur_if
->prefix
= 'P';
4508 apsta_params
->vsdb
= TRUE
;
4509 wl_ext_iovar_setint(cur_if
->dev
, "assoc_retry_max", 3);
4515 wl_ext_iapsta_ifadding(struct net_device
*net
, int ifidx
)
4517 struct dhd_pub
*dhd
= dhd_get_pub(net
);
4518 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4519 struct wl_if_info
*cur_if
= NULL
;
4521 AEXT_TRACE(net
->name
, "ifidx=%d\n", ifidx
);
4522 if (ifidx
< MAX_IF_NUM
) {
4523 cur_if
= &apsta_params
->if_info
[ifidx
];
4524 wl_set_isam_status(cur_if
, IF_ADDING
);
4529 wl_ext_iapsta_iftype_enabled(struct net_device
*net
, int wl_iftype
)
4531 struct dhd_pub
*dhd
= dhd_get_pub(net
);
4532 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4533 struct wl_if_info
*cur_if
= NULL
;
4534 ifmode_t ifmode
= 0;
4536 wl_ext_iftype_to_ifmode(net
, wl_iftype
, &ifmode
);
4537 cur_if
= wl_ext_if_enabled(apsta_params
, ifmode
);
4545 wl_ext_iapsta_mesh_creating(struct net_device
*net
)
4547 struct dhd_pub
*dhd
= dhd_get_pub(net
);
4548 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4549 struct wl_if_info
*cur_if
;
4553 for (i
=0; i
<MAX_IF_NUM
; i
++) {
4554 cur_if
= &apsta_params
->if_info
[i
];
4555 if (cur_if
->ifmode
==IMESH_MODE
&& wl_get_isam_status(cur_if
, IF_ADDING
))
4561 #endif /* WL_CFG80211 */
4564 wl_ext_iapsta_alive_preinit(struct net_device
*dev
)
4566 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
4567 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4569 if (apsta_params
->init
== TRUE
) {
4570 AEXT_ERROR(dev
->name
, "don't init twice\n");
4574 AEXT_TRACE(dev
->name
, "Enter\n");
4576 apsta_params
->init
= TRUE
;
4582 wl_ext_iapsta_alive_postinit(struct net_device
*dev
)
4584 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
4585 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4586 s32 apsta
= 0, ap
= 0;
4587 struct wl_if_info
*cur_if
;
4590 wl_ext_iovar_getint(dev
, "apsta", &apsta
);
4591 wl_ext_ioctl(dev
, WLC_GET_AP
, &ap
, sizeof(ap
), 0);
4592 if (apsta
== 1 || ap
== 0) {
4593 apsta_params
->apstamode
= ISTAONLY_MODE
;
4594 apsta_params
->if_info
[IF_PIF
].ifmode
= ISTA_MODE
;
4595 op_mode
= DHD_FLAG_STA_MODE
;
4597 apsta_params
->apstamode
= IAPONLY_MODE
;
4598 apsta_params
->if_info
[IF_PIF
].ifmode
= IAP_MODE
;
4599 op_mode
= DHD_FLAG_HOSTAP_MODE
;
4601 // fix me: how to check it's ISTAAP_MODE or IDUALAP_MODE?
4603 wl_ext_get_ioctl_ver(dev
, &apsta_params
->ioctl_ver
);
4604 WL_MSG(dev
->name
, "apstamode=%d\n", apsta_params
->apstamode
);
4606 for (i
=0; i
<MAX_IF_NUM
; i
++) {
4607 cur_if
= &apsta_params
->if_info
[i
];
4608 if (i
== 1 && !strlen(cur_if
->ifname
))
4609 strcpy(cur_if
->ifname
, "wlan1");
4610 if (i
== 2 && !strlen(cur_if
->ifname
))
4611 strcpy(cur_if
->ifname
, "wlan2");
4612 if (cur_if
->ifmode
== ISTA_MODE
) {
4613 cur_if
->channel
= 0;
4614 cur_if
->maxassoc
= -1;
4615 wl_set_isam_status(cur_if
, IF_READY
);
4616 cur_if
->prio
= PRIO_STA
;
4617 cur_if
->prefix
= 'S';
4618 snprintf(cur_if
->ssid
, DOT11_MAX_SSID_LEN
, "ttt_sta");
4619 } else if (cur_if
->ifmode
== IAP_MODE
) {
4620 cur_if
->channel
= 1;
4621 cur_if
->maxassoc
= -1;
4622 wl_set_isam_status(cur_if
, IF_READY
);
4623 cur_if
->prio
= PRIO_AP
;
4624 cur_if
->prefix
= 'A';
4625 snprintf(cur_if
->ssid
, DOT11_MAX_SSID_LEN
, "ttt_ap");
4627 } else if (cur_if
->ifmode
== IMESH_MODE
) {
4628 cur_if
->channel
= 1;
4629 cur_if
->maxassoc
= -1;
4630 wl_set_isam_status(cur_if
, IF_READY
);
4631 cur_if
->prio
= PRIO_MESH
;
4632 cur_if
->prefix
= 'M';
4633 snprintf(cur_if
->ssid
, DOT11_MAX_SSID_LEN
, "ttt_mesh");
4642 wl_ext_iapsta_get_rsdb(struct net_device
*net
, struct dhd_pub
*dhd
)
4644 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
4645 wl_config_t
*rsdb_p
;
4646 int ret
= 0, rsdb
= 0;
4648 if (dhd
->conf
->chip
== BCM4359_CHIP_ID
) {
4649 ret
= wldev_iovar_getbuf(net
, "rsdb_mode", NULL
, 0,
4650 iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
4652 if (dhd
->conf
->fw_type
== FW_TYPE_MESH
) {
4655 rsdb_p
= (wl_config_t
*) iovar_buf
;
4656 rsdb
= rsdb_p
->config
;
4661 AEXT_INFO(net
->name
, "rsdb_mode=%d\n", rsdb
);
4667 wl_ext_iapsta_postinit(struct net_device
*net
, struct wl_if_info
*cur_if
)
4669 struct dhd_pub
*dhd
= dhd_get_pub(net
);
4670 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4673 AEXT_TRACE(cur_if
->ifname
, "ifidx=%d\n", cur_if
->ifidx
);
4674 if (cur_if
->ifidx
== 0) {
4675 apsta_params
->rsdb
= wl_ext_iapsta_get_rsdb(net
, dhd
);
4676 apsta_params
->vsdb
= FALSE
;
4677 apsta_params
->csa
= 0;
4678 apsta_params
->acs
= 0;
4679 apsta_params
->radar
= wl_ext_radar_detect(net
);
4680 if (dhd
->conf
->fw_type
== FW_TYPE_MESH
) {
4681 apsta_params
->csa
|= (CSA_FW_BIT
| CSA_DRV_BIT
);
4684 if (cur_if
->ifmode
== ISTA_MODE
) {
4685 wl_ext_iovar_setint(cur_if
->dev
, "roam_off", dhd
->conf
->roam_off
);
4686 wl_ext_iovar_setint(cur_if
->dev
, "bcn_timeout", dhd
->conf
->bcn_timeout
);
4687 if (dhd
->conf
->pm
>= 0)
4691 wl_ext_ioctl(cur_if
->dev
, WLC_SET_PM
, &pm
, sizeof(pm
), 1);
4692 wl_ext_iovar_setint(cur_if
->dev
, "assoc_retry_max", 20);
4695 else if (cur_if
->ifmode
== IMESH_MODE
) {
4697 wl_ext_ioctl(cur_if
->dev
, WLC_SET_PM
, &pm
, sizeof(pm
), 1);
4701 #ifdef PROPTX_MAXCOUNT
4702 wl_ext_update_wlfc_maxcount(dhd
);
4703 #endif /* PROPTX_MAXCOUNT */
4708 wl_ext_iapsta_attach_name(struct net_device
*net
, int ifidx
)
4710 struct dhd_pub
*dhd
= dhd_get_pub(net
);
4711 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4712 struct wl_if_info
*cur_if
= NULL
;
4714 AEXT_TRACE(net
->name
, "ifidx=%d\n", ifidx
);
4715 if (ifidx
< MAX_IF_NUM
) {
4716 cur_if
= &apsta_params
->if_info
[ifidx
];
4719 strcpy(cur_if
->ifname
, net
->name
);
4720 wl_ext_iapsta_postinit(net
, cur_if
);
4721 wl_set_isam_status(cur_if
, IF_READY
);
4722 } else if (cur_if
&& wl_get_isam_status(cur_if
, IF_ADDING
)) {
4723 strcpy(cur_if
->ifname
, net
->name
);
4724 wl_ext_iapsta_postinit(net
, cur_if
);
4725 wl_clr_isam_status(cur_if
, IF_ADDING
);
4726 wl_set_isam_status(cur_if
, IF_READY
);
4727 #ifndef WL_STATIC_IF
4728 wake_up_interruptible(&apsta_params
->netif_change_event
);
4729 #endif /* WL_STATIC_IF */
4736 wl_ext_iapsta_update_net_device(struct net_device
*net
, int ifidx
)
4738 struct dhd_pub
*dhd
= dhd_get_pub(net
);
4739 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4740 struct wl_if_info
*cur_if
= NULL
, *primary_if
;
4742 AEXT_TRACE(net
->name
, "ifidx=%d\n", ifidx
);
4743 if (ifidx
< MAX_IF_NUM
) {
4744 cur_if
= &apsta_params
->if_info
[ifidx
];
4746 if (cur_if
&& wl_get_isam_status(cur_if
, IF_ADDING
)) {
4747 primary_if
= &apsta_params
->if_info
[IF_PIF
];
4748 if (strlen(cur_if
->ifname
)) {
4749 memset(net
->name
, 0, sizeof(IFNAMSIZ
));
4750 strcpy(net
->name
, cur_if
->ifname
);
4751 net
->name
[IFNAMSIZ
-1] = '\0';
4753 #ifndef WL_STATIC_IF
4754 if (apsta_params
->apstamode
!= IUNKNOWN_MODE
&&
4755 apsta_params
->apstamode
!= ISTAAPAP_MODE
&&
4756 apsta_params
->apstamode
!= ISTASTA_MODE
) {
4757 memcpy(net
->dev_addr
, primary_if
->dev
->dev_addr
, ETHER_ADDR_LEN
);
4758 net
->dev_addr
[0] |= 0x02;
4760 net
->dev_addr
[4] ^= 0x80;
4761 net
->dev_addr
[4] += ifidx
;
4762 net
->dev_addr
[5] += (ifidx
-1);
4765 #endif /* WL_STATIC_IF */
4772 wl_ext_iapsta_attach_netdev(struct net_device
*net
, int ifidx
, uint8 bssidx
)
4774 struct dhd_pub
*dhd
= dhd_get_pub(net
);
4775 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4776 struct wl_if_info
*cur_if
= NULL
, *primary_if
;
4778 AEXT_TRACE(net
->name
, "ifidx=%d, bssidx=%d\n", ifidx
, bssidx
);
4779 if (ifidx
< MAX_IF_NUM
) {
4780 cur_if
= &apsta_params
->if_info
[ifidx
];
4783 memset(apsta_params
, 0, sizeof(struct wl_apsta_params
));
4784 apsta_params
->dhd
= dhd
;
4786 cur_if
->ifidx
= ifidx
;
4787 cur_if
->bssidx
= bssidx
;
4788 cur_if
->ifmode
= ISTA_MODE
;
4789 cur_if
->prio
= PRIO_STA
;
4790 cur_if
->prefix
= 'S';
4791 wl_ext_event_register(net
, dhd
, WLC_E_LAST
, wl_ext_iapsta_event
,
4792 apsta_params
, PRIO_EVENT_IAPSTA
);
4793 strcpy(cur_if
->ifname
, net
->name
);
4794 init_waitqueue_head(&apsta_params
->netif_change_event
);
4795 mutex_init(&apsta_params
->usr_sync
);
4796 mutex_init(&cur_if
->pm_sync
);
4797 INIT_DELAYED_WORK(&cur_if
->pm_enable_work
, wl_ext_pm_work_handler
);
4798 } else if (cur_if
&& wl_get_isam_status(cur_if
, IF_ADDING
)) {
4799 primary_if
= &apsta_params
->if_info
[IF_PIF
];
4801 cur_if
->ifidx
= ifidx
;
4802 cur_if
->bssidx
= bssidx
;
4803 wl_ext_event_register(net
, dhd
, WLC_E_LAST
, wl_ext_iapsta_event
,
4804 apsta_params
, PRIO_EVENT_IAPSTA
);
4805 #if defined(WLMESH) && defined(WL_ESCAN)
4806 if (cur_if
->ifmode
== IMESH_MODE
&& apsta_params
->macs
) {
4807 wl_mesh_escan_attach(dhd
, cur_if
);
4809 #endif /* WLMESH && WL_ESCAN */
4810 mutex_init(&cur_if
->pm_sync
);
4811 INIT_DELAYED_WORK(&cur_if
->pm_enable_work
, wl_ext_pm_work_handler
);
4818 wl_ext_iapsta_dettach_netdev(struct net_device
*net
, int ifidx
)
4820 struct dhd_pub
*dhd
= dhd_get_pub(net
);
4821 struct wl_apsta_params
*apsta_params
= dhd
->iapsta_params
;
4822 struct wl_if_info
*cur_if
= NULL
;
4827 AEXT_TRACE(net
->name
, "ifidx=%d\n", ifidx
);
4828 if (ifidx
< MAX_IF_NUM
) {
4829 cur_if
= &apsta_params
->if_info
[ifidx
];
4833 wl_ext_add_remove_pm_enable_work(net
, FALSE
);
4834 wl_ext_event_deregister(net
, dhd
, WLC_E_LAST
, wl_ext_iapsta_event
);
4835 #if defined(WLMESH) && defined(WL_ESCAN)
4836 if (cur_if
->ifmode
== IMESH_MODE
&& apsta_params
->macs
) {
4837 wl_mesh_escan_detach(dhd
, cur_if
);
4839 #endif /* WLMESH && WL_ESCAN */
4840 memset(apsta_params
, 0, sizeof(struct wl_apsta_params
));
4841 } else if (cur_if
&& (wl_get_isam_status(cur_if
, IF_READY
) ||
4842 wl_get_isam_status(cur_if
, IF_ADDING
))) {
4843 wl_ext_add_remove_pm_enable_work(net
, FALSE
);
4844 wl_ext_event_deregister(net
, dhd
, WLC_E_LAST
, wl_ext_iapsta_event
);
4845 #if defined(WLMESH) && defined(WL_ESCAN)
4846 if (cur_if
->ifmode
== IMESH_MODE
&& apsta_params
->macs
) {
4847 wl_mesh_escan_detach(dhd
, cur_if
);
4849 #endif /* WLMESH && WL_ESCAN */
4850 memset(cur_if
, 0, sizeof(struct wl_if_info
));
4857 wl_ext_iapsta_attach(dhd_pub_t
*pub
)
4859 struct wl_apsta_params
*iapsta_params
;
4861 iapsta_params
= kzalloc(sizeof(struct wl_apsta_params
), GFP_KERNEL
);
4862 if (unlikely(!iapsta_params
)) {
4863 AEXT_ERROR("wlan", "Could not allocate apsta_params\n");
4866 pub
->iapsta_params
= (void *)iapsta_params
;
4872 wl_ext_iapsta_dettach(dhd_pub_t
*pub
)
4874 if (pub
->iapsta_params
) {
4875 kfree(pub
->iapsta_params
);
4876 pub
->iapsta_params
= NULL
;
4879 #endif /* WL_EXT_IAPSTA */
4884 dhd_priv wl dhcpc_dump
4885 dhd_priv wl dhcpc_param <client ip> <server ip> <lease time>
4888 wl_ext_dhcpc_dump(struct net_device
*dev
, char *data
, char *command
,
4892 int bytes_written
= 0;
4897 ret
= wl_ext_iovar_getint(dev
, "dhcpc_ip_addr", &ip_addr
);
4899 bcm_ip_ntoa((struct ipv4_addr
*)&ip_addr
, buf
);
4900 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
4904 ret
= wl_ext_iovar_getint(dev
, "dhcpc_ip_mask", &ip_addr
);
4906 bcm_ip_ntoa((struct ipv4_addr
*)&ip_addr
, buf
);
4907 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
4911 ret
= wl_ext_iovar_getint(dev
, "dhcpc_ip_gateway", &ip_addr
);
4913 bcm_ip_ntoa((struct ipv4_addr
*)&ip_addr
, buf
);
4914 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
4918 ret
= wl_ext_iovar_getint(dev
, "dhcpc_ip_dnsserv", &ip_addr
);
4920 bcm_ip_ntoa((struct ipv4_addr
*)&ip_addr
, buf
);
4921 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
4922 "dnsserv %s ", buf
);
4928 AEXT_TRACE(dev
->name
, "command result is %s\n", command
);
4931 return bytes_written
;
4935 wl_ext_dhcpc_param(struct net_device
*dev
, char *data
, char *command
,
4938 int ret
= -1, bytes_written
= 0;
4939 char ip_addr_str
[20]="", ip_serv_str
[20]="";
4940 struct dhcpc_parameter dhcpc_param
;
4941 uint32 ip_addr
, ip_serv
, lease_time
;
4942 char iovar_buf
[WLC_IOCTL_SMLEN
]="\0";
4945 AEXT_TRACE(dev
->name
, "cmd %s", command
);
4946 sscanf(data
, "%s %s %d", ip_addr_str
, ip_serv_str
, &lease_time
);
4947 AEXT_TRACE(dev
->name
, "ip_addr = %s, ip_serv = %s, lease_time = %d",
4948 ip_addr_str
, ip_serv_str
, lease_time
);
4950 memset(&dhcpc_param
, 0, sizeof(struct dhcpc_parameter
));
4951 if (!bcm_atoipv4(ip_addr_str
, (struct ipv4_addr
*)&ip_addr
)) {
4952 AEXT_ERROR(dev
->name
, "wrong ip_addr_str %s\n", ip_addr_str
);
4956 dhcpc_param
.ip_addr
= ip_addr
;
4958 if (!bcm_atoipv4(ip_addr_str
, (struct ipv4_addr
*)&ip_serv
)) {
4959 AEXT_ERROR(dev
->name
, "wrong ip_addr_str %s\n", ip_addr_str
);
4963 dhcpc_param
.ip_serv
= ip_serv
;
4964 dhcpc_param
.lease_time
= lease_time
;
4965 ret
= wl_ext_iovar_setbuf(dev
, "dhcpc_param", &dhcpc_param
,
4966 sizeof(struct dhcpc_parameter
), iovar_buf
, sizeof(iovar_buf
), NULL
);
4968 ret
= wl_ext_iovar_getbuf(dev
, "dhcpc_param", &dhcpc_param
,
4969 sizeof(struct dhcpc_parameter
), iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
4971 bcm_ip_ntoa((struct ipv4_addr
*)&dhcpc_param
.ip_addr
, ip_addr_str
);
4972 bytes_written
+= snprintf(command
+ bytes_written
, total_len
,
4973 "ip_addr %s\n", ip_addr_str
);
4974 bcm_ip_ntoa((struct ipv4_addr
*)&dhcpc_param
.ip_serv
, ip_serv_str
);
4975 bytes_written
+= snprintf(command
+ bytes_written
, total_len
,
4976 "ip_serv %s\n", ip_serv_str
);
4977 bytes_written
+= snprintf(command
+ bytes_written
, total_len
,
4978 "lease_time %d\n", dhcpc_param
.lease_time
);
4979 AEXT_TRACE(dev
->name
, "command result is %s\n", command
);
4980 ret
= bytes_written
;
4990 wl_ext_mkeep_alive(struct net_device
*dev
, char *data
, char *command
,
4993 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
4994 wl_mkeep_alive_pkt_t
*mkeep_alive_pktp
;
4995 int ret
= -1, i
, ifidx
, id
, period
=-1;
4996 char *packet
= NULL
, *buf
= NULL
;
4997 int bytes_written
= 0;
5000 buf
= kmalloc(total_len
, GFP_KERNEL
);
5002 AEXT_ERROR(dev
->name
, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN
);
5005 packet
= kmalloc(WLC_IOCTL_SMLEN
, GFP_KERNEL
);
5006 if (packet
== NULL
) {
5007 AEXT_ERROR(dev
->name
, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN
);
5010 AEXT_TRACE(dev
->name
, "cmd %s", command
);
5011 sscanf(data
, "%d %d %s", &id
, &period
, packet
);
5012 AEXT_TRACE(dev
->name
, "id=%d, period=%d, packet=%s", id
, period
, packet
);
5014 ifidx
= dhd_net2idx(dhd
->info
, dev
);
5015 ret
= dhd_conf_mkeep_alive(dhd
, ifidx
, id
, period
, packet
, FALSE
);
5019 ret
= wl_ext_iovar_getbuf(dev
, "mkeep_alive", &id
, sizeof(id
), buf
,
5022 mkeep_alive_pktp
= (wl_mkeep_alive_pkt_t
*) buf
;
5023 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
5025 "Period (msec) :%d\n"
5028 mkeep_alive_pktp
->keep_alive_id
,
5029 dtoh32(mkeep_alive_pktp
->period_msec
),
5030 dtoh16(mkeep_alive_pktp
->len_bytes
));
5031 for (i
=0; i
<mkeep_alive_pktp
->len_bytes
; i
++) {
5032 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
5033 "%02x", mkeep_alive_pktp
->data
[i
]);
5035 AEXT_TRACE(dev
->name
, "command result is %s\n", command
);
5036 ret
= bytes_written
;
5051 wl_ext_tcpka_conn_add(struct net_device
*dev
, char *data
, char *command
,
5055 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
5056 tcpka_conn_t
*tcpka
= NULL
;
5057 uint32 sess_id
= 0, ipid
= 0, srcport
= 0, dstport
= 0, seq
= 0, ack
= 0,
5058 tcpwin
= 0, tsval
= 0, tsecr
= 0, len
= 0, ka_payload_len
= 0;
5059 char dst_mac
[ETHER_ADDR_STR_LEN
], src_ip
[IPV4_ADDR_STR_LEN
],
5060 dst_ip
[IPV4_ADDR_STR_LEN
], ka_payload
[32];
5063 memset(dst_mac
, 0, sizeof(dst_mac
));
5064 memset(src_ip
, 0, sizeof(src_ip
));
5065 memset(dst_ip
, 0, sizeof(dst_ip
));
5066 memset(ka_payload
, 0, sizeof(ka_payload
));
5067 sscanf(data
, "%d %s %s %s %d %d %d %u %u %d %u %u %u %32s",
5068 &sess_id
, dst_mac
, src_ip
, dst_ip
, &ipid
, &srcport
, &dstport
, &seq
,
5069 &ack
, &tcpwin
, &tsval
, &tsecr
, &len
, ka_payload
);
5071 ka_payload_len
= strlen(ka_payload
) / 2;
5072 tcpka
= kmalloc(sizeof(struct tcpka_conn
) + ka_payload_len
, GFP_KERNEL
);
5073 if (tcpka
== NULL
) {
5074 AEXT_ERROR(dev
->name
, "Failed to allocate buffer of %d bytes\n",
5075 sizeof(struct tcpka_conn
) + ka_payload_len
);
5078 memset(tcpka
, 0, sizeof(struct tcpka_conn
) + ka_payload_len
);
5080 tcpka
->sess_id
= sess_id
;
5081 if (!(ret
= bcm_ether_atoe(dst_mac
, &tcpka
->dst_mac
))) {
5082 AEXT_ERROR(dev
->name
, "mac parsing err addr=%s\n", dst_mac
);
5085 if (!bcm_atoipv4(src_ip
, &tcpka
->src_ip
)) {
5086 AEXT_ERROR(dev
->name
, "src_ip parsing err ip=%s\n", src_ip
);
5089 if (!bcm_atoipv4(dst_ip
, &tcpka
->dst_ip
)) {
5090 AEXT_ERROR(dev
->name
, "dst_ip parsing err ip=%s\n", dst_ip
);
5094 tcpka
->srcport
= srcport
;
5095 tcpka
->dstport
= dstport
;
5098 tcpka
->tcpwin
= tcpwin
;
5099 tcpka
->tsval
= tsval
;
5100 tcpka
->tsecr
= tsecr
;
5102 ka_payload_len
= wl_pattern_atoh(ka_payload
, (char *)tcpka
->ka_payload
);
5103 if (ka_payload_len
== -1) {
5104 AEXT_ERROR(dev
->name
,"rejecting ka_payload=%s\n", ka_payload
);
5107 tcpka
->ka_payload_len
= ka_payload_len
;
5109 AEXT_INFO(dev
->name
,
5110 "tcpka_conn_add %d %pM %pM %pM %d %d %d %u %u %d %u %u %u %u \"%s\"\n",
5111 tcpka
->sess_id
, &tcpka
->dst_mac
, &tcpka
->src_ip
, &tcpka
->dst_ip
,
5112 tcpka
->ipid
, tcpka
->srcport
, tcpka
->dstport
, tcpka
->seq
,
5113 tcpka
->ack
, tcpka
->tcpwin
, tcpka
->tsval
, tcpka
->tsecr
,
5114 tcpka
->len
, tcpka
->ka_payload_len
, tcpka
->ka_payload
);
5116 ret
= wl_ext_iovar_setbuf(dev
, "tcpka_conn_add", (char *)tcpka
,
5117 (sizeof(tcpka_conn_t
) + tcpka
->ka_payload_len
- 1),
5118 iovar_buf
, sizeof(iovar_buf
), NULL
);
5128 wl_ext_tcpka_conn_enable(struct net_device
*dev
, char *data
, char *command
,
5131 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
5132 tcpka_conn_sess_t tcpka_conn
;
5134 uint32 sess_id
= 0, flag
, interval
= 0, retry_interval
= 0, retry_count
= 0;
5137 sscanf(data
, "%d %d %d %d %d",
5138 &sess_id
, &flag
, &interval
, &retry_interval
, &retry_count
);
5139 tcpka_conn
.sess_id
= sess_id
;
5140 tcpka_conn
.flag
= flag
;
5141 if (tcpka_conn
.flag
) {
5142 tcpka_conn
.tcpka_timers
.interval
= interval
;
5143 tcpka_conn
.tcpka_timers
.retry_interval
= retry_interval
;
5144 tcpka_conn
.tcpka_timers
.retry_count
= retry_count
;
5146 tcpka_conn
.tcpka_timers
.interval
= 0;
5147 tcpka_conn
.tcpka_timers
.retry_interval
= 0;
5148 tcpka_conn
.tcpka_timers
.retry_count
= 0;
5151 AEXT_INFO(dev
->name
, "tcpka_conn_enable %d %d %d %d %d\n",
5152 tcpka_conn
.sess_id
, tcpka_conn
.flag
,
5153 tcpka_conn
.tcpka_timers
.interval
,
5154 tcpka_conn
.tcpka_timers
.retry_interval
,
5155 tcpka_conn
.tcpka_timers
.retry_count
);
5157 ret
= wl_ext_iovar_setbuf(dev
, "tcpka_conn_enable", (char *)&tcpka_conn
,
5158 sizeof(tcpka_conn_sess_t
), iovar_buf
, sizeof(iovar_buf
), NULL
);
5165 wl_ext_tcpka_conn_info(struct net_device
*dev
, char *data
, char *command
,
5168 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
5169 tcpka_conn_sess_info_t
*info
= NULL
;
5171 int ret
= 0, bytes_written
= 0;
5174 sscanf(data
, "%d", &sess_id
);
5175 AEXT_INFO(dev
->name
, "tcpka_conn_sess_info %d\n", sess_id
);
5176 ret
= wl_ext_iovar_getbuf(dev
, "tcpka_conn_sess_info", (char *)&sess_id
,
5177 sizeof(uint32
), iovar_buf
, sizeof(iovar_buf
), NULL
);
5179 info
= (tcpka_conn_sess_info_t
*) iovar_buf
;
5180 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
5185 sess_id
, info
->ipid
, info
->seq
, info
->ack
);
5186 AEXT_INFO(dev
->name
, "%s\n", command
);
5187 ret
= bytes_written
;
5193 #endif /* WL_EXT_TCPKA */
5196 wl_ext_rsdb_mode(struct net_device
*dev
, char *data
, char *command
,
5199 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
5200 wl_config_t rsdb_mode_cfg
= {1, 0}, *rsdb_p
;
5204 rsdb_mode_cfg
.config
= (int)simple_strtol(data
, NULL
, 0);
5205 ret
= wl_ext_iovar_setbuf(dev
, "rsdb_mode", (char *)&rsdb_mode_cfg
,
5206 sizeof(rsdb_mode_cfg
), iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
5207 AEXT_INFO(dev
->name
, "rsdb_mode %d\n", rsdb_mode_cfg
.config
);
5209 ret
= wl_ext_iovar_getbuf(dev
, "rsdb_mode", NULL
, 0,
5210 iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
5212 rsdb_p
= (wl_config_t
*) iovar_buf
;
5213 ret
= snprintf(command
, total_len
, "%d", rsdb_p
->config
);
5214 AEXT_TRACE(dev
->name
, "command result is %s\n", command
);
5222 wl_ext_recal(struct net_device
*dev
, char *data
, char *command
,
5225 int ret
= 0, i
, nchan
, nssid
= 0;
5226 int params_size
= WL_SCAN_PARAMS_FIXED_SIZE
+ WL_NUMCHANNELS
* sizeof(uint16
);
5227 wl_scan_params_t
*params
= NULL
;
5231 AEXT_TRACE(dev
->name
, "Enter\n");
5234 params_size
+= WL_SCAN_PARAMS_SSID_MAX
* sizeof(wlc_ssid_t
);
5235 params
= (wl_scan_params_t
*) kzalloc(params_size
, GFP_KERNEL
);
5236 if (params
== NULL
) {
5240 memset(params
, 0, params_size
);
5242 wl_ext_get_ioctl_ver(dev
, &ioctl_ver
);
5244 memcpy(¶ms
->bssid
, ðer_bcast
, ETHER_ADDR_LEN
);
5245 params
->bss_type
= DOT11_BSSTYPE_ANY
;
5246 params
->scan_type
= 0;
5247 params
->nprobes
= -1;
5248 params
->active_time
= -1;
5249 params
->passive_time
= -1;
5250 params
->home_time
= -1;
5251 params
->channel_num
= 0;
5253 params
->scan_type
|= WL_SCANFLAGS_PASSIVE
;
5255 params
->channel_list
[0] = wf_channel2chspec(1, WL_CHANSPEC_BW_20
);
5256 params
->channel_list
[1] = wf_channel2chspec(2, WL_CHANSPEC_BW_20
);
5258 params
->nprobes
= htod32(params
->nprobes
);
5259 params
->active_time
= htod32(params
->active_time
);
5260 params
->passive_time
= htod32(params
->passive_time
);
5261 params
->home_time
= htod32(params
->home_time
);
5263 for (i
= 0; i
< nchan
; i
++) {
5264 wl_ext_chspec_host_to_driver(ioctl_ver
, params
->channel_list
[i
]);
5267 p
= (char*)params
->channel_list
+ nchan
* sizeof(uint16
);
5269 params
->channel_num
= htod32((nssid
<< WL_SCAN_PARAMS_NSSID_SHIFT
) |
5270 (nchan
& WL_SCAN_PARAMS_COUNT_MASK
));
5271 params_size
= p
- (char*)params
+ nssid
* sizeof(wlc_ssid_t
);
5273 AEXT_INFO(dev
->name
, "recal\n");
5274 ret
= wl_ext_ioctl(dev
, WLC_SCAN
, params
, params_size
, 1);
5284 wl_ext_add_remove_eventmsg(struct net_device
*ndev
, u16 event
, bool add
)
5286 s8 iovbuf
[WL_EVENTING_MASK_LEN
+ 12];
5287 s8 eventmask
[WL_EVENTING_MASK_LEN
];
5293 /* Setup event_msgs */
5294 err
= wldev_iovar_getbuf(ndev
, "event_msgs", NULL
, 0, iovbuf
, sizeof(iovbuf
), NULL
);
5295 if (unlikely(err
)) {
5296 AEXT_ERROR(ndev
->name
, "Get event_msgs error (%d)\n", err
);
5299 memcpy(eventmask
, iovbuf
, WL_EVENTING_MASK_LEN
);
5301 setbit(eventmask
, event
);
5303 clrbit(eventmask
, event
);
5305 err
= wldev_iovar_setbuf(ndev
, "event_msgs", eventmask
, WL_EVENTING_MASK_LEN
, iovbuf
,
5306 sizeof(iovbuf
), NULL
);
5307 if (unlikely(err
)) {
5308 AEXT_ERROR(ndev
->name
, "Set event_msgs error (%d)\n", err
);
5317 wl_ext_event_msg(struct net_device
*dev
, char *data
,
5318 char *command
, int total_len
)
5320 s8 iovbuf
[WL_EVENTING_MASK_LEN
+ 12];
5321 s8 eventmask
[WL_EVENTING_MASK_LEN
];
5322 int i
, bytes_written
= 0, add
= -1;
5327 /* dhd_priv wl event_msg [offset] [1/0, 1 for add, 0 for remove] */
5328 /* dhd_priv wl event_msg 40 1 */
5330 AEXT_TRACE(dev
->name
, "data = %s\n", data
);
5331 sscanf(data
, "%d %d", &event
, &add
);
5332 /* Setup event_msgs */
5333 bytes_written
= wldev_iovar_getbuf(dev
, "event_msgs", NULL
, 0, iovbuf
,
5334 sizeof(iovbuf
), NULL
);
5335 if (unlikely(bytes_written
)) {
5336 AEXT_ERROR(dev
->name
, "Get event_msgs error (%d)\n", bytes_written
);
5339 memcpy(eventmask
, iovbuf
, WL_EVENTING_MASK_LEN
);
5341 if (isset(eventmask
, event
))
5342 bytes_written
+= snprintf(command
+bytes_written
, total_len
, "1");
5344 bytes_written
+= snprintf(command
+bytes_written
, total_len
, "0");
5345 AEXT_INFO(dev
->name
, "%s\n", command
);
5348 bytes_written
= wl_ext_add_remove_eventmsg(dev
, event
, add
);
5351 /* Setup event_msgs */
5352 bytes_written
= wldev_iovar_getbuf(dev
, "event_msgs", NULL
, 0, iovbuf
,
5353 sizeof(iovbuf
), NULL
);
5354 if (bytes_written
) {
5355 AEXT_ERROR(dev
->name
, "Get event_msgs error (%d)\n", bytes_written
);
5358 vbuf
= (char *)iovbuf
;
5359 bytes_written
+= snprintf(command
+bytes_written
, total_len
, "0x");
5360 for (i
= (sizeof(eventmask
) - 1); i
>= 0; i
--) {
5361 if (vbuf
[i
] || (i
== 0))
5365 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
5366 "%02x", vbuf
[i
] & 0xff);
5368 AEXT_INFO(dev
->name
, "%s\n", command
);
5372 return bytes_written
;
5375 #ifdef PKT_FILTER_SUPPORT
5376 extern void dhd_pktfilter_offload_set(dhd_pub_t
* dhd
, char *arg
);
5377 extern void dhd_pktfilter_offload_delete(dhd_pub_t
*dhd
, int id
);
5378 extern void dhd_pktfilter_offload_enable(dhd_pub_t
* dhd
, char *arg
, int enable
, int master_mode
);
5380 wl_ext_pkt_filter_add(struct net_device
*dev
, char *data
, char *command
,
5383 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
5384 int i
, filter_id
, new_id
= 0, cnt
;
5385 conf_pkt_filter_add_t
*filter_add
= &dhd
->conf
->pkt_filter_add
;
5386 char **pktfilter
= dhd
->pktfilter
;
5390 AEXT_TRACE(dev
->name
, "data = %s\n", data
);
5392 new_id
= simple_strtol(data
, NULL
, 10);
5394 AEXT_ERROR(dev
->name
, "wrong id %d\n", new_id
);
5398 cnt
= dhd
->pktfilter_count
;
5399 for (i
=0; i
<cnt
; i
++) {
5402 filter_id
= simple_strtol(pktfilter
[i
], NULL
, 10);
5403 if (new_id
== filter_id
) {
5404 AEXT_ERROR(dev
->name
, "filter id %d already in list\n", filter_id
);
5409 cnt
= filter_add
->count
;
5410 if (cnt
>= DHD_CONF_FILTER_MAX
) {
5411 AEXT_ERROR(dev
->name
, "not enough filter\n");
5414 for (i
=0; i
<cnt
; i
++) {
5415 filter_id
= simple_strtol(filter_add
->filter
[i
], NULL
, 10);
5416 if (new_id
== filter_id
) {
5417 AEXT_ERROR(dev
->name
, "filter id %d already in list\n", filter_id
);
5422 strcpy(&filter_add
->filter
[cnt
][0], data
);
5423 dhd
->pktfilter
[dhd
->pktfilter_count
] = filter_add
->filter
[cnt
];
5424 filter_add
->count
++;
5425 dhd
->pktfilter_count
++;
5427 dhd_pktfilter_offload_set(dhd
, data
);
5428 AEXT_INFO(dev
->name
, "filter id %d added\n", new_id
);
5435 wl_ext_pkt_filter_delete(struct net_device
*dev
, char *data
, char *command
,
5438 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
5439 int i
, j
, filter_id
, cnt
;
5440 char **pktfilter
= dhd
->pktfilter
;
5441 conf_pkt_filter_add_t
*filter_add
= &dhd
->conf
->pkt_filter_add
;
5442 bool in_filter
= FALSE
;
5446 AEXT_TRACE(dev
->name
, "data = %s\n", data
);
5447 id
= (int)simple_strtol(data
, NULL
, 0);
5449 cnt
= filter_add
->count
;
5450 for (i
=0; i
<cnt
; i
++) {
5451 filter_id
= simple_strtol(filter_add
->filter
[i
], NULL
, 10);
5452 if (id
== filter_id
) {
5454 memset(filter_add
->filter
[i
], 0, PKT_FILTER_LEN
);
5455 for (j
=i
; j
<(cnt
-1); j
++) {
5456 strcpy(filter_add
->filter
[j
], filter_add
->filter
[j
+1]);
5457 memset(filter_add
->filter
[j
+1], 0, PKT_FILTER_LEN
);
5460 filter_add
->count
--;
5461 dhd
->pktfilter_count
--;
5465 cnt
= dhd
->pktfilter_count
;
5466 for (i
=0; i
<cnt
; i
++) {
5469 filter_id
= simple_strtol(pktfilter
[i
], NULL
, 10);
5470 if (id
== filter_id
) {
5472 memset(pktfilter
[i
], 0, strlen(pktfilter
[i
]));
5477 dhd_pktfilter_offload_delete(dhd
, id
);
5478 AEXT_INFO(dev
->name
, "filter id %d deleted\n", id
);
5480 AEXT_ERROR(dev
->name
, "filter id %d not in list\n", id
);
5489 wl_ext_pkt_filter_enable(struct net_device
*dev
, char *data
, char *command
,
5492 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
5493 int err
= 0, id
, enable
;
5494 int i
, filter_id
, cnt
;
5495 char **pktfilter
= dhd
->pktfilter
;
5496 bool in_filter
= FALSE
;
5498 /* dhd_priv wl pkt_filter_enable [id] [1/0] */
5499 /* dhd_priv wl pkt_filter_enable 141 1 */
5501 sscanf(data
, "%d %d", &id
, &enable
);
5503 cnt
= dhd
->pktfilter_count
;
5504 for (i
=0; i
<cnt
; i
++) {
5507 filter_id
= simple_strtol(pktfilter
[i
], NULL
, 10);
5508 if (id
== filter_id
) {
5515 dhd_pktfilter_offload_enable(dhd
, dhd
->pktfilter
[i
],
5516 enable
, dhd_master_mode
);
5517 AEXT_INFO(dev
->name
, "filter id %d %s\n", id
, enable
?"enabled":"disabled");
5519 AEXT_ERROR(dev
->name
, "filter id %d not in list\n", id
);
5526 #endif /* PKT_FILTER_SUPPORT */
5530 wl_ext_send_probreq(struct net_device
*dev
, char *data
, char *command
,
5534 char addr_str
[16], addr
[6];
5535 char iovar_buf
[WLC_IOCTL_SMLEN
]="\0";
5536 char ie_data
[WLC_IOCTL_SMLEN
] = "\0";
5537 wl_probe_params_t params
;
5539 /* dhd_priv wl send_probreq [dest. addr] [OUI+VAL] */
5540 /* dhd_priv wl send_probreq 0x00904c010203 0x00904c01020304050607 */
5542 AEXT_TRACE(dev
->name
, "data = %s\n", data
);
5543 sscanf(data
, "%s %s", addr_str
, ie_data
);
5544 AEXT_TRACE(dev
->name
, "addr=%s, ie=%s\n", addr_str
, ie_data
);
5546 if (strlen(addr_str
) != 14) {
5547 AEXT_ERROR(dev
->name
, "wrong addr %s\n", addr_str
);
5550 wl_pattern_atoh(addr_str
, (char *) addr
);
5551 memset(¶ms
, 0, sizeof(params
));
5552 memcpy(¶ms
.bssid
, addr
, ETHER_ADDR_LEN
);
5553 memcpy(¶ms
.mac
, addr
, ETHER_ADDR_LEN
);
5555 err
= wl_ext_add_del_ie(dev
, VNDR_IE_PRBREQ_FLAG
, ie_data
, "add");
5558 err
= wl_ext_iovar_setbuf(dev
, "sendprb", (char *)¶ms
, sizeof(params
),
5559 iovar_buf
, sizeof(iovar_buf
), NULL
);
5561 wl_ext_add_del_ie(dev
, VNDR_IE_PRBREQ_FLAG
, ie_data
, "del");
5569 wl_ext_send_probresp(struct net_device
*dev
, char *data
, char *command
,
5573 char addr_str
[16], addr
[6];
5574 char iovar_buf
[WLC_IOCTL_SMLEN
]="\0";
5575 char ie_data
[WLC_IOCTL_SMLEN
] = "\0";
5577 /* dhd_priv wl send_probresp [dest. addr] [OUI+VAL] */
5578 /* dhd_priv wl send_probresp 0x00904c010203 0x00904c01020304050607 */
5580 AEXT_TRACE(dev
->name
, "data = %s\n", data
);
5581 sscanf(data
, "%s %s", addr_str
, ie_data
);
5582 AEXT_TRACE(dev
->name
, "addr=%s, ie=%s\n", addr_str
, ie_data
);
5584 if (strlen(addr_str
) != 14) {
5585 AEXT_ERROR(dev
->name
, "wrong addr %s\n", addr_str
);
5588 wl_pattern_atoh(addr_str
, (char *) addr
);
5590 err
= wl_ext_add_del_ie(dev
, VNDR_IE_PRBRSP_FLAG
, ie_data
, "add");
5593 err
= wl_ext_iovar_setbuf(dev
, "send_probresp", addr
, sizeof(addr
),
5594 iovar_buf
, sizeof(iovar_buf
), NULL
);
5596 wl_ext_add_del_ie(dev
, VNDR_IE_PRBRSP_FLAG
, ie_data
, "del");
5604 wl_ext_recv_probreq(struct net_device
*dev
, char *data
, char *command
,
5607 int err
= 0, enable
= 0;
5609 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
5613 2. dhd_priv wl event_msg 44 1
5615 1. dhd_priv wl 86 2;
5616 2. dhd_priv wl event_msg 44 0
5619 AEXT_TRACE(dev
->name
, "data = %s\n", data
);
5620 sscanf(data
, "%d", &enable
);
5622 strcpy(cmd
, "wl 86 0");
5623 err
= wl_ext_wl_iovar(dev
, cmd
, total_len
);
5626 strcpy(cmd
, "wl event_msg 44 1");
5627 err
= wl_ext_wl_iovar(dev
, cmd
, total_len
);
5630 dhd
->recv_probereq
= TRUE
;
5633 strcpy(cmd
, "wl 86 2"); {
5634 wl_ext_wl_iovar(dev
, cmd
, total_len
);
5636 strcpy(cmd
, "wl event_msg 44 0");
5637 wl_ext_wl_iovar(dev
, cmd
, total_len
);
5638 dhd
->recv_probereq
= FALSE
;
5647 wl_ext_recv_probresp(struct net_device
*dev
, char *data
, char *command
,
5650 int err
= 0, enable
= 0;
5654 1. dhd_priv wl pkt_filter_add 150 0 0 0 0xFF 0x50
5655 2. dhd_priv wl pkt_filter_enable 150 1
5656 3. dhd_priv wl mpc 0
5657 4. dhd_priv wl 108 1
5659 1. dhd_priv wl 108 0
5660 2. dhd_priv wl mpc 1
5661 3. dhd_priv wl pkt_filter_disable 150 0
5662 4. dhd_priv pkt_filter_delete 150
5665 AEXT_TRACE(dev
->name
, "data = %s\n", data
);
5666 sscanf(data
, "%d", &enable
);
5668 strcpy(cmd
, "wl pkt_filter_add 150 0 0 0 0xFF 0x50");
5669 err
= wl_ext_wl_iovar(dev
, cmd
, total_len
);
5672 strcpy(cmd
, "wl pkt_filter_enable 150 1");
5673 err
= wl_ext_wl_iovar(dev
, cmd
, total_len
);
5676 strcpy(cmd
, "wl mpc 0");
5677 err
= wl_ext_wl_iovar(dev
, cmd
, total_len
);
5680 strcpy(cmd
, "wl 108 1");
5681 err
= wl_ext_wl_iovar(dev
, cmd
, total_len
);
5683 strcpy(cmd
, "wl 108 0");
5684 wl_ext_wl_iovar(dev
, cmd
, total_len
);
5685 strcpy(cmd
, "wl mpc 1");
5686 wl_ext_wl_iovar(dev
, cmd
, total_len
);
5687 strcpy(cmd
, "wl pkt_filter_enable 150 0");
5688 wl_ext_wl_iovar(dev
, cmd
, total_len
);
5689 strcpy(cmd
, "wl pkt_filter_delete 150");
5690 wl_ext_wl_iovar(dev
, cmd
, total_len
);
5697 #endif /* SENDPROB */
5700 wl_ext_gtk_key_info(struct net_device
*dev
, char *data
, char *command
, int total_len
)
5703 char iovar_buf
[WLC_IOCTL_SMLEN
]="\0";
5704 gtk_keyinfo_t keyinfo
;
5705 bcol_gtk_para_t bcol_keyinfo
;
5707 /* wl gtk_key_info [kck kek replay_ctr] */
5708 /* wl gtk_key_info 001122..FF001122..FF00000000000001 */
5710 memset(&keyinfo
, 0, sizeof(keyinfo
));
5711 memcpy(&keyinfo
, data
, RSN_KCK_LENGTH
+RSN_KEK_LENGTH
+RSN_REPLAY_LEN
);
5712 if (android_msg_level
& ANDROID_INFO_LEVEL
) {
5713 prhex("kck", (uchar
*)keyinfo
.KCK
, RSN_KCK_LENGTH
);
5714 prhex("kek", (uchar
*)keyinfo
.KEK
, RSN_KEK_LENGTH
);
5715 prhex("replay_ctr", (uchar
*)keyinfo
.ReplayCounter
, RSN_REPLAY_LEN
);
5718 memset(&bcol_keyinfo
, 0, sizeof(bcol_keyinfo
));
5719 bcol_keyinfo
.enable
= 1;
5720 bcol_keyinfo
.ptk_len
= 64;
5721 memcpy(&bcol_keyinfo
.ptk
, data
, RSN_KCK_LENGTH
+RSN_KEK_LENGTH
);
5722 err
= wl_ext_iovar_setbuf(dev
, "bcol_gtk_rekey_ptk", &bcol_keyinfo
,
5723 sizeof(bcol_keyinfo
), iovar_buf
, sizeof(iovar_buf
), NULL
);
5728 err
= wl_ext_iovar_setbuf(dev
, "gtk_key_info", &keyinfo
, sizeof(keyinfo
),
5729 iovar_buf
, sizeof(iovar_buf
), NULL
);
5731 AEXT_ERROR(dev
->name
, "failed to set gtk_key_info\n");
5742 wl_ext_wowl_pattern(struct net_device
*dev
, char *data
, char *command
,
5745 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
5748 char mask
[128]="\0", pattern
[128]="\0", add
[4]="\0",
5749 mask_tmp
[128], *pmask_tmp
;
5750 uint32 masksize
, patternsize
, pad_len
= 0;
5751 wl_wowl_pattern2_t
*wowl_pattern2
= NULL
;
5752 wl_wowl_pattern_t
*wowl_pattern
= NULL
;
5753 char *mask_and_pattern
;
5754 wl_wowl_pattern_list_t
*list
;
5756 int ret
= 0, i
, j
, v
;
5759 sscanf(data
, "%s %d %s %s", add
, &offset
, mask_tmp
, pattern
);
5760 if (strcmp(add
, "add") != 0 && strcmp(add
, "clr") != 0) {
5761 AEXT_ERROR(dev
->name
, "first arg should be add or clr\n");
5764 if (!strcmp(add
, "clr")) {
5765 AEXT_INFO(dev
->name
, "wowl_pattern clr\n");
5766 ret
= wl_ext_iovar_setbuf(dev
, "wowl_pattern", add
,
5767 sizeof(add
), iovar_buf
, sizeof(iovar_buf
), NULL
);
5770 masksize
= strlen(mask_tmp
) -2;
5771 AEXT_TRACE(dev
->name
, "0 mask_tmp=%s, masksize=%d\n", mask_tmp
, masksize
);
5775 pad_len
= (16 - masksize
% 16);
5776 for (i
=0; i
<pad_len
; i
++)
5777 strcat(mask_tmp
, "0");
5778 masksize
+= pad_len
;
5779 AEXT_TRACE(dev
->name
, "1 mask_tmp=%s, masksize=%d\n", mask_tmp
, masksize
);
5781 // translate 0x00 to 0, others to 1
5783 pmask_tmp
= &mask_tmp
[2];
5784 for (i
=0; i
<masksize
/2; i
++) {
5785 if(strncmp(&pmask_tmp
[i
*2], "00", 2))
5791 pmask_tmp
[j
] = '\0';
5792 masksize
= masksize
/ 2;
5793 AEXT_TRACE(dev
->name
, "2 mask_tmp=%s, masksize=%d\n", mask_tmp
, masksize
);
5795 // reorder per 8bits
5796 pmask_tmp
= &mask_tmp
[2];
5797 for (i
=0; i
<masksize
/8; i
++) {
5799 for (j
=0; j
<4; j
++) {
5800 c
= pmask_tmp
[i
*8+j
];
5801 pmask_tmp
[i
*8+j
] = pmask_tmp
[(i
+1)*8-j
-1];
5802 pmask_tmp
[(i
+1)*8-j
-1] = c
;
5805 AEXT_TRACE(dev
->name
, "3 mask_tmp=%s, masksize=%d\n", mask_tmp
, masksize
);
5807 // translate 8bits to 1byte
5809 pmask_tmp
= &mask_tmp
[2];
5811 for (i
=0; i
<masksize
; i
++) {
5812 v
= (v
<<1) | (pmask_tmp
[i
]=='1');
5813 if (((i
+1)%4) == 0) {
5815 mask
[j
+2] = v
+ '0';
5817 mask
[j
+2] = (v
-10) + 'a';
5824 AEXT_TRACE(dev
->name
, "4 mask=%s, masksize=%d\n", mask
, masksize
);
5826 patternsize
= (strlen(pattern
)-2)/2;
5827 buf_len
= sizeof(wl_wowl_pattern2_t
) + patternsize
+ masksize
;
5828 wowl_pattern2
= kmalloc(buf_len
, GFP_KERNEL
);
5829 if (wowl_pattern2
== NULL
) {
5830 AEXT_ERROR(dev
->name
, "Failed to allocate buffer of %d bytes\n", buf_len
);
5833 memset(wowl_pattern2
, 0, sizeof(wl_wowl_pattern2_t
));
5835 strncpy(wowl_pattern2
->cmd
, add
, sizeof(add
));
5836 wowl_pattern2
->wowl_pattern
.type
= 0;
5837 wowl_pattern2
->wowl_pattern
.offset
= offset
;
5838 mask_and_pattern
= (char*)wowl_pattern2
+ sizeof(wl_wowl_pattern2_t
);
5840 wowl_pattern2
->wowl_pattern
.masksize
= masksize
;
5841 ret
= wl_pattern_atoh(mask
, mask_and_pattern
);
5843 AEXT_ERROR(dev
->name
, "rejecting mask=%s\n", mask
);
5847 mask_and_pattern
+= wowl_pattern2
->wowl_pattern
.masksize
;
5848 wowl_pattern2
->wowl_pattern
.patternoffset
= sizeof(wl_wowl_pattern_t
) +
5849 wowl_pattern2
->wowl_pattern
.masksize
;
5851 wowl_pattern2
->wowl_pattern
.patternsize
= patternsize
;
5852 ret
= wl_pattern_atoh(pattern
, mask_and_pattern
);
5854 AEXT_ERROR(dev
->name
, "rejecting pattern=%s\n", pattern
);
5858 AEXT_INFO(dev
->name
, "%s %d %s %s\n", add
, offset
, mask
, pattern
);
5860 ret
= wl_ext_iovar_setbuf(dev
, "wowl_pattern", (char *)wowl_pattern2
,
5861 buf_len
, iovar_buf
, sizeof(iovar_buf
), NULL
);
5864 ret
= wl_ext_iovar_getbuf(dev
, "wowl_pattern", NULL
, 0,
5865 iovar_buf
, sizeof(iovar_buf
), NULL
);
5867 list
= (wl_wowl_pattern_list_t
*)iovar_buf
;
5868 ret
= snprintf(command
, total_len
, "#of patterns :%d\n", list
->count
);
5869 ptr
= (uint8
*)list
->pattern
;
5870 for (i
=0; i
<list
->count
; i
++) {
5872 wowl_pattern
= (wl_wowl_pattern_t
*)ptr
;
5873 ret
+= snprintf(command
+ret
, total_len
,
5879 i
+1, (uint32
)wowl_pattern
->id
, wowl_pattern
->offset
,
5880 wowl_pattern
->masksize
);
5881 pattern
= ((uint8
*)wowl_pattern
+ sizeof(wl_wowl_pattern_t
));
5882 for (j
= 0; j
< wowl_pattern
->masksize
; j
++) {
5883 ret
+= snprintf(command
+ret
, total_len
, "%02x", pattern
[j
]);
5885 ret
+= snprintf(command
+ret
, total_len
, "\n");
5886 ret
+= snprintf(command
+ret
, total_len
,
5889 wowl_pattern
->patternsize
);
5891 pattern
= ((uint8
*)wowl_pattern
+ wowl_pattern
->patternoffset
);
5892 for (j
=0; j
<wowl_pattern
->patternsize
; j
++)
5893 ret
+= snprintf(command
+ret
, total_len
, "%02x", pattern
[j
]);
5894 ret
+= snprintf(command
+ret
, total_len
, "\n");
5895 ptr
+= (wowl_pattern
->masksize
+ wowl_pattern
->patternsize
+
5896 sizeof(wl_wowl_pattern_t
));
5899 AEXT_INFO(dev
->name
, "%s\n", command
);
5905 kfree(wowl_pattern2
);
5910 wl_ext_wowl_wakeind(struct net_device
*dev
, char *data
, char *command
,
5913 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
5914 wl_wowl_wakeind_t
*wake
= NULL
;
5919 sscanf(data
, "%s", clr
);
5920 if (!strcmp(clr
, "clear")) {
5921 AEXT_INFO(dev
->name
, "wowl_wakeind clear\n");
5922 ret
= wl_ext_iovar_setbuf(dev
, "wowl_wakeind", clr
, sizeof(clr
),
5923 iovar_buf
, sizeof(iovar_buf
), NULL
);
5925 AEXT_ERROR(dev
->name
, "first arg should be clear\n");
5928 ret
= wl_ext_iovar_getbuf(dev
, "wowl_wakeind", NULL
, 0,
5929 iovar_buf
, sizeof(iovar_buf
), NULL
);
5931 wake
= (wl_wowl_wakeind_t
*) iovar_buf
;
5932 ret
= snprintf(command
, total_len
, "wakeind=0x%x", wake
->ucode_wakeind
);
5933 if (wake
->ucode_wakeind
& WL_WOWL_MAGIC
)
5934 ret
+= snprintf(command
+ret
, total_len
, " (MAGIC packet)");
5935 if (wake
->ucode_wakeind
& WL_WOWL_NET
)
5936 ret
+= snprintf(command
+ret
, total_len
, " (Netpattern)");
5937 if (wake
->ucode_wakeind
& WL_WOWL_DIS
)
5938 ret
+= snprintf(command
+ret
, total_len
, " (Disassoc/Deauth)");
5939 if (wake
->ucode_wakeind
& WL_WOWL_BCN
)
5940 ret
+= snprintf(command
+ret
, total_len
, " (Loss of beacon)");
5941 if (wake
->ucode_wakeind
& WL_WOWL_TCPKEEP_TIME
)
5942 ret
+= snprintf(command
+ret
, total_len
, " (TCPKA timeout)");
5943 if (wake
->ucode_wakeind
& WL_WOWL_TCPKEEP_DATA
)
5944 ret
+= snprintf(command
+ret
, total_len
, " (TCPKA data)");
5945 if (wake
->ucode_wakeind
& WL_WOWL_TCPFIN
)
5946 ret
+= snprintf(command
+ret
, total_len
, " (TCP FIN)");
5947 AEXT_INFO(dev
->name
, "%s\n", command
);
5953 #endif /* WL_EXT_WOWL */
5955 #ifdef WL_GPIO_NOTIFY
5956 typedef struct notify_payload
{
5963 wl_ext_gpio_notify(struct net_device
*dev
, char *data
, char *command
,
5966 s8 iovar_buf
[WLC_IOCTL_SMLEN
];
5967 notify_payload_t notify
, *pnotify
= NULL
;
5968 int i
, ret
= 0, bytes_written
= 0;
5969 char frame_str
[WLC_IOCTL_SMLEN
+3];
5972 memset(¬ify
, 0, sizeof(notify
));
5973 memset(frame_str
, 0, sizeof(frame_str
));
5974 sscanf(data
, "%d %s", ¬ify
.index
, frame_str
);
5976 if (notify
.index
< 0)
5979 if (strlen(frame_str
)) {
5980 notify
.len
= wl_pattern_atoh(frame_str
, notify
.payload
);
5981 if (notify
.len
== -1) {
5982 AEXT_ERROR(dev
->name
, "rejecting pattern=%s\n", frame_str
);
5985 AEXT_INFO(dev
->name
, "index=%d, len=%d\n", notify
.index
, notify
.len
);
5986 if (android_msg_level
& ANDROID_INFO_LEVEL
)
5987 prhex("payload", (uchar
*)notify
.payload
, notify
.len
);
5988 ret
= wl_ext_iovar_setbuf(dev
, "bcol_gpio_noti", (char *)¬ify
,
5989 sizeof(notify
), iovar_buf
, WLC_IOCTL_SMLEN
, NULL
);
5991 AEXT_INFO(dev
->name
, "index=%d\n", notify
.index
);
5992 ret
= wl_ext_iovar_getbuf(dev
, "bcol_gpio_noti", ¬ify
.index
,
5993 sizeof(notify
.index
), iovar_buf
, sizeof(iovar_buf
), NULL
);
5995 pnotify
= (notify_payload_t
*)iovar_buf
;
5996 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
6000 for (i
=0; i
<pnotify
->len
; i
++) {
6001 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
6002 "%02x", pnotify
->payload
[i
]);
6004 AEXT_TRACE(dev
->name
, "command result is\n%s\n", command
);
6005 ret
= bytes_written
;
6013 #endif /* WL_GPIO_NOTIFY */
6016 typedef struct csi_config
{
6017 /* Peer device mac address. */
6018 struct ether_addr addr
;
6019 /* BW to be used in the measurements. This needs to be supported both by the */
6020 /* device itself and the peer. */
6022 /* Time interval between measurements (units: 1 ms). */
6028 typedef struct csi_list
{
6030 csi_config_t configs
[1];
6034 wl_ether_atoe(const char *a
, struct ether_addr
*n
)
6039 memset(n
, 0, ETHER_ADDR_LEN
);
6041 n
->octet
[i
++] = (uint8
)strtoul(a
, &c
, 16);
6042 if (!*c
++ || i
== ETHER_ADDR_LEN
)
6046 return (i
== ETHER_ADDR_LEN
);
6050 wl_ext_csi(struct net_device
*dev
, char *data
, char *command
, int total_len
)
6052 csi_config_t csi
, *csip
;
6053 csi_list_t
*csi_list
;
6054 int ret
= -1, period
=-1, i
;
6055 char mac
[32], *buf
= NULL
;
6056 struct ether_addr ea
;
6057 int bytes_written
= 0;
6059 buf
= kmalloc(WLC_IOCTL_SMLEN
, GFP_KERNEL
);
6061 AEXT_ERROR(dev
->name
, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN
);
6064 memset(buf
, 0, WLC_IOCTL_SMLEN
);
6067 sscanf(data
, "%s %d", mac
, &period
);
6068 ret
= wl_ether_atoe(mac
, &ea
);
6070 AEXT_ERROR(dev
->name
, "rejecting mac=%s, ret=%d\n", mac
, ret
);
6073 AEXT_TRACE(dev
->name
, "mac=%pM, period=%d", &ea
, period
);
6075 memset(&csi
, 0, sizeof(csi_config_t
));
6076 bcopy(&ea
, &csi
.addr
, ETHER_ADDR_LEN
);
6077 csi
.period
= period
;
6078 ret
= wl_ext_iovar_setbuf(dev
, "csi", (char *)&csi
, sizeof(csi
),
6079 buf
, WLC_IOCTL_SMLEN
, NULL
);
6080 } else if (period
== 0) {
6081 memset(&csi
, 0, sizeof(csi_config_t
));
6082 bcopy(&ea
, &csi
.addr
, ETHER_ADDR_LEN
);
6083 ret
= wl_ext_iovar_setbuf(dev
, "csi_del", (char *)&csi
, sizeof(csi
),
6084 buf
, WLC_IOCTL_SMLEN
, NULL
);
6086 ret
= wl_ext_iovar_getbuf(dev
, "csi", &ea
, ETHER_ADDR_LEN
, buf
,
6087 WLC_IOCTL_SMLEN
, NULL
);
6089 csip
= (csi_config_t
*) buf
;
6090 /* Dump all lists */
6091 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
6096 &csip
->addr
, csip
->period
, csip
->bw
, csip
->method
);
6097 AEXT_TRACE(dev
->name
, "command result is %s\n", command
);
6098 ret
= bytes_written
;
6103 ret
= wl_ext_iovar_getbuf(dev
, "csi_list", NULL
, 0, buf
, WLC_IOCTL_SMLEN
, NULL
);
6105 csi_list
= (csi_list_t
*)buf
;
6106 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
6107 "Total number :%d\n", csi_list
->cnt
);
6108 for (i
=0; i
<csi_list
->cnt
; i
++) {
6109 csip
= &csi_list
->configs
[i
];
6110 bytes_written
+= snprintf(command
+bytes_written
, total_len
,
6116 i
+1, &csip
->addr
, csip
->period
, csip
->bw
, csip
->method
);
6118 AEXT_TRACE(dev
->name
, "command result is %s\n", command
);
6119 ret
= bytes_written
;
6128 #endif /* CSI_SUPPORT */
6130 typedef int (wl_ext_tpl_parse_t
)(struct net_device
*dev
, char *data
, char *command
,
6133 typedef struct wl_ext_iovar_tpl_t
{
6137 wl_ext_tpl_parse_t
*parse
;
6138 } wl_ext_iovar_tpl_t
;
6140 const wl_ext_iovar_tpl_t wl_ext_iovar_tpl_list
[] = {
6141 {WLC_GET_VAR
, WLC_SET_VAR
, "event_msg", wl_ext_event_msg
},
6142 {WLC_GET_VAR
, WLC_SET_VAR
, "gtk_key_info", wl_ext_gtk_key_info
},
6143 {WLC_GET_VAR
, WLC_SET_VAR
, "recal", wl_ext_recal
},
6144 {WLC_GET_VAR
, WLC_SET_VAR
, "rsdb_mode", wl_ext_rsdb_mode
},
6145 {WLC_GET_VAR
, WLC_SET_VAR
, "mkeep_alive", wl_ext_mkeep_alive
},
6146 #ifdef PKT_FILTER_SUPPORT
6147 {WLC_GET_VAR
, WLC_SET_VAR
, "pkt_filter_add", wl_ext_pkt_filter_add
},
6148 {WLC_GET_VAR
, WLC_SET_VAR
, "pkt_filter_delete", wl_ext_pkt_filter_delete
},
6149 {WLC_GET_VAR
, WLC_SET_VAR
, "pkt_filter_enable", wl_ext_pkt_filter_enable
},
6150 #endif /* PKT_FILTER_SUPPORT */
6151 #if defined(WL_EXT_IAPSTA) && defined(WLMESH)
6152 {WLC_GET_VAR
, WLC_SET_VAR
, "mesh_peer_status", wl_ext_mesh_peer_status
},
6153 #endif /* WL_EXT_IAPSTA && WLMESH */
6155 {WLC_GET_VAR
, WLC_SET_VAR
, "send_probreq", wl_ext_send_probreq
},
6156 {WLC_GET_VAR
, WLC_SET_VAR
, "send_probresp", wl_ext_send_probresp
},
6157 {WLC_GET_VAR
, WLC_SET_VAR
, "recv_probreq", wl_ext_recv_probreq
},
6158 {WLC_GET_VAR
, WLC_SET_VAR
, "recv_probresp", wl_ext_recv_probresp
},
6159 #endif /* SENDPROB */
6161 {WLC_GET_VAR
, WLC_SET_VAR
, "tcpka_conn_add", wl_ext_tcpka_conn_add
},
6162 {WLC_GET_VAR
, WLC_SET_VAR
, "tcpka_conn_enable", wl_ext_tcpka_conn_enable
},
6163 {WLC_GET_VAR
, WLC_SET_VAR
, "tcpka_conn_sess_info", wl_ext_tcpka_conn_info
},
6164 #endif /* WL_EXT_TCPKA */
6166 {WLC_GET_VAR
, WLC_SET_VAR
, "wowl_pattern", wl_ext_wowl_pattern
},
6167 {WLC_GET_VAR
, WLC_SET_VAR
, "wowl_wakeind", wl_ext_wowl_wakeind
},
6168 #endif /* WL_EXT_WOWL */
6170 {WLC_GET_VAR
, WLC_SET_VAR
, "dhcpc_dump", wl_ext_dhcpc_dump
},
6171 {WLC_GET_VAR
, WLC_SET_VAR
, "dhcpc_param", wl_ext_dhcpc_param
},
6173 #ifdef WL_GPIO_NOTIFY
6174 {WLC_GET_VAR
, WLC_SET_VAR
, "bcol_gpio_noti", wl_ext_gpio_notify
},
6175 #endif /* WL_GPIO_NOTIFY */
6177 {WLC_GET_VAR
, WLC_SET_VAR
, "csi", wl_ext_csi
},
6178 #endif /* CSI_SUPPORT */
6182 Ex: dhd_priv wl [cmd] [val]
6189 wl_ext_wl_iovar(struct net_device
*dev
, char *command
, int total_len
)
6191 int cmd
, val
, ret
= -1, i
;
6192 char name
[32], *pch
, *pick_tmp
, *data
;
6193 int bytes_written
=-1;
6194 const wl_ext_iovar_tpl_t
*tpl
= wl_ext_iovar_tpl_list
;
6195 int tpl_count
= ARRAY_SIZE(wl_ext_iovar_tpl_list
);
6197 AEXT_TRACE(dev
->name
, "cmd %s\n", command
);
6200 pch
= bcmstrtok(&pick_tmp
, " ", 0); // pick wl
6201 if (!pch
|| strncmp(pch
, "wl", 2))
6204 pch
= bcmstrtok(&pick_tmp
, " ", 0); // pick cmd
6208 memset(name
, 0 , sizeof (name
));
6209 cmd
= (int)simple_strtol(pch
, NULL
, 0);
6213 data
= bcmstrtok(&pick_tmp
, "", 0); // pick data
6214 if (data
&& cmd
== 0) {
6216 } else if (cmd
== 0) {
6220 /* look for a matching code in the table */
6221 for (i
= 0; i
< tpl_count
; i
++, tpl
++) {
6222 if ((tpl
->get
== cmd
|| tpl
->set
== cmd
) && !strcmp(tpl
->name
, name
))
6225 if (i
< tpl_count
&& tpl
->parse
) {
6226 ret
= tpl
->parse(dev
, data
, command
, total_len
);
6228 if (cmd
== WLC_SET_VAR
) {
6229 val
= (int)simple_strtol(data
, NULL
, 0);
6230 AEXT_INFO(dev
->name
, "set %s %d\n", name
, val
);
6231 ret
= wl_ext_iovar_setint(dev
, name
, val
);
6232 } else if (cmd
== WLC_GET_VAR
) {
6233 AEXT_INFO(dev
->name
, "get %s\n", name
);
6234 ret
= wl_ext_iovar_getint(dev
, name
, &val
);
6236 bytes_written
= snprintf(command
, total_len
, "%d", val
);
6237 AEXT_INFO(dev
->name
, "command result is %s\n", command
);
6238 ret
= bytes_written
;
6241 val
= (int)simple_strtol(data
, NULL
, 0);
6242 AEXT_INFO(dev
->name
, "set %d %d\n", cmd
, val
);
6243 ret
= wl_ext_ioctl(dev
, cmd
, &val
, sizeof(val
), TRUE
);
6245 AEXT_INFO(dev
->name
, "get %d\n", cmd
);
6246 ret
= wl_ext_ioctl(dev
, cmd
, &val
, sizeof(val
), FALSE
);
6248 bytes_written
= snprintf(command
, total_len
, "%d", val
);
6249 AEXT_INFO(dev
->name
, "command result is %s\n", command
);
6250 ret
= bytes_written
;
6260 wl_android_ext_priv_cmd(struct net_device
*net
, char *command
,
6261 int total_len
, int *bytes_written
)
6265 if (strnicmp(command
, CMD_CHANNELS
, strlen(CMD_CHANNELS
)) == 0) {
6266 *bytes_written
= wl_ext_channels(net
, command
, total_len
);
6268 else if (strnicmp(command
, CMD_CHANNEL
, strlen(CMD_CHANNEL
)) == 0) {
6269 *bytes_written
= wl_ext_channel(net
, command
, total_len
);
6271 else if (strnicmp(command
, CMD_ROAM_TRIGGER
, strlen(CMD_ROAM_TRIGGER
)) == 0) {
6272 *bytes_written
= wl_ext_roam_trigger(net
, command
, total_len
);
6274 else if (strnicmp(command
, CMD_PM
, strlen(CMD_PM
)) == 0) {
6275 *bytes_written
= wl_ext_pm(net
, command
, total_len
);
6277 else if (strnicmp(command
, CMD_MONITOR
, strlen(CMD_MONITOR
)) == 0) {
6278 *bytes_written
= wl_ext_monitor(net
, command
, total_len
);
6280 else if (strnicmp(command
, CMD_SET_SUSPEND_BCN_LI_DTIM
, strlen(CMD_SET_SUSPEND_BCN_LI_DTIM
)) == 0) {
6282 bcn_li_dtim
= (int)simple_strtol((command
+ strlen(CMD_SET_SUSPEND_BCN_LI_DTIM
) + 1), NULL
, 10);
6283 *bytes_written
= net_os_set_suspend_bcn_li_dtim(net
, bcn_li_dtim
);
6285 #ifdef WL_EXT_IAPSTA
6286 else if (strnicmp(command
, CMD_IAPSTA_INIT
, strlen(CMD_IAPSTA_INIT
)) == 0 ||
6287 strnicmp(command
, CMD_ISAM_INIT
, strlen(CMD_ISAM_INIT
)) == 0) {
6288 *bytes_written
= wl_ext_isam_init(net
, command
, total_len
);
6290 else if (strnicmp(command
, CMD_IAPSTA_CONFIG
, strlen(CMD_IAPSTA_CONFIG
)) == 0 ||
6291 strnicmp(command
, CMD_ISAM_CONFIG
, strlen(CMD_ISAM_CONFIG
)) == 0) {
6292 *bytes_written
= wl_ext_iapsta_config(net
, command
, total_len
);
6294 else if (strnicmp(command
, CMD_IAPSTA_ENABLE
, strlen(CMD_IAPSTA_ENABLE
)) == 0 ||
6295 strnicmp(command
, CMD_ISAM_ENABLE
, strlen(CMD_ISAM_ENABLE
)) == 0) {
6296 *bytes_written
= wl_ext_iapsta_enable(net
, command
, total_len
);
6298 else if (strnicmp(command
, CMD_IAPSTA_DISABLE
, strlen(CMD_IAPSTA_DISABLE
)) == 0 ||
6299 strnicmp(command
, CMD_ISAM_DISABLE
, strlen(CMD_ISAM_DISABLE
)) == 0) {
6300 *bytes_written
= wl_ext_iapsta_disable(net
, command
, total_len
);
6302 else if (strnicmp(command
, CMD_ISAM_STATUS
, strlen(CMD_ISAM_STATUS
)) == 0) {
6303 *bytes_written
= wl_ext_isam_status(net
, command
, total_len
);
6305 else if (strnicmp(command
, CMD_ISAM_PARAM
, strlen(CMD_ISAM_PARAM
)) == 0) {
6306 *bytes_written
= wl_ext_isam_param(net
, command
, total_len
);
6308 #if defined(WLMESH) && defined(WL_ESCAN)
6309 else if (strnicmp(command
, CMD_ISAM_PEER_PATH
, strlen(CMD_ISAM_PEER_PATH
)) == 0) {
6310 *bytes_written
= wl_ext_isam_peer_path(net
, command
, total_len
);
6312 #endif /* WLMESH && WL_ESCAN */
6313 #endif /* WL_EXT_IAPSTA */
6315 else if (strnicmp(command
, CMD_AUTOCHANNEL
, strlen(CMD_AUTOCHANNEL
)) == 0) {
6316 *bytes_written
= wl_cfg80211_autochannel(net
, command
, total_len
);
6318 #endif /* WL_CFG80211 */
6319 #if defined(WL_WIRELESS_EXT) && defined(WL_ESCAN)
6320 else if (strnicmp(command
, CMD_AUTOCHANNEL
, strlen(CMD_AUTOCHANNEL
)) == 0) {
6321 *bytes_written
= wl_iw_autochannel(net
, command
, total_len
);
6323 #endif /* WL_WIRELESS_EXT && WL_ESCAN */
6324 else if (strnicmp(command
, CMD_WLMSGLEVEL
, strlen(CMD_WLMSGLEVEL
)) == 0) {
6325 *bytes_written
= wl_ext_wlmsglevel(net
, command
, total_len
);
6327 else if (strnicmp(command
, CMD_WL
, strlen(CMD_WL
)) == 0) {
6328 *bytes_written
= wl_ext_wl_iovar(net
, command
, total_len
);
6336 #if defined(WL_CFG80211) || defined(WL_ESCAN)
6338 wl_ext_get_distance(struct net_device
*net
, u32 band
)
6340 u32 bw
= WL_CHANSPEC_BW_20
;
6341 s32 bw_cap
= 0, distance
= 0;
6346 char buf
[WLC_IOCTL_SMLEN
]="\0";
6350 err
= wl_ext_iovar_getbuf(net
, "bw_cap", ¶m
, sizeof(param
), buf
,
6353 if (err
!= BCME_UNSUPPORTED
) {
6354 AEXT_ERROR(net
->name
, "bw_cap failed, %d\n", err
);
6357 err
= wl_ext_iovar_getint(net
, "mimo_bw_cap", &bw_cap
);
6358 if (bw_cap
!= WLC_N_BW_20ALL
)
6359 bw
= WL_CHANSPEC_BW_40
;
6362 if (WL_BW_CAP_80MHZ(buf
[0]))
6363 bw
= WL_CHANSPEC_BW_80
;
6364 else if (WL_BW_CAP_40MHZ(buf
[0]))
6365 bw
= WL_CHANSPEC_BW_40
;
6367 bw
= WL_CHANSPEC_BW_20
;
6370 if (bw
== WL_CHANSPEC_BW_20
)
6372 else if (bw
== WL_CHANSPEC_BW_40
)
6374 else if (bw
== WL_CHANSPEC_BW_80
)
6378 AEXT_INFO(net
->name
, "bw=0x%x, distance=%d\n", bw
, distance
);
6384 wl_ext_get_best_channel(struct net_device
*net
,
6385 #if defined(BSSCACHE)
6386 wl_bss_cache_ctrl_t
*bss_cache_ctrl
,
6388 struct wl_scan_results
*bss_list
,
6389 #endif /* BSSCACHE */
6390 int ioctl_ver
, int *best_2g_ch
, int *best_5g_ch
6393 struct wl_bss_info
*bi
= NULL
; /* must be initialized */
6395 #if defined(BSSCACHE)
6396 wl_bss_cache_t
*node
;
6397 #endif /* BSSCACHE */
6398 int b_band
[CH_MAX_2G_CHANNEL
]={0}, a_band1
[4]={0}, a_band4
[5]={0};
6399 s32 cen_ch
, distance
, distance_2g
, distance_5g
, ch
, min_ap
=999;
6400 u8 valid_chan_list
[sizeof(u32
)*(WL_NUMCHANNELS
+ 1)];
6401 wl_uint32_list_t
*list
;
6403 chanspec_t chanspec
;
6404 struct dhd_pub
*dhd
= dhd_get_pub(net
);
6406 memset(b_band
, -1, sizeof(b_band
));
6407 memset(a_band1
, -1, sizeof(a_band1
));
6408 memset(a_band4
, -1, sizeof(a_band4
));
6410 memset(valid_chan_list
, 0, sizeof(valid_chan_list
));
6411 list
= (wl_uint32_list_t
*)(void *) valid_chan_list
;
6412 list
->count
= htod32(WL_NUMCHANNELS
);
6413 ret
= wl_ext_ioctl(net
, WLC_GET_VALID_CHANNELS
, &valid_chan_list
,
6414 sizeof(valid_chan_list
), 0);
6416 AEXT_ERROR(net
->name
, "get channels failed with %d\n", ret
);
6419 for (i
= 0; i
< dtoh32(list
->count
); i
++) {
6420 ch
= dtoh32(list
->element
[i
]);
6421 if (!dhd_conf_match_channel(dhd
, ch
))
6423 if (ch
< CH_MAX_2G_CHANNEL
)
6426 a_band1
[(ch
-36)/4] = 0;
6427 else if (ch
>= 149 && ch
<= 161)
6428 a_band4
[(ch
-149)/4] = 0;
6432 distance_2g
= wl_ext_get_distance(net
, WLC_BAND_2G
);
6433 distance_5g
= wl_ext_get_distance(net
, WLC_BAND_5G
);
6435 #if defined(BSSCACHE)
6436 node
= bss_cache_ctrl
->m_cache_head
;
6437 for (i
=0; node
&& i
<256; i
++)
6439 for (i
=0; i
< bss_list
->count
; i
++)
6440 #endif /* BSSCACHE */
6442 #if defined(BSSCACHE)
6443 bi
= node
->results
.bss_info
;
6445 bi
= bi
? (wl_bss_info_t
*)((uintptr
)bi
+ dtoh32(bi
->length
)) : bss_list
->bss_info
;
6446 #endif /* BSSCACHE */
6447 chanspec
= wl_ext_chspec_driver_to_host(ioctl_ver
, bi
->chanspec
);
6448 cen_ch
= CHSPEC_CHANNEL(bi
->chanspec
);
6450 if (CHSPEC_IS20(chanspec
))
6452 else if (CHSPEC_IS40(chanspec
))
6454 else if (CHSPEC_IS80(chanspec
))
6459 if (CHSPEC_IS2G(chanspec
)) {
6460 distance
+= distance_2g
;
6461 for (j
=0; j
<ARRAYSIZE(b_band
); j
++) {
6462 if (b_band
[j
] >= 0 && abs(cen_ch
-(1+j
)) <= distance
)
6466 distance
+= distance_5g
;
6468 for (j
=0; j
<ARRAYSIZE(a_band1
); j
++) {
6469 if (a_band1
[j
] >= 0 && abs(cen_ch
-(36+j
*4)) <= distance
)
6472 } else if (cen_ch
>= 149) {
6473 for (j
=0; j
<ARRAYSIZE(a_band4
); j
++) {
6474 if (a_band4
[j
] >= 0 && abs(cen_ch
-(149+j
*4)) <= distance
)
6479 #if defined(BSSCACHE)
6481 #endif /* BSSCACHE */
6486 for (i
=0; i
<CH_MAX_2G_CHANNEL
; i
++) {
6487 if(b_band
[i
] < min_ap
&& b_band
[i
] >= 0) {
6494 for (i
=0; i
<ARRAYSIZE(a_band1
); i
++) {
6495 if(a_band1
[i
] < min_ap
&& a_band1
[i
] >= 0) {
6496 min_ap
= a_band1
[i
];
6497 *best_5g_ch
= i
*4 + 36;
6500 for (i
=0; i
<ARRAYSIZE(a_band4
); i
++) {
6501 if(a_band4
[i
] < min_ap
&& a_band4
[i
] >= 0) {
6502 min_ap
= a_band4
[i
];
6503 *best_5g_ch
= i
*4 + 149;
6507 if (android_msg_level
& ANDROID_INFO_LEVEL
) {
6508 struct bcmstrbuf strbuf
;
6509 char *tmp_buf
= NULL
;
6510 tmp_buf
= kmalloc(WLC_IOCTL_SMLEN
, GFP_KERNEL
);
6511 if (tmp_buf
== NULL
) {
6512 AEXT_ERROR(net
->name
, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN
);
6515 bcm_binit(&strbuf
, tmp_buf
, WLC_IOCTL_SMLEN
);
6516 for (j
=0; j
<ARRAYSIZE(b_band
); j
++)
6517 bcm_bprintf(&strbuf
, "%d/%d, ", b_band
[j
], 1+j
);
6518 bcm_bprintf(&strbuf
, "\n");
6519 for (j
=0; j
<ARRAYSIZE(a_band1
); j
++)
6520 bcm_bprintf(&strbuf
, "%d/%d, ", a_band1
[j
], 36+j
*4);
6521 bcm_bprintf(&strbuf
, "\n");
6522 for (j
=0; j
<ARRAYSIZE(a_band4
); j
++)
6523 bcm_bprintf(&strbuf
, "%d/%d, ", a_band4
[j
], 149+j
*4);
6524 bcm_bprintf(&strbuf
, "\n");
6525 bcm_bprintf(&strbuf
, "best_2g_ch=%d, best_5g_ch=%d\n",
6526 *best_2g_ch
, *best_5g_ch
);
6527 AEXT_INFO(net
->name
, "\n%s", strbuf
.origbuf
);
6536 #endif /* WL_CFG80211 || WL_ESCAN */
6539 #define APCS_MAX_RETRY 10
6541 wl_ext_fw_apcs(struct net_device
*dev
, uint32 band
)
6543 int channel
= 0, chosen
= 0, retry
= 0, ret
= 0, spect
= 0;
6547 ret
= wldev_ioctl_get(dev
, WLC_GET_SPECT_MANAGMENT
, &spect
, sizeof(spect
));
6549 AEXT_ERROR(dev
->name
, "ACS: error getting the spect, ret=%d\n", ret
);
6554 ret
= wl_android_set_spect(dev
, 0);
6556 AEXT_ERROR(dev
->name
, "ACS: error while setting spect, ret=%d\n", ret
);
6561 reqbuf
= kmalloc(CHANSPEC_BUF_SIZE
, GFP_KERNEL
);
6562 if (reqbuf
== NULL
) {
6563 AEXT_ERROR(dev
->name
, "failed to allocate chanspec buffer\n");
6566 memset(reqbuf
, 0, CHANSPEC_BUF_SIZE
);
6568 if (band
== WLC_BAND_AUTO
) {
6569 AEXT_INFO(dev
->name
, "ACS full channel scan \n");
6570 reqbuf
[0] = htod32(0);
6571 } else if (band
== WLC_BAND_5G
) {
6572 AEXT_INFO(dev
->name
, "ACS 5G band scan \n");
6573 if ((ret
= wl_cfg80211_get_chanspecs_5g(dev
, reqbuf
, CHANSPEC_BUF_SIZE
)) < 0) {
6574 AEXT_ERROR(dev
->name
, "ACS 5g chanspec retreival failed! \n");
6577 } else if (band
== WLC_BAND_2G
) {
6579 * If channel argument is not provided/ argument 20 is provided,
6580 * Restrict channel to 2GHz, 20MHz BW, No SB
6582 AEXT_INFO(dev
->name
, "ACS 2G band scan \n");
6583 if ((ret
= wl_cfg80211_get_chanspecs_2g(dev
, reqbuf
, CHANSPEC_BUF_SIZE
)) < 0) {
6584 AEXT_ERROR(dev
->name
, "ACS 2g chanspec retreival failed! \n");
6588 AEXT_ERROR(dev
->name
, "ACS: No band chosen\n");
6592 buf_size
= (band
== WLC_BAND_AUTO
) ? sizeof(int) : CHANSPEC_BUF_SIZE
;
6593 ret
= wldev_ioctl_set(dev
, WLC_START_CHANNEL_SEL
, (void *)reqbuf
,
6596 AEXT_ERROR(dev
->name
, "can't start auto channel scan, err = %d\n", ret
);
6601 /* Wait for auto channel selection, max 3000 ms */
6602 if ((band
== WLC_BAND_2G
) || (band
== WLC_BAND_5G
)) {
6606 * Full channel scan at the minimum takes 1.2secs
6607 * even with parallel scan. max wait time: 3500ms
6612 retry
= APCS_MAX_RETRY
;
6614 ret
= wldev_ioctl_get(dev
, WLC_GET_CHANNEL_SEL
, &chosen
,
6619 chosen
= dtoh32(chosen
);
6625 #ifdef D11AC_IOTYPES
6626 if (wl_cfg80211_get_ioctl_version() == 1) {
6627 channel
= LCHSPEC_CHANNEL((chanspec_t
)chosen
);
6629 channel
= CHSPEC_CHANNEL((chanspec_t
)chosen
);
6632 channel
= CHSPEC_CHANNEL((chanspec_t
)chosen
);
6633 #endif /* D11AC_IOTYPES */
6634 apcs_band
= (band
== WLC_BAND_AUTO
) ? WLC_BAND_2G
: band
;
6635 chosen_band
= (channel
<= CH_MAX_2G_CHANNEL
) ? WLC_BAND_2G
: WLC_BAND_5G
;
6636 if (apcs_band
== chosen_band
) {
6637 WL_MSG(dev
->name
, "selected channel = %d\n", channel
);
6641 AEXT_INFO(dev
->name
, "%d tried, ret = %d, chosen = 0x%x\n",
6642 (APCS_MAX_RETRY
- retry
), ret
, chosen
);
6648 if ((ret
= wl_android_set_spect(dev
, spect
) < 0)) {
6649 AEXT_ERROR(dev
->name
, "ACS: error while setting spect\n");
6659 #endif /* WL_CFG80211 */
6663 wl_ext_drv_apcs(struct net_device
*dev
, uint32 band
)
6665 int ret
= 0, channel
= 0;
6666 struct dhd_pub
*dhd
= dhd_get_pub(dev
);
6667 struct wl_escan_info
*escan
= NULL
;
6668 int retry
= 0, retry_max
, retry_interval
= 250, up
= 1;
6670 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
6671 #endif /* WL_CFG80211 */
6675 retry_max
= WL_ESCAN_TIMER_INTERVAL_MS
/retry_interval
;
6676 ret
= wldev_ioctl_get(dev
, WLC_GET_UP
, &up
, sizeof(s32
));
6677 if (ret
< 0 || up
== 0) {
6678 ret
= wldev_ioctl_set(dev
, WLC_UP
, &up
, sizeof(s32
));
6682 if (escan
->escan_state
== ESCAN_STATE_SCANING
6684 || wl_get_drv_status_all(cfg
, SCANNING
)
6688 AEXT_INFO(dev
->name
, "Scanning %d tried, ret = %d\n",
6689 (retry_max
- retry
), ret
);
6691 escan
->autochannel
= 1;
6692 ret
= wl_escan_set_scan(dev
, dhd
, NULL
, 0, TRUE
);
6696 OSL_SLEEP(retry_interval
);
6698 if ((retry
== 0) || (ret
< 0))
6702 if (escan
->escan_state
== ESCAN_STATE_IDLE
) {
6703 if (band
== WLC_BAND_5G
)
6704 channel
= escan
->best_5g_ch
;
6706 channel
= escan
->best_2g_ch
;
6707 WL_MSG(dev
->name
, "selected channel = %d\n", channel
);
6710 AEXT_INFO(dev
->name
, "escan_state=%d, %d tried, ret = %d\n",
6711 escan
->escan_state
, (retry_max
- retry
), ret
);
6712 OSL_SLEEP(retry_interval
);
6714 if ((retry
== 0) || (ret
< 0))
6720 escan
->autochannel
= 0;
6724 #endif /* WL_ESCAN */
6727 wl_ext_autochannel(struct net_device
*dev
, uint acs
, uint32 band
)
6730 uint16 chan_2g
, chan_5g
;
6732 AEXT_INFO(dev
->name
, "acs=0x%x, band=%d \n", acs
, band
);
6735 if (acs
& ACS_FW_BIT
) {
6737 ret
= wldev_ioctl_get(dev
, WLC_GET_CHANNEL_SEL
, &channel
, sizeof(channel
));
6739 if (ret
!= BCME_UNSUPPORTED
)
6740 channel
= wl_ext_fw_apcs(dev
, band
);
6747 if (acs
& ACS_DRV_BIT
)
6748 channel
= wl_ext_drv_apcs(dev
, band
);
6749 #endif /* WL_ESCAN */
6752 wl_ext_get_default_chan(dev
, &chan_2g
, &chan_5g
, TRUE
);
6753 if (band
== WLC_BAND_5G
) {
6758 AEXT_ERROR(dev
->name
, "ACS failed. Fall back to default channel (%d) \n", channel
);
6764 #if defined(RSSIAVG)
6766 wl_free_rssi_cache(wl_rssi_cache_ctrl_t
*rssi_cache_ctrl
)
6768 wl_rssi_cache_t
*node
, *cur
, **rssi_head
;
6771 rssi_head
= &rssi_cache_ctrl
->m_cache_head
;
6775 AEXT_INFO("wlan", "Free %d with BSSID %pM\n", i
, &node
->BSSID
);
6785 wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t
*rssi_cache_ctrl
)
6787 wl_rssi_cache_t
*node
, *prev
, **rssi_head
;
6788 int i
= -1, tmp
= 0;
6789 struct osl_timespec now
;
6791 osl_do_gettimeofday(&now
);
6793 rssi_head
= &rssi_cache_ctrl
->m_cache_head
;
6798 if (now
.tv_sec
> node
->tv
.tv_sec
) {
6799 if (node
== *rssi_head
) {
6801 *rssi_head
= node
->next
;
6804 prev
->next
= node
->next
;
6806 AEXT_INFO("wlan", "Del %d with BSSID %pM\n", i
, &node
->BSSID
);
6822 wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t
*rssi_cache_ctrl
,
6825 wl_rssi_cache_t
*node
, *prev
, **rssi_head
;
6826 int i
= -1, tmp
= 0;
6828 rssi_head
= &rssi_cache_ctrl
->m_cache_head
;
6833 if (!memcmp(&node
->BSSID
, bssid
, ETHER_ADDR_LEN
)) {
6834 if (node
== *rssi_head
) {
6836 *rssi_head
= node
->next
;
6839 prev
->next
= node
->next
;
6841 AEXT_INFO("wlan", "Del %d with BSSID %pM\n", i
, &node
->BSSID
);
6857 wl_reset_rssi_cache(wl_rssi_cache_ctrl_t
*rssi_cache_ctrl
)
6859 wl_rssi_cache_t
*node
, **rssi_head
;
6861 rssi_head
= &rssi_cache_ctrl
->m_cache_head
;
6872 wl_update_connected_rssi_cache(struct net_device
*net
,
6873 wl_rssi_cache_ctrl_t
*rssi_cache_ctrl
, int *rssi_avg
)
6875 wl_rssi_cache_t
*node
, *prev
, *leaf
, **rssi_head
;
6878 struct ether_addr bssid
;
6879 struct osl_timespec now
, timeout
;
6885 error
= wldev_ioctl(net
, WLC_GET_BSSID
, &bssid
, sizeof(bssid
), 0);
6886 if (error
== BCME_NOTASSOCIATED
) {
6887 AEXT_INFO("wlan", "Not Associated! res:%d\n", error
);
6891 AEXT_ERROR(net
->name
, "Could not get bssid (%d)\n", error
);
6893 error
= wldev_get_rssi(net
, &scbval
);
6895 AEXT_ERROR(net
->name
, "Could not get rssi (%d)\n", error
);
6900 osl_do_gettimeofday(&now
);
6901 timeout
.tv_sec
= now
.tv_sec
+ RSSICACHE_TIMEOUT
;
6902 if (timeout
.tv_sec
< now
.tv_sec
) {
6904 * Integer overflow - assume long enough timeout to be assumed
6905 * to be infinite, i.e., the timeout would never happen.
6907 AEXT_TRACE(net
->name
,
6908 "Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu\n",
6909 RSSICACHE_TIMEOUT
, now
.tv_sec
, timeout
.tv_sec
);
6913 rssi_head
= &rssi_cache_ctrl
->m_cache_head
;
6917 if (!memcmp(&node
->BSSID
, &bssid
, ETHER_ADDR_LEN
)) {
6918 AEXT_INFO("wlan", "Update %d with BSSID %pM, RSSI=%d\n", k
, &bssid
, rssi
);
6919 for (j
=0; j
<RSSIAVG_LEN
-1; j
++)
6920 node
->RSSI
[j
] = node
->RSSI
[j
+1];
6921 node
->RSSI
[j
] = rssi
;
6931 leaf
= kmalloc(sizeof(wl_rssi_cache_t
), GFP_KERNEL
);
6933 AEXT_ERROR(net
->name
, "Memory alloc failure %d\n", (int)sizeof(wl_rssi_cache_t
));
6936 AEXT_INFO(net
->name
, "Add %d with cached BSSID %pM, RSSI=%3d in the leaf\n",
6942 memcpy(&leaf
->BSSID
, &bssid
, ETHER_ADDR_LEN
);
6943 for (j
=0; j
<RSSIAVG_LEN
; j
++)
6944 leaf
->RSSI
[j
] = rssi
;
6952 *rssi_avg
= (int)wl_get_avg_rssi(rssi_cache_ctrl
, &bssid
);
6958 wl_update_rssi_cache(wl_rssi_cache_ctrl_t
*rssi_cache_ctrl
,
6959 wl_scan_results_t
*ss_list
)
6961 wl_rssi_cache_t
*node
, *prev
, *leaf
, **rssi_head
;
6962 wl_bss_info_t
*bi
= NULL
;
6964 struct osl_timespec now
, timeout
;
6966 if (!ss_list
->count
)
6969 osl_do_gettimeofday(&now
);
6970 timeout
.tv_sec
= now
.tv_sec
+ RSSICACHE_TIMEOUT
;
6971 if (timeout
.tv_sec
< now
.tv_sec
) {
6973 * Integer overflow - assume long enough timeout to be assumed
6974 * to be infinite, i.e., the timeout would never happen.
6977 "Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu\n",
6978 RSSICACHE_TIMEOUT
, now
.tv_sec
, timeout
.tv_sec
);
6981 rssi_head
= &rssi_cache_ctrl
->m_cache_head
;
6984 for (i
= 0; i
< ss_list
->count
; i
++) {
6988 bi
= bi
? (wl_bss_info_t
*)((uintptr
)bi
+ dtoh32(bi
->length
)) : ss_list
->bss_info
;
6990 if (!memcmp(&node
->BSSID
, &bi
->BSSID
, ETHER_ADDR_LEN
)) {
6991 AEXT_INFO("wlan", "Update %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
6992 k
, &bi
->BSSID
, dtoh16(bi
->RSSI
), bi
->SSID
);
6993 for (j
=0; j
<RSSIAVG_LEN
-1; j
++)
6994 node
->RSSI
[j
] = node
->RSSI
[j
+1];
6995 node
->RSSI
[j
] = dtoh16(bi
->RSSI
);
7008 leaf
= kmalloc(sizeof(wl_rssi_cache_t
), GFP_KERNEL
);
7010 AEXT_ERROR("wlan", "Memory alloc failure %d\n",
7011 (int)sizeof(wl_rssi_cache_t
));
7014 AEXT_INFO("wlan", "Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\" in the leaf\n",
7015 k
, &bi
->BSSID
, dtoh16(bi
->RSSI
), bi
->SSID
);
7020 memcpy(&leaf
->BSSID
, &bi
->BSSID
, ETHER_ADDR_LEN
);
7021 for (j
=0; j
<RSSIAVG_LEN
; j
++)
7022 leaf
->RSSI
[j
] = dtoh16(bi
->RSSI
);
7032 wl_get_avg_rssi(wl_rssi_cache_ctrl_t
*rssi_cache_ctrl
, void *addr
)
7034 wl_rssi_cache_t
*node
, **rssi_head
;
7035 int j
, rssi_sum
, rssi
=RSSI_MINVAL
;
7037 rssi_head
= &rssi_cache_ctrl
->m_cache_head
;
7041 if (!memcmp(&node
->BSSID
, addr
, ETHER_ADDR_LEN
)) {
7044 for (j
=0; j
<RSSIAVG_LEN
; j
++)
7045 rssi_sum
+= node
->RSSI
[RSSIAVG_LEN
-j
-1];
7046 rssi
= rssi_sum
/ j
;
7051 rssi
= MIN(rssi
, RSSI_MAXVAL
);
7052 if (rssi
== RSSI_MINVAL
) {
7053 AEXT_ERROR("wlan", "BSSID %pM does not in RSSI cache\n", addr
);
7057 #endif /* RSSIAVG */
7059 #if defined(RSSIOFFSET)
7061 wl_update_rssi_offset(struct net_device
*net
, int rssi
)
7063 #if defined(RSSIOFFSET_NEW)
7065 #endif /* RSSIOFFSET_NEW */
7070 #if defined(RSSIOFFSET_NEW)
7071 for (j
=0; j
<RSSI_OFFSET
; j
++) {
7072 if (rssi
- (RSSI_OFFSET_MINVAL
+RSSI_OFFSET_INTVAL
*(j
+1)) < 0)
7077 rssi
+= RSSI_OFFSET
;
7078 #endif /* RSSIOFFSET_NEW */
7079 return MIN(rssi
, RSSI_MAXVAL
);
7081 #endif /* RSSIOFFSET */
7083 #if defined(BSSCACHE)
7085 wl_free_bss_cache(wl_bss_cache_ctrl_t
*bss_cache_ctrl
)
7087 wl_bss_cache_t
*node
, *cur
, **bss_head
;
7090 AEXT_TRACE("wlan", "called\n");
7092 bss_head
= &bss_cache_ctrl
->m_cache_head
;
7096 AEXT_TRACE("wlan", "Free %d with BSSID %pM\n",
7097 i
, &node
->results
.bss_info
->BSSID
);
7107 wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t
*bss_cache_ctrl
)
7109 wl_bss_cache_t
*node
, *prev
, **bss_head
;
7110 int i
= -1, tmp
= 0;
7111 struct osl_timespec now
;
7113 osl_do_gettimeofday(&now
);
7115 bss_head
= &bss_cache_ctrl
->m_cache_head
;
7120 if (now
.tv_sec
> node
->tv
.tv_sec
) {
7121 if (node
== *bss_head
) {
7123 *bss_head
= node
->next
;
7126 prev
->next
= node
->next
;
7128 AEXT_TRACE("wlan", "Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
7129 i
, &node
->results
.bss_info
->BSSID
,
7130 dtoh16(node
->results
.bss_info
->RSSI
), node
->results
.bss_info
->SSID
);
7146 wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t
*bss_cache_ctrl
,
7149 wl_bss_cache_t
*node
, *prev
, **bss_head
;
7150 int i
= -1, tmp
= 0;
7152 bss_head
= &bss_cache_ctrl
->m_cache_head
;
7157 if (!memcmp(&node
->results
.bss_info
->BSSID
, bssid
, ETHER_ADDR_LEN
)) {
7158 if (node
== *bss_head
) {
7160 *bss_head
= node
->next
;
7163 prev
->next
= node
->next
;
7165 AEXT_TRACE("wlan", "Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
7166 i
, &node
->results
.bss_info
->BSSID
,
7167 dtoh16(node
->results
.bss_info
->RSSI
), node
->results
.bss_info
->SSID
);
7183 wl_reset_bss_cache(wl_bss_cache_ctrl_t
*bss_cache_ctrl
)
7185 wl_bss_cache_t
*node
, **bss_head
;
7187 bss_head
= &bss_cache_ctrl
->m_cache_head
;
7197 void dump_bss_cache(
7198 #if defined(RSSIAVG)
7199 wl_rssi_cache_ctrl_t
*rssi_cache_ctrl
,
7200 #endif /* RSSIAVG */
7201 wl_bss_cache_t
*node
)
7207 #if defined(RSSIAVG)
7208 rssi
= wl_get_avg_rssi(rssi_cache_ctrl
, &node
->results
.bss_info
->BSSID
);
7210 rssi
= dtoh16(node
->results
.bss_info
->RSSI
);
7211 #endif /* RSSIAVG */
7212 AEXT_TRACE("wlan", "dump %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
7213 k
, &node
->results
.bss_info
->BSSID
, rssi
, node
->results
.bss_info
->SSID
);
7220 wl_update_bss_cache(wl_bss_cache_ctrl_t
*bss_cache_ctrl
,
7221 #if defined(RSSIAVG)
7222 wl_rssi_cache_ctrl_t
*rssi_cache_ctrl
,
7223 #endif /* RSSIAVG */
7224 wl_scan_results_t
*ss_list
)
7226 wl_bss_cache_t
*node
, *prev
, *leaf
, **bss_head
;
7227 wl_bss_info_t
*bi
= NULL
;
7229 #if defined(SORT_BSS_BY_RSSI)
7230 int16 rssi
, rssi_node
;
7231 #endif /* SORT_BSS_BY_RSSI */
7232 struct osl_timespec now
, timeout
;
7234 if (!ss_list
->count
)
7237 osl_do_gettimeofday(&now
);
7238 timeout
.tv_sec
= now
.tv_sec
+ BSSCACHE_TIMEOUT
;
7239 if (timeout
.tv_sec
< now
.tv_sec
) {
7241 * Integer overflow - assume long enough timeout to be assumed
7242 * to be infinite, i.e., the timeout would never happen.
7245 "Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu\n",
7246 BSSCACHE_TIMEOUT
, now
.tv_sec
, timeout
.tv_sec
);
7249 bss_head
= &bss_cache_ctrl
->m_cache_head
;
7251 for (i
=0; i
< ss_list
->count
; i
++) {
7254 bi
= bi
? (wl_bss_info_t
*)((uintptr
)bi
+ dtoh32(bi
->length
)) : ss_list
->bss_info
;
7257 if (!memcmp(&node
->results
.bss_info
->BSSID
, &bi
->BSSID
, ETHER_ADDR_LEN
)) {
7258 if (node
== *bss_head
)
7259 *bss_head
= node
->next
;
7261 prev
->next
= node
->next
;
7269 leaf
= kmalloc(dtoh32(bi
->length
) + sizeof(wl_bss_cache_t
), GFP_KERNEL
);
7271 AEXT_ERROR("wlan", "Memory alloc failure %d\n",
7272 dtoh32(bi
->length
) + (int)sizeof(wl_bss_cache_t
));
7279 "Update %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
7280 k
, &bi
->BSSID
, dtoh16(bi
->RSSI
), bi
->SSID
);
7283 "Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
7284 k
, &bi
->BSSID
, dtoh16(bi
->RSSI
), bi
->SSID
);
7286 memcpy(leaf
->results
.bss_info
, bi
, dtoh32(bi
->length
));
7290 leaf
->results
.count
= 1;
7291 leaf
->results
.version
= ss_list
->version
;
7294 if (*bss_head
== NULL
)
7297 #if defined(SORT_BSS_BY_RSSI)
7299 #if defined(RSSIAVG)
7300 rssi
= wl_get_avg_rssi(rssi_cache_ctrl
, &leaf
->results
.bss_info
->BSSID
);
7302 rssi
= dtoh16(leaf
->results
.bss_info
->RSSI
);
7303 #endif /* RSSIAVG */
7305 #if defined(RSSIAVG)
7306 rssi_node
= wl_get_avg_rssi(rssi_cache_ctrl
,
7307 &node
->results
.bss_info
->BSSID
);
7309 rssi_node
= dtoh16(node
->results
.bss_info
->RSSI
);
7310 #endif /* RSSIAVG */
7311 if (rssi
> rssi_node
) {
7313 if (node
== *bss_head
)
7325 leaf
->next
= *bss_head
;
7327 #endif /* SORT_BSS_BY_RSSI */
7331 #if defined(RSSIAVG)
7333 #endif /* RSSIAVG */
7338 wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t
*bss_cache_ctrl
)
7340 AEXT_TRACE("wlan", "Enter\n");
7341 wl_free_bss_cache(bss_cache_ctrl
);
7343 #endif /* BSSCACHE */