From a965c2909e85495269db307b3bef330e2b87538a Mon Sep 17 00:00:00 2001 From: zzc Date: Wed, 18 Jan 2017 09:21:47 +0800 Subject: [PATCH] net: rkwifi: fix using wext protocol anomaly Change-Id: Id7a6b4069cb25bcf369f506e47630e86f98ec890 Signed-off-by: zzc --- .../rockchip_wlan/rkwifi/bcmdhd/Makefile | 4 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c | 58 +- .../bcmdhd/include/devctrl_if/wlioctl_defs.h | 1 + .../rockchip_wlan/rkwifi/bcmdhd/wl_android.c | 27 - .../rockchip_wlan/rkwifi/bcmdhd/wl_android.h | 27 + .../rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c | 2 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_escan.c | 1457 +++++++++++++++++ .../rockchip_wlan/rkwifi/bcmdhd/wl_escan.h | 75 + .../rockchip_wlan/rkwifi/bcmdhd/wl_iw.c | 54 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_iw.h | 4 + 10 files changed, 1663 insertions(+), 46 deletions(-) mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/devctrl_if/wlioctl_defs.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.h diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile old mode 100755 new mode 100644 index 5160edc2786e..a9b91da46f8e --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile @@ -72,8 +72,8 @@ DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -DENHANCED_STATIC_BUF endif ifneq ($(CONFIG_WIRELESS_EXT),) -DHDOFILES += wl_iw.o -DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW +DHDOFILES += wl_iw.o wl_escan.o +DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW -DWL_ESCAN endif ifneq ($(CONFIG_CFG80211),) DHDOFILES += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o wl_cfg_btcoex.o diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c index f7beba4eeaba..ca27706af9fb 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c @@ -81,6 +81,9 @@ #include #include #include +#ifdef WL_ESCAN +#include +#endif #include #ifdef CONFIG_HAS_WAKELOCK #include @@ -5714,17 +5717,35 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) goto done; } ioc.cmd = compat_ioc.cmd; - ioc.buf = compat_ptr(compat_ioc.buf); - ioc.len = compat_ioc.len; - ioc.set = compat_ioc.set; - ioc.used = compat_ioc.used; - ioc.needed = compat_ioc.needed; - /* To differentiate between wl and dhd read 4 more byes */ - if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t), - sizeof(uint)) != 0)) { - ret = BCME_BADADDR; - goto done; - } + if (ioc.cmd & WLC_SPEC_FLAG) { + memset(&ioc, 0, sizeof(ioc)); + /* Copy the ioc control structure part of ioctl request */ + if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { + ret = BCME_BADADDR; + goto done; + } + ioc.cmd &= ~WLC_SPEC_FLAG; /* Clear the FLAG */ + + /* To differentiate between wl and dhd read 4 more byes */ + if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), + sizeof(uint)) != 0)) { + ret = BCME_BADADDR; + goto done; + } + + } else { /* ioc.cmd & WLC_SPEC_FLAG */ + ioc.buf = compat_ptr(compat_ioc.buf); + ioc.len = compat_ioc.len; + ioc.set = compat_ioc.set; + ioc.used = compat_ioc.used; + ioc.needed = compat_ioc.needed; + /* To differentiate between wl and dhd read 4 more byes */ + if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t), + sizeof(uint)) != 0)) { + ret = BCME_BADADDR; + goto done; + } + } /* ioc.cmd & WLC_SPEC_FLAG */ } else #endif /* CONFIG_COMPAT */ { @@ -5733,7 +5754,9 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) ret = BCME_BADADDR; goto done; } - +#ifdef CONFIG_COMPAT + ioc.cmd &= ~WLC_SPEC_FLAG; /* make sure it was clear when it isn't a compat task*/ +#endif /* To differentiate between wl and dhd read 4 more byes */ if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), sizeof(uint)) != 0)) { @@ -7221,6 +7244,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) } dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; } +#ifdef WL_ESCAN + wl_escan_attach(net, (void *)&dhd->pub); +#endif #endif /* defined(WL_WIRELESS_EXT) */ #ifdef SHOW_LOGTRACE @@ -8792,6 +8818,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef WLTDLS setbit(eventmask, WLC_E_TDLS_PEER_EVENT); #endif /* WLTDLS */ +#ifdef WL_ESCAN + setbit(eventmask, WLC_E_ESCAN_RESULT); +#endif #ifdef WL_CFG80211 setbit(eventmask, WLC_E_ESCAN_RESULT); setbit(eventmask, WLC_E_AP_STARTED); @@ -9663,6 +9692,9 @@ void dhd_detach(dhd_pub_t *dhdp) /* Detatch and unlink in the iw */ wl_iw_detach(); } +#ifdef WL_ESCAN + wl_escan_detach(); +#endif #endif /* defined(WL_WIRELESS_EXT) */ /* delete all interfaces, start with virtual */ @@ -12432,7 +12464,7 @@ bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret) net = dhd_idx2net(dhdp, ifidx); if (!net) { DHD_ERROR(("%s : Invalid index : %d\n", __FUNCTION__, ifidx)); - return -EINVAL; + return FALSE; } return dhd_check_hang(net, dhdp, ret); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/devctrl_if/wlioctl_defs.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/devctrl_if/wlioctl_defs.h old mode 100755 new mode 100644 index 2fbe8e0a6b50..3cae18d8a9d8 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/devctrl_if/wlioctl_defs.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/devctrl_if/wlioctl_defs.h @@ -796,6 +796,7 @@ #define WLC_DUMP_RATESET 322 #define WLC_ECHO 323 #define WLC_LAST 324 +#define WLC_SPEC_FLAG 0x80000000 /* For some special IOCTL */ #ifndef EPICTRL_COOKIE #define EPICTRL_COOKIE 0xABADCEDE #endif diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c old mode 100755 new mode 100644 index 1e722fbe62d9..1a54e5ff738d --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c @@ -69,35 +69,8 @@ #define dtohchanspec(i) i #endif -/* message levels */ -#define ANDROID_ERROR_LEVEL 0x0001 -#define ANDROID_TRACE_LEVEL 0x0002 -#define ANDROID_INFO_LEVEL 0x0004 - uint android_msg_level = ANDROID_ERROR_LEVEL; -#define ANDROID_ERROR(x) \ - do { \ - if (android_msg_level & ANDROID_ERROR_LEVEL) { \ - printk(KERN_ERR "ANDROID-ERROR) "); \ - printk x; \ - } \ - } while (0) -#define ANDROID_TRACE(x) \ - do { \ - if (android_msg_level & ANDROID_TRACE_LEVEL) { \ - printk(KERN_ERR "ANDROID-TRACE) "); \ - printk x; \ - } \ - } while (0) -#define ANDROID_INFO(x) \ - do { \ - if (android_msg_level & ANDROID_INFO_LEVEL) { \ - printk(KERN_ERR "ANDROID-INFO) "); \ - printk x; \ - } \ - } while (0) - /* * Android private command strings, PLEASE define new private commands here * so they can be updated easily in the future (if needed) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h old mode 100755 new mode 100644 index 31dfac6a271c..11252fd85ac8 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h @@ -49,6 +49,33 @@ * or cfg, define them as static in wl_android.c */ +/* message levels */ +#define ANDROID_ERROR_LEVEL 0x0001 +#define ANDROID_TRACE_LEVEL 0x0002 +#define ANDROID_INFO_LEVEL 0x0004 + +#define ANDROID_ERROR(x) \ + do { \ + if (android_msg_level & ANDROID_ERROR_LEVEL) { \ + printk(KERN_ERR "ANDROID-ERROR) "); \ + printk x; \ + } \ + } while (0) +#define ANDROID_TRACE(x) \ + do { \ + if (android_msg_level & ANDROID_TRACE_LEVEL) { \ + printk(KERN_ERR "ANDROID-TRACE) "); \ + printk x; \ + } \ + } while (0) +#define ANDROID_INFO(x) \ + do { \ + if (android_msg_level & ANDROID_INFO_LEVEL) { \ + printk(KERN_ERR "ANDROID-INFO) "); \ + printk x; \ + } \ + } while (0) + /** * wl_android_init will be called from module init function (dhd_module_init now), similarly * wl_android_exit will be called from module exit function (dhd_module_cleanup now) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c index 89efcf1c484e..7106db17c324 100755 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c @@ -12299,7 +12299,7 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } if (!ndev || (!wl_get_drv_status(cfg, SCANNING, ndev) && !cfg->sched_scan_running)) { - WL_ERR(("escan is not ready ndev %p drv_status 0x%x e_type %d e_states %d\n", + WL_DBG(("escan is not ready ndev %p drv_status 0x%x e_type %d e_states %d\n", ndev, wl_get_drv_status(cfg, SCANNING, ndev), ntoh32(e->event_type), ntoh32(e->status))); goto exit; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c new file mode 100644 index 000000000000..259b3d9d7f39 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c @@ -0,0 +1,1457 @@ + +#if defined(WL_ESCAN) + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +/* message levels */ +#define ESCAN_ERROR_LEVEL 0x0001 +#define ESCAN_SCAN_LEVEL 0x0002 +#define ESCAN_TRACE_LEVEL 0x0004 + +#define ESCAN_ERROR(x) \ + do { \ + if (iw_msg_level & ESCAN_ERROR_LEVEL) { \ + printf(KERN_ERR "ESCAN-ERROR) "); \ + printf x; \ + } \ + } while (0) +#define ESCAN_SCAN(x) \ + do { \ + if (iw_msg_level & ESCAN_SCAN_LEVEL) { \ + printf(KERN_ERR "ESCAN-SCAN) "); \ + printf x; \ + } \ + } while (0) +#define ESCAN_TRACE(x) \ + do { \ + if (iw_msg_level & ESCAN_TRACE_LEVEL) { \ + printf(KERN_ERR "ESCAN-TRACE) "); \ + printf x; \ + } \ + } while (0) + +/* IOCTL swapping mode for Big Endian host with Little Endian dongle. Default to off */ +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) + +#define wl_escan_get_buf(a) ((wl_scan_results_t *) (a)->escan_buf) + +#define for_each_bss(list, bss, __i) \ + for (__i = 0; __i < list->count && __i < IW_MAX_AP; __i++, bss = next_bss(list, bss)) + +#define wl_escan_set_sync_id(a) ((a) = htod16(0x1234)) + +#ifdef ESCAN_BUF_OVERFLOW_MGMT +#define BUF_OVERFLOW_MGMT_COUNT 3 +typedef struct { + int RSSI; + int length; + struct ether_addr BSSID; +} removal_element_t; +#endif /* ESCAN_BUF_OVERFLOW_MGMT */ + +struct wl_escan_info *g_escan = NULL; + +#if defined(RSSIAVG) +static wl_rssi_cache_ctrl_t g_rssi_cache_ctrl; +static wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl; +#endif +#if defined(BSSCACHE) +static wl_bss_cache_ctrl_t g_bss_cache_ctrl; +#endif + +/* Return a new chanspec given a legacy chanspec + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_from_legacy(chanspec_t legacy_chspec) +{ + chanspec_t chspec; + + /* get the channel number */ + chspec = LCHSPEC_CHANNEL(legacy_chspec); + + /* convert the band */ + if (LCHSPEC_IS2G(legacy_chspec)) { + chspec |= WL_CHANSPEC_BAND_2G; + } else { + chspec |= WL_CHANSPEC_BAND_5G; + } + + /* convert the bw and sideband */ + if (LCHSPEC_IS20(legacy_chspec)) { + chspec |= WL_CHANSPEC_BW_20; + } else { + chspec |= WL_CHANSPEC_BW_40; + if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) { + chspec |= WL_CHANSPEC_CTL_SB_L; + } else { + chspec |= WL_CHANSPEC_CTL_SB_U; + } + } + + if (wf_chspec_malformed(chspec)) { + ESCAN_ERROR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n", + chspec)); + return INVCHANSPEC; + } + + return chspec; +} + +/* Return a legacy chanspec given a new chanspec + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_to_legacy(chanspec_t chspec) +{ + chanspec_t lchspec; + + if (wf_chspec_malformed(chspec)) { + ESCAN_ERROR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n", + chspec)); + return INVCHANSPEC; + } + + /* get the channel number */ + lchspec = CHSPEC_CHANNEL(chspec); + + /* convert the band */ + if (CHSPEC_IS2G(chspec)) { + lchspec |= WL_LCHANSPEC_BAND_2G; + } else { + lchspec |= WL_LCHANSPEC_BAND_5G; + } + + /* convert the bw and sideband */ + if (CHSPEC_IS20(chspec)) { + lchspec |= WL_LCHANSPEC_BW_20; + lchspec |= WL_LCHANSPEC_CTL_SB_NONE; + } else if (CHSPEC_IS40(chspec)) { + lchspec |= WL_LCHANSPEC_BW_40; + if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) { + lchspec |= WL_LCHANSPEC_CTL_SB_LOWER; + } else { + lchspec |= WL_LCHANSPEC_CTL_SB_UPPER; + } + } else { + /* cannot express the bandwidth */ + char chanbuf[CHANSPEC_STR_LEN]; + ESCAN_ERROR(( + "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) " + "to pre-11ac format\n", + wf_chspec_ntoa(chspec, chanbuf), chspec)); + return INVCHANSPEC; + } + + return lchspec; +} + +/* given a chanspec value from the driver, do the endian and chanspec version conversion to + * a chanspec_t value + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec) +{ + chanspec = dtohchanspec(chanspec); + if (ioctl_ver == 1) { + chanspec = wl_chspec_from_legacy(chanspec); + } + + return chanspec; +} + +/* given a chanspec value, do the endian and chanspec version conversion to + * a chanspec_t value + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_host_to_driver(chanspec_t chanspec) +{ + if (1) { + chanspec = wl_chspec_to_legacy(chanspec); + if (chanspec == INVCHANSPEC) { + return chanspec; + } + } + chanspec = htodchanspec(chanspec); + + return chanspec; +} + +/* given a channel value, do the endian and chanspec version conversion to + * a chanspec_t value + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_ch_host_to_driver(s32 bssidx, u16 channel) +{ + chanspec_t chanspec; + + chanspec = channel & WL_CHANSPEC_CHAN_MASK; + + if (channel <= CH_MAX_2G_CHANNEL) + chanspec |= WL_CHANSPEC_BAND_2G; + else + chanspec |= WL_CHANSPEC_BAND_5G; + + chanspec |= WL_CHANSPEC_BW_20; + + chanspec |= WL_CHANSPEC_CTL_SB_NONE; + + return wl_chspec_host_to_driver(chanspec); +} + +static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) +{ + return bss = bss ? + (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info; +} + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] + +static int +rssi_to_qual(int rssi) +{ + if (rssi <= WL_IW_RSSI_NO_SIGNAL) + return 0; + else if (rssi <= WL_IW_RSSI_VERY_LOW) + return 1; + else if (rssi <= WL_IW_RSSI_LOW) + return 2; + else if (rssi <= WL_IW_RSSI_GOOD) + return 3; + else if (rssi <= WL_IW_RSSI_VERY_GOOD) + return 4; + else + return 5; +} + +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ + 4 && __GNUC_MINOR__ >= 6)) +#define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \ +_Pragma("GCC diagnostic push") \ +_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \ +(entry) = list_first_entry((ptr), type, member); \ +_Pragma("GCC diagnostic pop") \ + +#define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \ +_Pragma("GCC diagnostic push") \ +_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \ +entry = container_of((ptr), type, member); \ +_Pragma("GCC diagnostic pop") \ + +#else +#define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \ +(entry) = list_first_entry((ptr), type, member); \ + +#define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \ +entry = container_of((ptr), type, member); \ + +#endif /* STRICT_GCC_WARNINGS */ + +static unsigned long wl_lock_eq(struct wl_escan_info *escan) +{ + unsigned long flags; + + spin_lock_irqsave(&escan->eq_lock, flags); + return flags; +} + +static void wl_unlock_eq(struct wl_escan_info *escan, unsigned long flags) +{ + spin_unlock_irqrestore(&escan->eq_lock, flags); +} + +static void wl_init_eq(struct wl_escan_info *escan) +{ + spin_lock_init(&escan->eq_lock); + INIT_LIST_HEAD(&escan->eq_list); +} + +static void wl_flush_eq(struct wl_escan_info *escan) +{ + struct escan_event_q *e; + unsigned long flags; + + flags = wl_lock_eq(escan); + while (!list_empty_careful(&escan->eq_list)) { + BCM_SET_LIST_FIRST_ENTRY(e, &escan->eq_list, struct escan_event_q, eq_list); + list_del(&e->eq_list); + kfree(e); + } + wl_unlock_eq(escan, flags); +} + +static struct escan_event_q *wl_deq_event(struct wl_escan_info *escan) +{ + struct escan_event_q *e = NULL; + unsigned long flags; + + flags = wl_lock_eq(escan); + if (likely(!list_empty(&escan->eq_list))) { + BCM_SET_LIST_FIRST_ENTRY(e, &escan->eq_list, struct escan_event_q, eq_list); + list_del(&e->eq_list); + } + wl_unlock_eq(escan, flags); + + return e; +} + +/* + * push event to tail of the queue + */ + +static s32 +wl_enq_event(struct wl_escan_info *escan, struct net_device *ndev, u32 event, + const wl_event_msg_t *msg, void *data) +{ + struct escan_event_q *e; + s32 err = 0; + uint32 evtq_size; + uint32 data_len; + unsigned long flags; + gfp_t aflags; + + data_len = 0; + if (data) + data_len = ntoh32(msg->datalen); + evtq_size = sizeof(struct escan_event_q) + data_len; + aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; + e = kzalloc(evtq_size, aflags); + if (unlikely(!e)) { + ESCAN_ERROR(("event alloc failed\n")); + return -ENOMEM; + } + e->etype = event; + memcpy(&e->emsg, msg, sizeof(wl_event_msg_t)); + if (data) + memcpy(e->edata, data, data_len); + flags = wl_lock_eq(escan); + list_add_tail(&e->eq_list, &escan->eq_list); + wl_unlock_eq(escan, flags); + + return err; +} + +static void wl_put_event(struct escan_event_q *e) +{ + kfree(e); +} + +static void wl_wakeup_event(struct wl_escan_info *escan) +{ + dhd_pub_t *dhd = (dhd_pub_t *)(escan->pub); + + if (dhd->up && (escan->event_tsk.thr_pid >= 0)) { + up(&escan->event_tsk.sema); + } +} + +static s32 wl_escan_event_handler(void *data) +{ + struct wl_escan_info *escan = NULL; + struct escan_event_q *e; + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + + escan = (struct wl_escan_info *)tsk->parent; + + printf("tsk Enter, tsk = 0x%p\n", tsk); + + while (down_interruptible (&tsk->sema) == 0) { + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + break; + } + while (escan && (e = wl_deq_event(escan))) { + ESCAN_TRACE(("dev=%p, event type (%d), ifidx: %d bssidx: %d \n", + escan->dev, e->etype, e->emsg.ifidx, e->emsg.bsscfgidx)); + + if (e->emsg.ifidx > WL_MAX_IFS) { + ESCAN_ERROR(("Event ifidx not in range. val:%d \n", e->emsg.ifidx)); + goto fail; + } + + if (escan->dev && escan->evt_handler[e->etype]) { + dhd_pub_t *dhd = (struct dhd_pub *)(escan->pub); + if (dhd->busstate == DHD_BUS_DOWN) { + ESCAN_ERROR((": BUS is DOWN.\n")); + } else { + escan->evt_handler[e->etype](escan, &e->emsg, e->edata); + } + } else { + ESCAN_TRACE(("Unknown Event (%d): ignoring\n", e->etype)); + } +fail: + wl_put_event(e); + DHD_EVENT_WAKE_UNLOCK(escan->pub); + } + } + printf("%s: was terminated\n", __FUNCTION__); + complete_and_exit(&tsk->completed, 0); + return 0; +} + +void +wl_escan_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) +{ + u32 event_type = ntoh32(e->event_type); + struct wl_escan_info *escan = g_escan; + + if (!escan || !escan->dev) { + return; + } + + if (escan->event_tsk.thr_pid == -1) { + ESCAN_ERROR(("Event handler is not created\n")); + return; + } + + if (escan == NULL) { + ESCAN_ERROR(("Stale event ignored\n")); + return; + } + + if (event_type == WLC_E_PFN_NET_FOUND) { + ESCAN_TRACE(("PNOEVENT: PNO_NET_FOUND\n")); + } + else if (event_type == WLC_E_PFN_NET_LOST) { + ESCAN_TRACE(("PNOEVENT: PNO_NET_LOST\n")); + } + + DHD_EVENT_WAKE_LOCK(escan->pub); + if (likely(!wl_enq_event(escan, ndev, event_type, e, data))) { + wl_wakeup_event(escan); + } else { + DHD_EVENT_WAKE_UNLOCK(escan->pub); + } +} + +static s32 wl_escan_inform_bss(struct wl_escan_info *escan) +{ + struct wl_scan_results *bss_list; + s32 err = 0; +#if defined(RSSIAVG) + int rssi; +#endif + + bss_list = escan->bss_list; + + /* Delete disconnected cache */ +#if defined(BSSCACHE) + wl_delete_disconnected_bss_cache(&g_bss_cache_ctrl, (u8*)&escan->disconnected_bssid); +#if defined(RSSIAVG) + wl_delete_disconnected_rssi_cache(&g_rssi_cache_ctrl, (u8*)&escan->disconnected_bssid); +#endif +#endif + + /* Update cache */ +#if defined(RSSIAVG) + wl_update_rssi_cache(&g_rssi_cache_ctrl, bss_list); + if (!in_atomic()) + wl_update_connected_rssi_cache(escan->dev, &g_rssi_cache_ctrl, &rssi); +#endif +#if defined(BSSCACHE) + wl_update_bss_cache(&g_bss_cache_ctrl, +#if defined(RSSIAVG) + &g_rssi_cache_ctrl, +#endif + bss_list); +#endif + + /* delete dirty cache */ +#if defined(RSSIAVG) + wl_delete_dirty_rssi_cache(&g_rssi_cache_ctrl); + wl_reset_rssi_cache(&g_rssi_cache_ctrl); +#endif +#if defined(BSSCACHE) + wl_delete_dirty_bss_cache(&g_bss_cache_ctrl); + wl_reset_bss_cache(&g_bss_cache_ctrl); +#endif + + ESCAN_TRACE(("scanned AP count (%d)\n", bss_list->count)); + + return err; +} + +static wl_scan_params_t * +wl_escan_alloc_params(int channel, int nprobes, int *out_params_size) +{ + wl_scan_params_t *params; + int params_size; + int num_chans; + int bssidx = 0; + + *out_params_size = 0; + + /* Our scan params only need space for 1 channel and 0 ssids */ + params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16); + params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL); + if (params == NULL) { + ESCAN_ERROR(("mem alloc failed (%d bytes)\n", params_size)); + return params; + } + memset(params, 0, params_size); + params->nprobes = nprobes; + + num_chans = (channel == 0) ? 0 : 1; + + memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); + params->bss_type = DOT11_BSSTYPE_ANY; + params->scan_type = DOT11_SCANTYPE_ACTIVE; + params->nprobes = htod32(1); + params->active_time = htod32(-1); + params->passive_time = htod32(-1); + params->home_time = htod32(10); + if (channel == -1) + params->channel_list[0] = htodchanspec(channel); + else + params->channel_list[0] = wl_ch_host_to_driver(bssidx, channel); + + /* Our scan params have 1 channel and 0 ssids */ + params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | + (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); + + *out_params_size = params_size; /* rtn size to the caller */ + return params; +} + +static void wl_escan_abort(struct wl_escan_info *escan) +{ + wl_scan_params_t *params = NULL; + s32 params_size = 0; + s32 err = BCME_OK; + if (!in_atomic()) { + /* Our scan params only need space for 1 channel and 0 ssids */ + params = wl_escan_alloc_params(-1, 0, ¶ms_size); + if (params == NULL) { + ESCAN_ERROR(("scan params allocation failed \n")); + err = -ENOMEM; + } else { + /* Do a scan abort to stop the driver's scan engine */ + err = wldev_ioctl(escan->dev, WLC_SCAN, params, params_size, true); + if (err < 0) { + ESCAN_ERROR(("scan abort failed \n")); + } + kfree(params); + } + } +} + +static s32 wl_notify_escan_complete(struct wl_escan_info *escan, bool fw_abort) +{ + s32 err = BCME_OK; + int cmd = 0; +#if WIRELESS_EXT > 13 + union iwreq_data wrqu; + char extra[IW_CUSTOM_MAX + 1]; + + memset(extra, 0, sizeof(extra)); +#endif + + ESCAN_TRACE(("Enter\n")); + + if (!escan || !escan->dev) { + ESCAN_ERROR(("escan or dev is null\n")); + err = BCME_ERROR; + goto out; + } + if (fw_abort && !in_atomic()) + wl_escan_abort(escan); + + if (timer_pending(&escan->scan_timeout)) + del_timer_sync(&escan->scan_timeout); +#if defined(ESCAN_RESULT_PATCH) + escan->bss_list = wl_escan_get_buf(escan); + wl_escan_inform_bss(escan); +#endif /* ESCAN_RESULT_PATCH */ + +#if WIRELESS_EXT > 13 +#if WIRELESS_EXT > 14 + cmd = SIOCGIWSCAN; +#endif + ESCAN_TRACE(("event WLC_E_SCAN_COMPLETE\n")); + // terence 20150224: fix "wlan0: (WE) : Wireless Event too big (65306)" + memset(&wrqu, 0, sizeof(wrqu)); + if (cmd) { + if (cmd == SIOCGIWSCAN) { + wireless_send_event(escan->dev, cmd, &wrqu, NULL); + } else + wireless_send_event(escan->dev, cmd, &wrqu, extra); + } +#endif + +out: + return err; +} + +#ifdef ESCAN_BUF_OVERFLOW_MGMT +static void +wl_cfg80211_find_removal_candidate(wl_bss_info_t *bss, removal_element_t *candidate) +{ + int idx; + for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) { + int len = BUF_OVERFLOW_MGMT_COUNT - idx - 1; + if (bss->RSSI < candidate[idx].RSSI) { + if (len) + memcpy(&candidate[idx + 1], &candidate[idx], + sizeof(removal_element_t) * len); + candidate[idx].RSSI = bss->RSSI; + candidate[idx].length = bss->length; + memcpy(&candidate[idx].BSSID, &bss->BSSID, ETHER_ADDR_LEN); + return; + } + } +} + +static void +wl_cfg80211_remove_lowRSSI_info(wl_scan_results_t *list, removal_element_t *candidate, + wl_bss_info_t *bi) +{ + int idx1, idx2; + int total_delete_len = 0; + for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) { + int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; + wl_bss_info_t *bss = NULL; + if (candidate[idx1].RSSI >= bi->RSSI) + continue; + for (idx2 = 0; idx2 < list->count; idx2++) { + bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) : + list->bss_info; + if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) && + candidate[idx1].RSSI == bss->RSSI && + candidate[idx1].length == dtoh32(bss->length)) { + u32 delete_len = dtoh32(bss->length); + ESCAN_TRACE(("delete scan info of " MACDBG " to add new AP\n", + MAC2STRDBG(bss->BSSID.octet))); + if (idx2 < list->count -1) { + memmove((u8 *)bss, (u8 *)bss + delete_len, + list->buflen - cur_len - delete_len); + } + list->buflen -= delete_len; + list->count--; + total_delete_len += delete_len; + /* if delete_len is greater than or equal to result length */ + if (total_delete_len >= bi->length) { + return; + } + break; + } + cur_len += dtoh32(bss->length); + } + } +} +#endif /* ESCAN_BUF_OVERFLOW_MGMT */ + +static s32 wl_escan_handler(struct wl_escan_info *escan, + const wl_event_msg_t *e, void *data) +{ + s32 err = BCME_OK; + s32 status = ntoh32(e->status); + wl_bss_info_t *bi; + wl_escan_result_t *escan_result; + wl_bss_info_t *bss = NULL; + wl_scan_results_t *list; + u32 bi_length; + u32 i; + u16 channel; + + ESCAN_TRACE(("enter event type : %d, status : %d \n", + ntoh32(e->event_type), ntoh32(e->status))); + + mutex_lock(&escan->usr_sync); + escan_result = (wl_escan_result_t *)data; + + if (escan->escan_state != ESCAN_STATE_SCANING) { + ESCAN_TRACE(("Not my scan\n")); + goto exit; + } + + if (status == WLC_E_STATUS_PARTIAL) { + ESCAN_TRACE(("WLC_E_STATUS_PARTIAL \n")); + if (!escan_result) { + ESCAN_ERROR(("Invalid escan result (NULL pointer)\n")); + goto exit; + } + if (dtoh16(escan_result->bss_count) != 1) { + ESCAN_ERROR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count)); + goto exit; + } + bi = escan_result->bss_info; + if (!bi) { + ESCAN_ERROR(("Invalid escan bss info (NULL pointer)\n")); + goto exit; + } + bi_length = dtoh32(bi->length); + if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { + ESCAN_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); + goto exit; + } + + /* +++++ terence 20130524: skip invalid bss */ + channel = + bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec)); + if (!dhd_conf_match_channel(escan->pub, channel)) + goto exit; + /* ----- terence 20130524: skip invalid bss */ + + { + int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; +#ifdef ESCAN_BUF_OVERFLOW_MGMT + removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT]; + int remove_lower_rssi = FALSE; + + bzero(candidate, sizeof(removal_element_t)*BUF_OVERFLOW_MGMT_COUNT); +#endif /* ESCAN_BUF_OVERFLOW_MGMT */ + + list = wl_escan_get_buf(escan); +#ifdef ESCAN_BUF_OVERFLOW_MGMT + if (bi_length > ESCAN_BUF_SIZE - list->buflen) + remove_lower_rssi = TRUE; +#endif /* ESCAN_BUF_OVERFLOW_MGMT */ + + ESCAN_TRACE(("%s("MACDBG") RSSI %d flags 0x%x length %d\n", bi->SSID, + MAC2STRDBG(bi->BSSID.octet), bi->RSSI, bi->flags, bi->length)); + for (i = 0; i < list->count; i++) { + bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) + : list->bss_info; +#ifdef ESCAN_BUF_OVERFLOW_MGMT + ESCAN_TRACE(("%s("MACDBG"), i=%d bss: RSSI %d list->count %d\n", + bss->SSID, MAC2STRDBG(bss->BSSID.octet), + i, bss->RSSI, list->count)); + + if (remove_lower_rssi) + wl_cfg80211_find_removal_candidate(bss, candidate); +#endif /* ESCAN_BUF_OVERFLOW_MGMT */ + if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) && + (CHSPEC_BAND(wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec)) + == CHSPEC_BAND(wl_chspec_driver_to_host(escan->ioctl_ver, bss->chanspec))) && + bi->SSID_len == bss->SSID_len && + !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) { + + /* do not allow beacon data to update + *the data recd from a probe response + */ + if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) && + (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) + goto exit; + + ESCAN_TRACE(("%s("MACDBG"), i=%d prev: RSSI %d" + " flags 0x%x, new: RSSI %d flags 0x%x\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), i, + bss->RSSI, bss->flags, bi->RSSI, bi->flags)); + + if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == + (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) { + /* preserve max RSSI if the measurements are + * both on-channel or both off-channel + */ + ESCAN_TRACE(("%s("MACDBG"), same onchan" + ", RSSI: prev %d new %d\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), + bss->RSSI, bi->RSSI)); + bi->RSSI = MAX(bss->RSSI, bi->RSSI); + } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) && + (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) { + /* preserve the on-channel rssi measurement + * if the new measurement is off channel + */ + ESCAN_TRACE(("%s("MACDBG"), prev onchan" + ", RSSI: prev %d new %d\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), + bss->RSSI, bi->RSSI)); + bi->RSSI = bss->RSSI; + bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL; + } + if (dtoh32(bss->length) != bi_length) { + u32 prev_len = dtoh32(bss->length); + + ESCAN_TRACE(("bss info replacement" + " is occured(bcast:%d->probresp%d)\n", + bss->ie_length, bi->ie_length)); + ESCAN_TRACE(("%s("MACDBG"), replacement!(%d -> %d)\n", + bss->SSID, MAC2STRDBG(bi->BSSID.octet), + prev_len, bi_length)); + + if (list->buflen - prev_len + bi_length + > ESCAN_BUF_SIZE) { + ESCAN_ERROR(("Buffer is too small: keep the" + " previous result of this AP\n")); + /* Only update RSSI */ + bss->RSSI = bi->RSSI; + bss->flags |= (bi->flags + & WL_BSS_FLAGS_RSSI_ONCHANNEL); + goto exit; + } + + if (i < list->count - 1) { + /* memory copy required by this case only */ + memmove((u8 *)bss + bi_length, + (u8 *)bss + prev_len, + list->buflen - cur_len - prev_len); + } + list->buflen -= prev_len; + list->buflen += bi_length; + } + list->version = dtoh32(bi->version); + memcpy((u8 *)bss, (u8 *)bi, bi_length); + goto exit; + } + cur_len += dtoh32(bss->length); + } + if (bi_length > ESCAN_BUF_SIZE - list->buflen) { +#ifdef ESCAN_BUF_OVERFLOW_MGMT + wl_cfg80211_remove_lowRSSI_info(list, candidate, bi); + if (bi_length > ESCAN_BUF_SIZE - list->buflen) { + ESCAN_TRACE(("RSSI(" MACDBG ") is too low(%d) to add Buffer\n", + MAC2STRDBG(bi->BSSID.octet), bi->RSSI)); + goto exit; + } +#else + ESCAN_ERROR(("Buffer is too small: ignoring\n")); + goto exit; +#endif /* ESCAN_BUF_OVERFLOW_MGMT */ + } + + if (strlen(bi->SSID) == 0) { // terence: fix for hidden SSID + ESCAN_SCAN(("Skip hidden SSID %pM\n", &bi->BSSID)); + goto exit; + } + + memcpy(&(((char *)list)[list->buflen]), bi, bi_length); + list->version = dtoh32(bi->version); + list->buflen += bi_length; + list->count++; + } + } + else if (status == WLC_E_STATUS_SUCCESS) { + escan->escan_state = ESCAN_STATE_IDLE; + + ESCAN_TRACE(("ESCAN COMPLETED\n")); + escan->bss_list = wl_escan_get_buf(escan); + ESCAN_TRACE(("SCAN COMPLETED: scanned AP count=%d\n", + escan->bss_list->count)); + wl_escan_inform_bss(escan); + wl_notify_escan_complete(escan, false); + + } else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN) || + (status == WLC_E_STATUS_11HQUIET) || (status == WLC_E_STATUS_CS_ABORT) || + (status == WLC_E_STATUS_NEWASSOC)) { + /* Handle all cases of scan abort */ + escan->escan_state = ESCAN_STATE_IDLE; + ESCAN_TRACE(("ESCAN ABORT reason: %d\n", status)); + wl_escan_inform_bss(escan); + wl_notify_escan_complete(escan, false); + } else if (status == WLC_E_STATUS_TIMEOUT) { + ESCAN_ERROR(("WLC_E_STATUS_TIMEOUT\n")); + ESCAN_ERROR(("reason[0x%x]\n", e->reason)); + if (e->reason == 0xFFFFFFFF) { + wl_notify_escan_complete(escan, true); + } + } else { + ESCAN_ERROR(("unexpected Escan Event %d : abort\n", status)); + escan->escan_state = ESCAN_STATE_IDLE; + escan->bss_list = wl_escan_get_buf(escan); + ESCAN_TRACE(("SCAN ABORTED(UNEXPECTED): scanned AP count=%d\n", + escan->bss_list->count)); + wl_escan_inform_bss(escan); + wl_notify_escan_complete(escan, false); + } +exit: + mutex_unlock(&escan->usr_sync); + return err; +} + +static int +wl_escan_prep(struct wl_escan_info *escan, wl_uint32_list_t *list, + wl_scan_params_t *params, wlc_ssid_t *ssid) +{ + int err = 0; + wl_scan_results_t *results; + s32 offset; + char *ptr; + int i = 0, j = 0; + wlc_ssid_t ssid_tmp; + u32 n_channels = 0; + uint channel; + chanspec_t chanspec; + + results = wl_escan_get_buf(escan); + results->version = 0; + results->count = 0; + results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; + escan->escan_state = ESCAN_STATE_SCANING; + + /* Arm scan timeout timer */ + mod_timer(&escan->scan_timeout, jiffies + msecs_to_jiffies(WL_ESCAN_TIMER_INTERVAL_MS)); + + memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); + params->bss_type = DOT11_BSSTYPE_ANY; + params->scan_type = 0; + params->nprobes = -1; + params->active_time = -1; + params->passive_time = -1; + params->home_time = -1; + params->channel_num = 0; + + params->nprobes = htod32(params->nprobes); + params->active_time = htod32(params->active_time); + params->passive_time = htod32(params->passive_time); + params->home_time = htod32(params->home_time); + + n_channels = dtoh32(list->count); + /* Copy channel array if applicable */ + ESCAN_SCAN(("### List of channelspecs to scan ###\n")); + if (n_channels > 0) { + for (i = 0; i < n_channels; i++) { + channel = dtoh32(list->element[i]); + if (!dhd_conf_match_channel(escan->pub, channel)) + continue; + chanspec = WL_CHANSPEC_BW_20; + if (chanspec == INVCHANSPEC) { + ESCAN_ERROR(("Invalid chanspec! Skipping channel\n")); + continue; + } + if (channel <= CH_MAX_2G_CHANNEL) { + chanspec |= WL_CHANSPEC_BAND_2G; + } else { + chanspec |= WL_CHANSPEC_BAND_5G; + } + params->channel_list[j] = channel; + params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK; + params->channel_list[j] |= chanspec; + ESCAN_SCAN(("Chan : %d, Channel spec: %x \n", + channel, params->channel_list[j])); + params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]); + j++; + } + } else { + ESCAN_SCAN(("Scanning all channels\n")); + } + + if (ssid && ssid->SSID_len) { + /* Copy ssid array if applicable */ + ESCAN_SCAN(("### List of SSIDs to scan ###\n")); + offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16); + offset = roundup(offset, sizeof(u32)); + ptr = (char*)params + offset; + + ESCAN_SCAN(("0: Broadcast scan\n")); + memset(&ssid_tmp, 0, sizeof(wlc_ssid_t)); + ssid_tmp.SSID_len = 0; + memcpy(ptr, &ssid_tmp, sizeof(wlc_ssid_t)); + ptr += sizeof(wlc_ssid_t); + + memset(&ssid_tmp, 0, sizeof(wlc_ssid_t)); + ssid_tmp.SSID_len = ssid->SSID_len; + memcpy(ssid_tmp.SSID, ssid->SSID, ssid->SSID_len); + memcpy(ptr, &ssid_tmp, sizeof(wlc_ssid_t)); + ptr += sizeof(wlc_ssid_t); + ESCAN_SCAN(("1: scan for %s size=%d\n", ssid_tmp.SSID, ssid_tmp.SSID_len)); + /* Adding mask to channel numbers */ + params->channel_num = + htod32((2 << WL_SCAN_PARAMS_NSSID_SHIFT) | + (n_channels & WL_SCAN_PARAMS_COUNT_MASK)); + } + else { + ESCAN_SCAN(("Broadcast scan\n")); + } + + return err; +} + +static int wl_escan_reset(void) { + struct wl_escan_info *escan = g_escan; + + if (timer_pending(&escan->scan_timeout)) + del_timer_sync(&escan->scan_timeout); + escan->escan_state = ESCAN_STATE_IDLE; + + return 0; +} + +static void wl_escan_timeout(unsigned long data) +{ + wl_event_msg_t msg; + struct wl_escan_info *escan = (struct wl_escan_info *)data; + struct wl_scan_results *bss_list; + struct wl_bss_info *bi = NULL; + s32 i; + u32 channel; + + bss_list = wl_escan_get_buf(escan); + if (!bss_list) { + ESCAN_ERROR(("bss_list is null. Didn't receive any partial scan results\n")); + } else { + ESCAN_ERROR(("%s: scanned AP count (%d)\n", __FUNCTION__, bss_list->count)); + bi = next_bss(bss_list, bi); + for_each_bss(bss_list, bi, i) { + channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec)); + ESCAN_ERROR(("SSID :%s Channel :%d\n", bi->SSID, channel)); + } + } + + if (!escan->dev) { + ESCAN_ERROR(("No dev present\n")); + return; + } + + bzero(&msg, sizeof(wl_event_msg_t)); + ESCAN_ERROR(("timer expired\n")); + + msg.event_type = hton32(WLC_E_ESCAN_RESULT); + msg.status = hton32(WLC_E_STATUS_TIMEOUT); + msg.reason = 0xFFFFFFFF; + wl_escan_event(escan->dev, &msg, NULL); + + // terence 20130729: workaround to fix out of memory in firmware +// if (dhd_conf_get_chip(dhd_get_pub(dev)) == BCM43362_CHIP_ID) { +// ESCAN_ERROR(("Send hang event\n")); +// net_os_send_hang_message(dev); +// } +} + +int +wl_escan_set_scan( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + s32 err = BCME_OK; + s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); + wl_escan_params_t *params = NULL; + scb_val_t scbval; + static int cnt = 0; + struct wl_escan_info *escan = NULL; + wlc_ssid_t ssid; + u32 n_channels = 0; + wl_uint32_list_t *list; + u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; + s32 val = 0; + + ESCAN_TRACE(("Enter \n")); + + escan = g_escan; + if (!escan) { + ESCAN_ERROR(("device is not ready\n")); \ + return -EIO; + } + mutex_lock(&escan->usr_sync); + + if (!escan->ioctl_ver) { + val = 1; + if ((err = wldev_ioctl(dev, WLC_GET_VERSION, &val, sizeof(int), false) < 0)) { + ANDROID_ERROR(("WLC_GET_VERSION failed, err=%d\n", err)); + goto exit; + } + val = dtoh32(val); + if (val != WLC_IOCTL_VERSION && val != 1) { + ANDROID_ERROR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n", + val, WLC_IOCTL_VERSION)); + goto exit; + } + escan->ioctl_ver = val; + printf("%s: ioctl_ver=%d\n", __FUNCTION__, val); + } + + /* default Broadcast scan */ + memset(&ssid, 0, sizeof(ssid)); + +#if WIRELESS_EXT > 17 + /* check for given essid */ + if (wrqu->data.length == sizeof(struct iw_scan_req)) { + if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { + struct iw_scan_req *req = (struct iw_scan_req *)extra; + ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len); + memcpy(ssid.SSID, req->essid, ssid.SSID_len); + ssid.SSID_len = htod32(ssid.SSID_len); + } + } +#endif + if (escan->escan_state == ESCAN_STATE_SCANING) { + ESCAN_ERROR(("Scanning already\n")); + goto exit; + } + + /* if scan request is not empty parse scan request paramters */ + memset(valid_chan_list, 0, sizeof(valid_chan_list)); + list = (wl_uint32_list_t *)(void *) valid_chan_list; + list->count = htod32(WL_NUMCHANNELS); + err = wldev_ioctl(escan->dev, WLC_GET_VALID_CHANNELS, valid_chan_list, sizeof(valid_chan_list), false); + if (err != 0) { + ESCAN_ERROR(("%s: get channels failed with %d\n", __FUNCTION__, err)); + goto exit; + } + n_channels = dtoh32(list->count); + /* Allocate space for populating ssids in wl_escan_params_t struct */ + if (dtoh32(list->count) % 2) + /* If n_channels is odd, add a padd of u16 */ + params_size += sizeof(u16) * (n_channels + 1); + else + params_size += sizeof(u16) * n_channels; + if (ssid.SSID_len) { + params_size += sizeof(struct wlc_ssid) * 2; + } + + params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL); + if (params == NULL) { + err = -ENOMEM; + goto exit; + } + wl_escan_prep(escan, list, ¶ms->params, &ssid); + + params->version = htod32(ESCAN_REQ_VERSION); + params->action = htod16(WL_SCAN_ACTION_START); + wl_escan_set_sync_id(params->sync_id); + if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) { + ESCAN_ERROR(("ioctl buffer length not sufficient\n")); + kfree(params); + err = -ENOMEM; + goto exit; + } + params->params.scan_type = DOT11_SCANTYPE_ACTIVE; + ESCAN_TRACE(("Passive scan_type %d\n", params->params.scan_type)); + + err = wldev_iovar_setbuf(dev, "escan", params, params_size, + escan->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(err)) { + if (err == BCME_EPERM) + /* Scan Not permitted at this point of time */ + ESCAN_TRACE(("Escan not permitted at this time (%d)\n", err)); + else + ESCAN_ERROR(("Escan set error (%d)\n", err)); + wl_escan_reset(); + } + kfree(params); + +exit: + if (unlikely(err)) { + /* Don't print Error incase of Scan suppress */ + if ((err == BCME_EPERM)) + ESCAN_TRACE(("Escan failed: Scan Suppressed \n")); + else { + cnt++; + ESCAN_ERROR(("error (%d), cnt=%d\n", err, cnt)); + // terence 20140111: send disassoc to firmware + if (cnt >= 4) { + memset(&scbval, 0, sizeof(scb_val_t)); + wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); + ESCAN_ERROR(("Send disassoc to break the busy dev=%p\n", dev)); + cnt = 0; + } + } + } else { + cnt = 0; + } + mutex_unlock(&escan->usr_sync); + return err; +} + +int +wl_escan_get_scan( + struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra +) +{ + s32 err = BCME_OK; + struct iw_event iwe; + int i, j; + char *event = extra, *end = extra + dwrq->length, *value; + int16 rssi; + int channel; + wl_bss_info_t *bi = NULL; + struct wl_escan_info *escan = g_escan; + struct wl_scan_results *bss_list; +#if defined(BSSCACHE) + wl_bss_cache_t *node; +#endif + + ESCAN_TRACE(("%s: %s SIOCGIWSCAN, len=%d\n", __FUNCTION__, dev->name, dwrq->length)); + + if (!extra) + return -EINVAL; + + mutex_lock(&escan->usr_sync); + + /* Check for scan in progress */ + if (escan->escan_state == ESCAN_STATE_SCANING) { + ESCAN_TRACE(("%s: SIOCGIWSCAN GET still scanning\n", dev->name)); + err = -EAGAIN; + goto exit; + } + +#if defined(BSSCACHE) + bss_list = &g_bss_cache_ctrl.m_cache_head->results; + node = g_bss_cache_ctrl.m_cache_head; + for (i=0; node && ibss_list; + bi = next_bss(bss_list, bi); + for_each_bss(bss_list, bi, i) +#endif + { +#if defined(BSSCACHE) + bi = node->results.bss_info; +#endif + /* overflow check cover fields before wpa IEs */ + if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + + IW_EV_QUAL_LEN >= end) { + err = -E2BIG; + goto exit; + } + +#if defined(RSSIAVG) + rssi = wl_get_avg_rssi(&g_rssi_cache_ctrl, &bi->BSSID); + if (rssi == RSSI_MINVAL) + rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL); +#else + // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS + rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL); +#endif + channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec)); + ESCAN_SCAN(("%s: BSSID="MACSTR", channel=%d, RSSI=%d, SSID=\"%s\"\n", + __FUNCTION__, MAC2STR(bi->BSSID.octet), channel, rssi, bi->SSID)); + + /* First entry must be the BSSID */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); + event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); + + /* SSID */ + iwe.u.data.length = dtoh32(bi->SSID_len); + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); + + /* Mode */ + if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { + iwe.cmd = SIOCGIWMODE; + if (dtoh16(bi->capability) & DOT11_CAP_ESS) + iwe.u.mode = IW_MODE_INFRA; + else + iwe.u.mode = IW_MODE_ADHOC; + event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); + } + + /* Channel */ + iwe.cmd = SIOCGIWFREQ; +#if 1 + iwe.u.freq.m = wf_channel2mhz(channel, channel <= CH_MAX_2G_CHANNEL ? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); +#else + iwe.u.freq.m = wf_channel2mhz(bi->n_cap ? + bi->ctl_ch : CHSPEC_CHANNEL(bi->chanspec), + CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); +#endif + iwe.u.freq.e = 6; + event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); + + /* Channel quality */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.qual = rssi_to_qual(rssi); + iwe.u.qual.level = 0x100 + rssi; + iwe.u.qual.noise = 0x100 + bi->phy_noise; + event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); + + wl_iw_handle_scanresults_ies(&event, end, info, bi); + + /* Encryption */ + iwe.cmd = SIOCGIWENCODE; + if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); + + /* Rates */ + if (bi->rateset.count <= sizeof(bi->rateset.rates)) { + if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end) { + err = -E2BIG; + goto exit; + } + value = event + IW_EV_LCP_LEN; + iwe.cmd = SIOCGIWRATE; + /* Those two flags are ignored... */ + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { + iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; + value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, + IW_EV_PARAM_LEN); + } + event = value; + } +#if defined(BSSCACHE) + node = node->next; +#endif + } + + dwrq->length = event - extra; + dwrq->flags = 0; /* todo */ + ESCAN_SCAN(("scanned AP count (%d)\n", i)); +exit: + mutex_unlock(&escan->usr_sync); + return err; +} + +static s32 wl_create_event_handler(struct wl_escan_info *escan) +{ + int ret = 0; + ESCAN_TRACE(("Enter \n")); + + /* Do not use DHD in cfg driver */ + escan->event_tsk.thr_pid = -1; + + PROC_START(wl_escan_event_handler, escan, &escan->event_tsk, 0, "wl_escan_handler"); + if (escan->event_tsk.thr_pid < 0) + ret = -ENOMEM; + return ret; +} + +static void wl_destroy_event_handler(struct wl_escan_info *escan) +{ + if (escan->event_tsk.thr_pid >= 0) + PROC_STOP(&escan->event_tsk); +} + +static void wl_escan_deinit(void) +{ + struct wl_escan_info *escan = g_escan; + + printf("%s: Enter\n", __FUNCTION__); + if (!escan) { + ESCAN_ERROR(("device is not ready\n")); \ + return; + } + wl_destroy_event_handler(escan); + wl_flush_eq(escan); + del_timer_sync(&escan->scan_timeout); + +#if defined(RSSIAVG) + wl_free_rssi_cache(&g_rssi_cache_ctrl); +#endif +#if defined(BSSCACHE) + wl_free_bss_cache(&g_bss_cache_ctrl); +#endif +} + +static s32 wl_escan_init(void) +{ + struct wl_escan_info *escan = g_escan; + int err = 0; + + printf("%s: Enter\n", __FUNCTION__); + if (!escan) { + ESCAN_ERROR(("device is not ready\n")); \ + return -EIO; + } + + /* Init scan_timeout timer */ + init_timer(&escan->scan_timeout); + escan->scan_timeout.data = (unsigned long) escan; + escan->scan_timeout.function = wl_escan_timeout; + + if (wl_create_event_handler(escan)) { + err = -ENOMEM; + goto err; + } + memset(escan->evt_handler, 0, sizeof(escan->evt_handler)); + + escan->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler; + escan->escan_state = ESCAN_STATE_IDLE; + + mutex_init(&escan->usr_sync); + + return 0; +err: + wl_escan_deinit(); + return err; +} + +void wl_escan_detach(void) +{ + struct wl_escan_info *escan = g_escan; + + printf("%s: Enter\n", __FUNCTION__); + + if (!escan) { + ESCAN_ERROR(("device is not ready\n")); \ + return; + } + + wl_escan_deinit(); + + if (escan->escan_ioctl_buf) { + kfree(escan->escan_ioctl_buf); + escan->escan_ioctl_buf = NULL; + } + + kfree(escan); + g_escan = NULL; +} + +int +wl_escan_attach(struct net_device *dev, void * dhdp) +{ + struct wl_escan_info *escan = NULL; + + printf("%s: Enter\n", __FUNCTION__); + + if (!dev) + return 0; + + escan = kmalloc(sizeof(struct wl_escan_info), GFP_KERNEL); + if (!escan) + return -ENOMEM; + memset(escan, 0, sizeof(struct wl_escan_info)); + + /* we only care about main interface so save a global here */ + g_escan = escan; + escan->dev = dev; + escan->pub = dhdp; + escan->escan_state = ESCAN_STATE_IDLE; + + escan->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); + if (unlikely(!escan->escan_ioctl_buf)) { + ESCAN_ERROR(("Ioctl buf alloc failed\n")); + goto err ; + } + wl_init_eq(escan); +#ifdef WL_ESCAN + wl_escan_init(); +#endif + + return 0; +err: + wl_escan_detach(); + return -ENOMEM; +} + +#endif /* WL_ESCAN */ + diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h new file mode 100644 index 000000000000..25ac1158d6e7 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h @@ -0,0 +1,75 @@ + +#ifndef _wl_escan_ +#define _wl_escan_ + +#include +#include +#include +#include +#include + + +#ifdef DHD_MAX_IFS +#define WL_MAX_IFS DHD_MAX_IFS +#else +#define WL_MAX_IFS 16 +#endif + +#define ESCAN_BUF_SIZE (64 * 1024) + +#define WL_ESCAN_TIMER_INTERVAL_MS 10000 /* Scan timeout */ + +/* event queue for cfg80211 main event */ +struct escan_event_q { + struct list_head eq_list; + u32 etype; + wl_event_msg_t emsg; + s8 edata[1]; +}; + +/* donlge escan state */ +enum escan_state { + ESCAN_STATE_IDLE, + ESCAN_STATE_SCANING +}; + +struct wl_escan_info; + +typedef s32(*ESCAN_EVENT_HANDLER) (struct wl_escan_info *escan, + const wl_event_msg_t *e, void *data); + +typedef struct wl_escan_info { + struct net_device *dev; + dhd_pub_t *pub; + struct timer_list scan_timeout; /* Timer for catch scan event timeout */ + int escan_state; + int ioctl_ver; + + char ioctlbuf[WLC_IOCTL_SMLEN]; + u8 escan_buf[ESCAN_BUF_SIZE]; + struct wl_scan_results *bss_list; + struct wl_scan_results *scan_results; + struct ether_addr disconnected_bssid; + u8 *escan_ioctl_buf; + spinlock_t eq_lock; /* for event queue synchronization */ + struct list_head eq_list; /* used for event queue */ + tsk_ctl_t event_tsk; /* task of main event handler thread */ + ESCAN_EVENT_HANDLER evt_handler[WLC_E_LAST]; + struct mutex usr_sync; /* maily for up/down synchronization */ +} wl_escan_info_t; + +void wl_escan_event(struct net_device *ndev, const wl_event_msg_t * e, void *data); + +int wl_escan_set_scan( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +); +int wl_escan_get_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra); +int wl_escan_attach(struct net_device *dev, void * dhdp); +void wl_escan_detach(void); + +#endif /* _wl_escan_ */ + diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c old mode 100755 new mode 100644 index 230891b35d35..9f5163cc223f --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c @@ -46,6 +46,9 @@ #include #endif #include +#ifdef WL_ESCAN +#include +#endif typedef const struct si_pub si_t; @@ -129,7 +132,7 @@ extern int dhd_wait_pend8021x(struct net_device *dev); #define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) #endif /* WIRELESS_EXT < 19 */ - +#ifndef WL_ESCAN #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) #define DAEMONIZE(a) do { \ allow_signal(SIGKILL); \ @@ -183,6 +186,7 @@ iscan_info_t *g_iscan = NULL; static void wl_iw_timerfunc(ulong data); static void wl_iw_set_event_mask(struct net_device *dev); static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action); +#endif /* WL_ESCAN */ /* priv_link becomes netdev->priv and is the link between netdev and wlif struct */ typedef struct priv_link { @@ -239,7 +243,11 @@ dev_wlc_ioctl( int ret; memset(&ioc, 0, sizeof(ioc)); +#ifdef CONFIG_COMPAT + ioc.cmd = cmd | WLC_SPEC_FLAG; +#else ioc.cmd = cmd; +#endif ioc.buf = arg; ioc.len = len; @@ -280,6 +288,7 @@ dev_wlc_intvar_set( return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len)); } +#ifndef WL_ESCAN static int dev_iw_iovar_setbuf( struct net_device *dev, @@ -315,6 +324,7 @@ dev_iw_iovar_getbuf( return (dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen)); } +#endif #if WIRELESS_EXT > 17 static int @@ -902,6 +912,7 @@ wl_iw_get_range( return 0; } +#ifndef WL_ESCAN static int rssi_to_qual(int rssi) { @@ -918,6 +929,7 @@ rssi_to_qual(int rssi) else return 5; } +#endif /* WL_ESCAN */ static int wl_iw_set_spy( @@ -1074,6 +1086,7 @@ wl_iw_mlme( } #endif /* WIRELESS_EXT > 17 */ +#ifndef WL_ESCAN static int wl_iw_get_aplist( struct net_device *dev, @@ -1221,8 +1234,10 @@ wl_iw_iscan_get_aplist( return 0; } +#endif #if WIRELESS_EXT > 13 +#ifndef WL_ESCAN static int wl_iw_set_scan( struct net_device *dev, @@ -1304,6 +1319,7 @@ wl_iw_iscan_set_scan( return 0; } +#endif /* WL_ESCAN */ #if WIRELESS_EXT > 17 static bool @@ -1352,7 +1368,10 @@ ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len) #endif /* WIRELESS_EXT > 17 */ -static int +#ifndef WL_ESCAN +static +#endif +int wl_iw_handle_scanresults_ies(char **event_p, char *end, struct iw_request_info *info, wl_bss_info_t *bi) { @@ -1420,6 +1439,7 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, return 0; } +#ifndef WL_ESCAN static int wl_iw_get_scan( struct net_device *dev, @@ -1681,10 +1701,11 @@ wl_iw_iscan_get_scan( dwrq->length = event - extra; dwrq->flags = 0; /* todo */ + WL_SCAN(("%s: apcnt=%d\n", __FUNCTION__, apcnt)); return 0; } - +#endif /* WL_ESCAN */ #endif /* WIRELESS_EXT > 13 */ @@ -2953,10 +2974,19 @@ static const iw_handler wl_iw_handler[] = #else (iw_handler) NULL, /* -- hole -- */ #endif +#ifdef WL_ESCAN + (iw_handler) NULL, /* SIOCGIWAPLIST */ +#else (iw_handler) wl_iw_iscan_get_aplist, /* SIOCGIWAPLIST */ +#endif #if WIRELESS_EXT > 13 +#ifdef WL_ESCAN + (iw_handler) wl_escan_set_scan, /* SIOCSIWSCAN */ + (iw_handler) wl_escan_get_scan, /* SIOCGIWSCAN */ +#else (iw_handler) wl_iw_iscan_set_scan, /* SIOCSIWSCAN */ (iw_handler) wl_iw_iscan_get_scan, /* SIOCGIWSCAN */ +#endif #else /* WIRELESS_EXT > 13 */ (iw_handler) NULL, /* SIOCSIWSCAN */ (iw_handler) NULL, /* SIOCGIWSCAN */ @@ -3095,9 +3125,11 @@ wl_iw_ioctl( #if WIRELESS_EXT > 13 case SIOCGIWSCAN: +#ifndef WL_ESCAN if (g_iscan) max_tokens = wrq->u.data.length; else +#endif max_tokens = IW_SCAN_MAX_DATA; break; #endif /* WIRELESS_EXT > 13 */ @@ -3377,6 +3409,13 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) } #endif /* WIRELESS_EXT > 17 */ +#ifdef WL_ESCAN + case WLC_E_ESCAN_RESULT: + WL_TRACE(("event WLC_E_ESCAN_RESULT\n")); + wl_escan_event(dev, e, data); + break; +#else + case WLC_E_SCAN_COMPLETE: #if WIRELESS_EXT > 14 cmd = SIOCGIWSCAN; @@ -3388,6 +3427,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) (g_iscan->iscan_state != ISCAN_STATE_IDLE)) up(&g_iscan->sysioc_sem); break; +#endif default: /* Cannot translate event */ @@ -3395,11 +3435,13 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) } if (cmd) { +#ifndef WL_ESCAN if (cmd == SIOCGIWSCAN) { if ((!g_iscan) || (g_iscan->sysioc_pid < 0)) { wireless_send_event(dev, cmd, &wrqu, NULL); }; } else +#endif wireless_send_event(dev, cmd, &wrqu, extra); } @@ -3597,6 +3639,7 @@ done: return res; } +#ifndef WL_ESCAN static void wl_iw_timerfunc(ulong data) { @@ -3810,10 +3853,12 @@ _iscan_sysioc_thread(void *data) printf("%s: was terminated\n", __FUNCTION__); complete_and_exit(&iscan->sysioc_exited, 0); } +#endif /* WL_ESCAN */ int wl_iw_attach(struct net_device *dev, void * dhdp) { +#ifndef WL_ESCAN iscan_info_t *iscan = NULL; printf("%s: Enter\n", __FUNCTION__); @@ -3851,11 +3896,13 @@ wl_iw_attach(struct net_device *dev, void * dhdp) #endif if (iscan->sysioc_pid < 0) return -ENOMEM; +#endif /* WL_ESCAN */ return 0; } void wl_iw_detach(void) { +#ifndef WL_ESCAN iscan_buf_t *buf; iscan_info_t *iscan = g_iscan; if (!iscan) @@ -3872,6 +3919,7 @@ void wl_iw_detach(void) } kfree(iscan); g_iscan = NULL; +#endif } #endif /* USE_IW */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.h old mode 100755 new mode 100644 index 6b86bb13a32c..dc80b2af0f05 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.h @@ -130,6 +130,10 @@ extern void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data); extern int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats); int wl_iw_attach(struct net_device *dev, void * dhdp); int wl_iw_send_priv_event(struct net_device *dev, char *flag); +#ifdef WL_ESCAN +int wl_iw_handle_scanresults_ies(char **event_p, char *end, + struct iw_request_info *info, wl_bss_info_t *bi); +#endif void wl_iw_detach(void); -- 2.34.1