*
* <<Broadcom-WL-IPTag/Open:>>
*
- * $Id: wl_cfg80211.c 798171 2019-01-07 09:10:40Z $
+ * $Id: wl_cfg80211.c 820080 2019-05-16 03:05:46Z $
*/
/* */
#include <typedefs.h>
static s32 wl_check_vif_support(struct bcm_cfg80211 *cfg, wl_iftype_t wl_iftype);
bool wl_is_wps_enrollee_active(struct net_device *ndev, const u8 *ie_ptr, u16 len);
-#ifdef WL_CFGVENDOR_SEND_HANG_EVENT
-static void wl_cfgvendor_send_hang_event(struct net_device *dev, u16 reason,
- char *string, int hang_info_cnt);
-static void wl_copy_hang_info_if_falure(struct net_device *dev, u16 reason, s32 err);
-#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
-
#ifdef WL_WPS_SYNC
static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg);
static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg);
#endif /* WL_WPS_SYNC */
const u8 *wl_find_attribute(const u8 *buf, u16 len, u16 element_id);
+#ifdef WL_BCNRECV
+static s32 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+#endif /* WL_BCNRECV */
+
static int bw2cap[] = { 0, 0, WLC_BW_CAP_20MHZ, WLC_BW_CAP_40MHZ, WLC_BW_CAP_80MHZ,
WLC_BW_CAP_160MHZ, WLC_BW_CAP_160MHZ };
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || (defined(CONFIG_ARCH_MSM) && \
- defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE))
-#define CFG80211_CONNECT_BSS(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || \
+ defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
+#define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
resp_ie_len, status, gfp) \
cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
#else
-#define CFG80211_CONNECT_BSS(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
+#define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
resp_ie_len, status, gfp) \
cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
resp_ie_len, status, gfp);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || \
- * (CONFIG_ARCH_MSM && CFG80211_CONNECT_TIMEOUT_REASON_CODE)
+ (CFG80211_CONNECT_TIMEOUT_REASON_CODE)
*/
+#elif defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
+/* There are customer kernels with backported changes for
+ * connect timeout. CFG80211_CONNECT_TIMEOUT_REASON_CODE define
+ * is available for kernels < 4.7 in such cases.
+ */
+#define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
+ resp_ie_len, status, gfp) \
+ cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, resp_ie, \
+ resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
+#else
+/* Kernels < 4.7 doesn't support cfg80211_connect_bss */
+#define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
+ resp_ie_len, status, gfp) \
+ cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, \
+ resp_ie_len, status, gfp);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) */
#ifdef RSSI_OFFSET
#define SOFT_AP_IF_NAME "swlan0"
+#ifdef P2P_LISTEN_OFFLOADING
+void wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg);
+#endif /* P2P_LISTEN_OFFLOADING */
+
#ifdef CUSTOMER_HW4_DEBUG
uint prev_dhd_console_ms = 0;
u32 prev_wl_dbg_level = 0;
#if defined(WL_CFG80211_P2P_DEV_IF)
if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
/* Handle Dedicated P2P discovery Interface */
- cfg->down_disc_if = FALSE;
return wl_cfgp2p_add_p2p_disc_if(cfg);
}
#endif /* WL_CFG80211_P2P_DEV_IF */
switch (state) {
case WL_IF_CREATE_REQ:
+#ifdef WL_BCNRECV
+ /* check fakeapscan in progress then abort */
+ wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
+#endif /* WL_BCNRECV */
wl_cfg80211_scan_abort(cfg);
wl_wlfc_enable(cfg, true);
#ifdef WL_CFG80211_P2P_DEV_IF
if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
/* Handle dedicated P2P discovery interface. */
-#ifdef CUSTOMER_HW4
- if (dhd_download_fw_on_driverload) {
- return wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
- } else {
- WL_INFORM_MEM(("skipping del p2p discovery\n"));
- cfg->down_disc_if = TRUE;
- return 0;
- }
-#else
return wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
-#endif /* CUSTOMER_HW4 */
}
#endif /* WL_CFG80211_P2P_DEV_IF */
return -EINVAL;
}
+ /* If any scan is going on, abort it */
+ if (wl_abort_scan_and_check(cfg) != TRUE) {
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+ }
+
mutex_lock(&cfg->if_sync);
netinfo = wl_get_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
if (unlikely(!netinfo)) {
goto fail;
}
- /* If any scan is going on, abort it */
- if (wl_abort_scan_and_check(cfg) != TRUE) {
- wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
- }
-
/* perform pre-if-change tasks */
wl_cfg80211_iface_state_ops(ndev->ieee80211_ptr,
WL_IF_CHANGE_REQ, wl_iftype, wl_mode);
WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
return -EOPNOTSUPP;
}
+#ifdef WL_BCNRECV
+ /* check fakeapscan in progress then abort */
+ wl_android_bcnrecv_stop(ndev, WL_BCNRECV_SCANBUSY);
+#endif /* WL_BCNRECV */
#ifdef P2P_LISTEN_OFFLOADING
if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
}
}
- mutex_lock(&cfg->usr_sync);
+ mutex_lock(&cfg->scan_sync);
err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
if (unlikely(err)) {
WL_ERR(("scan error (%d)\n", err));
mod_timer(&cfg->scan_timeout,
jiffies + msecs_to_jiffies(wl_get_scan_timeout_val(cfg)));
}
- mutex_unlock(&cfg->usr_sync);
+ mutex_unlock(&cfg->scan_sync);
#ifdef WL_DRV_AVOID_SCANCACHE
/* Reset roam cache after successful scan request */
#ifdef ROAM_CHANNEL_CACHE
u16 wl_iftype;
#ifdef WL_STATIC_IF
int need_legacy_war = 0;
+ dhd_pub_t *dhd = NULL;
#endif /* WL_STATIC_IF */
if (!ndev || !event) {
#ifdef WL_STATIC_IF
{
- need_legacy_war = ((wl_legacy_chip_check(cfg) ||
- wl_check_interface_create_v0(cfg)) &&
- !strnicmp(name, SOFT_AP_IF_NAME, strlen(SOFT_AP_IF_NAME)));
- if (need_legacy_war) {
- event->role = WLC_E_IF_ROLE_AP;
+ dhd = (dhd_pub_t *)(cfg->pub);
+ if (!DHD_OPMODE_SUPPORTED(dhd, DHD_FLAG_MFG_MODE) && name) {
+ need_legacy_war = ((wl_legacy_chip_check(cfg) ||
+ wl_check_interface_create_v0(cfg)) &&
+ !strnicmp(name, SOFT_AP_IF_NAME, strlen(SOFT_AP_IF_NAME)));
+ if (need_legacy_war) {
+ event->role = WLC_E_IF_ROLE_AP;
+ }
}
+ WL_DBG(("name: %s\n", name));
}
#endif /* WL_STATIC_IF */
wdev = new_ndev->ieee80211_ptr;
if (need_legacy_war) {
- s32 err;
+ /* Check whether mac addr is in sync with fw. If not,
+ * apply it using cur_etheraddr.
+ */
+ if (memcmp(addr, event->mac, ETH_ALEN) != 0) {
+ ret = wldev_iovar_setbuf_bsscfg(new_ndev, "cur_etheraddr",
+ addr, ETH_ALEN, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
+ event->bssidx, &cfg->ioctl_buf_sync);
+ if (unlikely(ret)) {
+ WL_ERR(("set cur_etheraddr Error (%d)\n", ret));
+ goto fail;
+ }
+ memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
+ WL_ERR(("Applying updated mac address to firmware\n"));
+ }
+
if (!wl_get_drv_status(cfg, AP_CREATED, new_ndev)) {
+ s32 err;
WL_INFORM_MEM(("[%s] Bringup SoftAP on bssidx:%d \n",
new_ndev->name, event->bssidx));
if ((err = wl_cfg80211_add_del_bss(cfg, new_ndev,
#ifdef ESCAN_CHANNEL_CACHE
chanspec_t chanspec_list[MAX_ROAM_CHANNEL];
#endif /* ESCAN_CHANNEL_CACHE */
-#if (defined(BCM4334_CHIP) || defined(BCM4359_CHIP) || !defined(ESCAN_RESULT_PATCH))
int wait_cnt;
-#endif // endif
WL_DBG(("In\n"));
if (!dev) {
/*
* Cancel ongoing scan to sync up with sme state machine of cfg80211.
*/
-#if (defined(BCM4359_CHIP) || !defined(ESCAN_RESULT_PATCH))
if (cfg->scan_request) {
WL_TRACE_HW4(("Aborting the scan! \n"));
wl_cfg80211_scan_abort(cfg);
wl_cfg80211_cancel_scan(cfg);
}
}
-#endif // endif
#ifdef WL_SCHED_SCAN
/* Locks are taken in wl_cfg80211_sched_scan_stop()
* A start scan occuring during connect is unlikely
}
}
+ if (sme->bssid) {
+ wl_update_prof(cfg, dev, NULL, sme->bssid, WL_PROF_LATEST_BSSID);
+ } else {
+ wl_update_prof(cfg, dev, NULL, ðer_bcast, WL_PROF_LATEST_BSSID);
+ }
+
/* 'connect' request received */
wl_set_drv_status(cfg, CONNECTING, dev);
/* clear nested connect bit on proceeding for connection */
/*
* Cancel ongoing scan to sync up with sme state machine of cfg80211.
*/
-#if !defined(ESCAN_RESULT_PATCH)
/* Let scan aborted by F/W */
if (cfg->scan_request) {
WL_TRACE_HW4(("Aborting the scan! \n"));
wl_cfg80211_cancel_scan(cfg);
}
-#endif /* ESCAN_RESULT_PATCH */
if (wl_get_drv_status(cfg, CONNECTING, dev) ||
wl_get_drv_status(cfg, CONNECTED, dev)) {
wl_set_drv_status(cfg, DISCONNECTING, dev);
}
#endif /* WPS_SYNC */
wl_cfg80211_wait_for_disconnection(cfg, dev);
+ if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
+ CFG80211_CONNECT_RESULT(dev, NULL, NULL,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
+ }
} else {
WL_INFORM_MEM(("act is false\n"));
+ CFG80211_CONNECT_RESULT(dev, NULL, NULL,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
}
#ifdef CUSTOM_SET_CPUCORE
/* set default cpucore */
struct net_device *ndev = NULL;
struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ RETURN_EIO_IF_NOT_UP(cfg);
#ifdef DHD_IFDEBUG
PRINT_WDEV_INFO(cfgdev);
#endif /* DHD_IFDEBUG */
}
#endif /* WL_NAN */
+ mutex_lock(&cfg->usr_sync);
WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n",
ieee80211_frequency_to_channel(channel->center_freq),
duration, (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES":"NO"));
goto exit;
}
-#ifdef P2P_LISTEN_OFFLOADING
- if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
- WL_ERR(("P2P_FIND: Discovery offload is in progress\n"));
- return -EAGAIN;
- }
-#endif /* P2P_LISTEN_OFFLOADING */
-
#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
if (wl_get_drv_status_all(cfg, SCANNING)) {
wl_cfg80211_cancel_scan(cfg);
}
#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+#ifdef P2P_LISTEN_OFFLOADING
+ wl_cfg80211_cancel_p2plo(cfg);
+#endif /* P2P_LISTEN_OFFLOADING */
+
target_channel = ieee80211_frequency_to_channel(channel->center_freq);
memcpy(&cfg->remain_on_chan, channel, sizeof(struct ieee80211_channel));
#if defined(WL_ENABLE_P2P_IF)
}
#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+#ifdef WL_BCNRECV
+ /* check fakeapscan in progress then abort */
+ wl_android_bcnrecv_stop(ndev, WL_BCNRECV_LISTENBUSY);
+#endif /* WL_BCNRECV */
#ifdef WL_CFG80211_SYNC_GON
if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
/* do not enter listen mode again if we are in listen mode already for next af.
} else {
WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie));
}
+ mutex_unlock(&cfg->usr_sync);
return err;
}
#ifdef BIGDATA_SOFTAP
wl_ap_stainfo_init(cfg);
#endif /* BIGDATA_SOFTAP */
+#ifdef WL_BCNRECV
+ /* check fakeapscan is in progress, if progress then abort */
+ wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
+#endif /* WL_BCNRECV */
return 0;
}
}
scb_val_t scbval;
u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
uint32 reason = 0;
+ bcm_tlv_t *deauth_info = NULL;
+ wips_detect_inform_t *wips_detect_info;
+ uint8 wips_bssid[ETHER_ADDR_LEN];
+ u32 len = ntoh32(e->datalen) + TLV_HDR_LEN;
+
struct ether_addr bssid_dongle = {{0, 0, 0, 0, 0, 0}};
struct ether_addr bssid_null = {{0, 0, 0, 0, 0, 0}};
"changed 0xFF\n", event, reason));
reason = WLC_E_DEAUTH_MAX_REASON;
}
+ if ((deauth_info = bcm_parse_tlvs(data, len,
+ TAG_DEAUTH_TLV_WIPS)) != NULL) {
+ wips_detect_info =
+ (wips_detect_inform_t *)deauth_info->data;
+ memcpy(wips_bssid, &wips_detect_info->ea,
+ ETHER_ADDR_LEN);
+ if (wips_detect_info->misdeauth > 1) {
+ WL_ERR(("WIPS attack!! cnt=%d, curRSSI=%d, "
+ "deauthRSSI=%d, time=%d, "
+ "MAC="MACDBG"\n",
+ wips_detect_info->misdeauth,
+ wips_detect_info->cur_bsscfg_rssi,
+ wips_detect_info->deauth_rssi,
+ wips_detect_info->timestamp,
+ MAC2STRDBG(wips_bssid)));
+ }
+ }
}
#ifdef SET_SSID_FAIL_CUSTOM_RC
if (event == WLC_E_SET_SSID) {
/* Dump FW preserve buffer content */
wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
- if (wl_get_drv_status(cfg, DISCONNECTING, ndev) &&
- wl_get_drv_status(cfg, CONNECTING, ndev)) {
- wl_clr_drv_status(cfg, DISCONNECTING, ndev);
- wl_clr_drv_status(cfg, CONNECTING, ndev);
- wl_cfg80211_scan_abort(cfg);
- DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
- return err;
- }
/* Clean up any pending scan request */
wl_cfg80211_cancel_scan(cfg);
- if (wl_get_drv_status(cfg, CONNECTING, ndev))
+ if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
+ if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
+ WL_INFORM_MEM(("wl dissassoc\n"));
+ err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
+ if (err < 0) {
+ WL_ERR(("WLC_DISASSOC error %d\n", err));
+ err = 0;
+ }
+ } else {
+ WL_DBG(("connect fail. clear disconnecting bit\n"));
+ wl_clr_drv_status(cfg, DISCONNECTING, ndev);
+ }
wl_bss_connect_done(cfg, ndev, e, data, false);
+ wl_clr_drv_status(cfg, CONNECTING, ndev);
+ WL_INFORM_MEM(("connect fail reported\n"));
+ }
} else {
WL_DBG(("%s nothing\n", __FUNCTION__));
}
completed = false;
sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
- CFG80211_CONNECT_BSS(ndev,
+
+ CFG80211_CONNECT_RESULT(ndev,
curbssid,
bss,
conn_info->req_ie,
sec->auth_assoc_res_status :
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
-#else
- cfg80211_connect_result(ndev,
- curbssid,
- conn_info->req_ie,
- conn_info->req_ie_len,
- conn_info->resp_ie,
- conn_info->resp_ie_len,
- completed ? WLAN_STATUS_SUCCESS :
- (sec->auth_assoc_res_status) ?
- sec->auth_assoc_res_status :
- WLAN_STATUS_UNSPECIFIED_FAILURE,
- GFP_KERNEL);
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) */
+
if (completed) {
WL_INFORM_MEM(("[%s] Report connect result - "
"connection succeeded\n", ndev->name));
}
ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
- mutex_lock(&cfg->usr_sync);
+ mutex_lock(&cfg->scan_sync);
wl_clr_drv_status(cfg, SCANNING, ndev);
memset(&channel_inform, 0, sizeof(channel_inform));
err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &channel_inform,
}
spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
WL_DBG(("cfg80211_scan_done\n"));
- mutex_unlock(&cfg->usr_sync);
+ mutex_unlock(&cfg->scan_sync);
return err;
}
#ifdef WL_BAM
cfg->evt_handler[WLC_E_ADPS] = wl_adps_event_handler;
#endif /* WL_BAM */
+#ifdef WL_BCNRECV
+ cfg->evt_handler[WLC_E_BCNRECV_ABORTED] = wl_bcnrecv_aborted_event_handler;
+#endif /* WL_BCNRECV */
}
#if defined(STATIC_WL_PRIV_STRUCT)
#ifdef DHD_FW_COREDUMP
uint32 prev_memdump_mode = dhdp->memdump_enabled;
#endif /* DHD_FW_COREDUMP */
+ unsigned long flags;
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
if (!(cfg->scan_request)) {
WL_ERR(("timer expired but no scan request\n"));
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
return;
+ } else {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+ if (cfg->scan_request->dev) {
+ wdev = cfg->scan_request->dev->ieee80211_ptr;
+ }
+#else
+ wdev = cfg->scan_request->wdev;
+#endif /* LINUX_VERSION < KERNEL_VERSION(3, 6, 0) */
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+
+ if (!wdev) {
+ WL_ERR(("No wireless_dev present\n"));
+ return;
+ }
}
#if defined(DHD_KERNEL_SCHED_DEBUG) && defined(DHD_FW_COREDUMP)
mutex_is_locked(&cfg->if_sync),
mutex_is_locked(&cfg->usr_sync),
mutex_is_locked(&cfg->pm_sync),
- mutex_is_locked(&cfg->scan_complete),
+ mutex_is_locked(&cfg->scan_sync),
spin_is_locked(&cfg->cfgdrv_lock),
spin_is_locked(&cfg->eq_lock)));
dhd_bus_intr_count_dump(dhdp);
}
}
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
- if (cfg->scan_request->dev)
- wdev = cfg->scan_request->dev->ieee80211_ptr;
-#else
- wdev = cfg->scan_request->wdev;
-#endif /* LINUX_VERSION < KERNEL_VERSION(3, 6, 0) */
- if (!wdev) {
- WL_ERR(("No wireless_dev present\n"));
- return;
- }
ndev = wdev_to_wlc_ndev(wdev, cfg);
-
bzero(&msg, sizeof(wl_event_msg_t));
WL_ERR(("timer expired\n"));
#ifdef BCMPCIE
struct wireless_dev *wdev = NULL;
struct net_device *ndev = NULL;
- if (!cfg->scan_request)
- return;
+ mutex_lock(&cfg->scan_sync);
+ if (!cfg->scan_request) {
+ goto exit;
+ }
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
if (cfg->scan_request->dev)
if (!wdev) {
WL_ERR(("No wireless_dev present\n"));
- return;
+ goto exit;
}
ndev = wdev_to_wlc_ndev(wdev, cfg);
wl_notify_escan_complete(cfg, ndev, true, true);
WL_INFORM_MEM(("Scan aborted! \n"));
+exit:
+ mutex_unlock(&cfg->scan_sync);
}
void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg)
WL_DBG(("Enter \n"));
BCM_REFERENCE(dhdp);
- mutex_lock(&cfg->scan_complete);
if (!ndev) {
WL_ERR(("ndev is null\n"));
err = BCME_ERROR;
spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
out:
- mutex_unlock(&cfg->scan_complete);
return err;
}
}
#endif /* WL_DRV_AVOID_SCANCACHE */
+
+#ifdef WL_BCNRECV
+/* Beacon recv results handler sending to upper layer */
+static s32
+wl_bcnrecv_result_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ wl_bss_info_v109_2_t *bi, uint32 scan_status)
+{
+ s32 err = BCME_OK;
+ struct wiphy *wiphy = NULL;
+ wl_bcnrecv_result_t *bcn_recv = NULL;
+ struct timespec ts;
+ if (!bi) {
+ WL_ERR(("%s: bi is NULL\n", __func__));
+ err = BCME_NORESOURCE;
+ goto exit;
+ }
+ if ((bi->length - bi->ie_length) < sizeof(wl_bss_info_v109_2_t)) {
+ WL_ERR(("bi info version doesn't support bcn_recv attributes\n"));
+ goto exit;
+ }
+
+ if (scan_status == WLC_E_STATUS_RXBCN) {
+ wiphy = cfg->wdev->wiphy;
+ if (!wiphy) {
+ WL_ERR(("wiphy is NULL\n"));
+ err = BCME_NORESOURCE;
+ goto exit;
+ }
+ bcn_recv = (wl_bcnrecv_result_t *)MALLOCZ(cfg->osh, sizeof(*bcn_recv));
+ if (unlikely(!bcn_recv)) {
+ WL_ERR(("Failed to allocate memory\n"));
+ return -ENOMEM;
+ }
+ memcpy((char *)bcn_recv->SSID, (char *)bi->SSID, DOT11_MAX_SSID_LEN);
+ memcpy(&bcn_recv->BSSID, &bi->BSSID, ETH_ALEN);
+ bcn_recv->channel = wf_chspec_ctlchan(
+ wl_chspec_driver_to_host(bi->chanspec));
+ bcn_recv->beacon_interval = bi->beacon_period;
+
+ /* kernal timestamp */
+ get_monotonic_boottime(&ts);
+ bcn_recv->system_time = ((u64)ts.tv_sec*1000000)
+ + ts.tv_nsec / 1000;
+ bcn_recv->timestamp[0] = bi->timestamp[0];
+ bcn_recv->timestamp[1] = bi->timestamp[1];
+ if (bcn_recv) {
+ if ((err = wl_android_bcnrecv_event(cfgdev_to_wlc_ndev(cfgdev, cfg),
+ BCNRECV_ATTR_BCNINFO, 0, 0, (uint8 *)bcn_recv, sizeof(*bcn_recv)))
+ != BCME_OK) {
+ WL_ERR(("failed to send bcnrecv event, error:%d\n", err));
+ }
+ }
+ } else {
+ WL_DBG(("Ignoring Escan Event:%d \n", scan_status));
+ }
+exit:
+ if (bcn_recv) {
+ MFREE(cfg->osh, bcn_recv, sizeof(*bcn_recv));
+ }
+ return err;
+}
+#endif /* WL_BCNRECV */
+
static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
const wl_event_msg_t *e, void *data)
{
ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
- mutex_lock(&cfg->usr_sync);
+ mutex_lock(&cfg->scan_sync);
/* P2P SCAN is coming from primary interface */
if (wl_get_p2p_status(cfg, SCANNING)) {
if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM))
ndev = cfg->afx_hdl->dev;
else
ndev = cfg->escan_info.ndev;
-
}
+ escan_result = (wl_escan_result_t *)data;
+#ifdef WL_BCNRECV
+ if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED &&
+ status == WLC_E_STATUS_RXBCN) {
+ /* handle beacon recv scan results */
+ wl_bss_info_v109_2_t *bi_info;
+ bi_info = (wl_bss_info_v109_2_t *)escan_result->bss_info;
+ err = wl_bcnrecv_result_handler(cfg, cfgdev, bi_info, status);
+ goto exit;
+ }
+#endif /* WL_BCNRECV */
if (!ndev || (!wl_get_drv_status(cfg, SCANNING, ndev) && !cfg->sched_scan_running)) {
WL_ERR_RLMT(("escan is not ready. drv_scan_status 0x%x"
" e_type %d e_states %d\n",
ntoh32(e->event_type), ntoh32(e->status)));
goto exit;
}
- escan_result = (wl_escan_result_t *)data;
#ifndef WL_DRV_AVOID_SCANCACHE
if (status == WLC_E_STATUS_PARTIAL) {
err = wl_escan_without_scan_cache(cfg, escan_result, ndev, e, status);
#endif /* WL_DRV_AVOID_SCANCACHE */
exit:
- mutex_unlock(&cfg->usr_sync);
+ mutex_unlock(&cfg->scan_sync);
return err;
}
wl_init_event_handler(cfg);
mutex_init(&cfg->usr_sync);
mutex_init(&cfg->event_sync);
- mutex_init(&cfg->scan_complete);
mutex_init(&cfg->if_sync);
+ mutex_init(&cfg->scan_sync);
#ifdef WLTDLS
mutex_init(&cfg->tdls_sync);
#endif /* WLTDLS */
+#ifdef WL_BCNRECV
+ mutex_init(&cfg->bcn_sync);
+#endif /* WL_BCNRECV */
#ifdef WL_WPS_SYNC
wl_init_wps_reauth_sm(cfg);
#endif /* WL_WPS_SYNC */
return 0;
}
+#ifdef WL_BCNRECV
+static s32
+wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 status = ntoh32(e->status);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ /* Abort fakeapscan, when Roam is in progress */
+ if (status == WLC_E_STATUS_RXBCN_ABORT) {
+ wl_android_bcnrecv_stop(ndev, WL_BCNRECV_ROAMABORT);
+ } else {
+ WL_ERR(("UNKNOWN STATUS. status:%d\n", status));
+ }
+ return BCME_OK;
+}
+#endif /* WL_BCNRECV */
+
+/* Get the concurrency mode */
+int wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 *cfg)
+{
+ struct net_info *iter, *next;
+ uint cmode = CONCURRENCY_MODE_NONE;
+ u32 connected_cnt = 0;
+ u32 pre_channel = 0, channel = 0;
+ u32 pre_band = 0;
+ u32 chanspec = 0;
+ u32 band = 0;
+
+ connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
+ if (connected_cnt <= 1) {
+ return cmode;
+ }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif // endif
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev) {
+ if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
+ if (wldev_iovar_getint(iter->ndev, "chanspec",
+ (s32 *)&chanspec) == BCME_OK) {
+ channel = wf_chspec_ctlchan(
+ wl_chspec_driver_to_host(chanspec));
+ band = (channel <= CH_MAX_2G_CHANNEL) ?
+ IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+ }
+ if ((!pre_channel && channel)) {
+ pre_band = band;
+ pre_channel = channel;
+ } else if (pre_channel) {
+ if ((pre_band == band) && (pre_channel == channel)) {
+ cmode = CONCURRENCY_SCC_MODE;
+ goto exit;
+ } else if ((pre_band == band) && (pre_channel != channel)) {
+ cmode = CONCURRENCY_VSDB_MODE;
+ goto exit;
+ } else if (pre_band != band) {
+ cmode = CONCURRENCY_RSDB_MODE;
+ goto exit;
+ }
+ }
+ }
+ }
+ }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif // endif
+exit:
+ return cmode;
+}
s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
{
s32 err;
if (iter->ndev == NULL)
continue;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+ WL_INFORM_MEM(("wl_cfg80211_down. connection state bit status: [%u:%u:%u:%u]\n",
+ wl_get_drv_status(cfg, CONNECTING, ndev),
+ wl_get_drv_status(cfg, CONNECTED, ndev),
+ wl_get_drv_status(cfg, DISCONNECTING, ndev),
+ wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
+
if ((iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
CFG80211_DISCONNECTED(iter->ndev, 0, NULL, 0, false, GFP_KERNEL);
}
+
+ if ((iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
+ wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
+ u8 *latest_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
+ struct cfg80211_bss *bss = CFG80211_GET_BSS(wiphy, NULL, latest_bssid,
+ wdev->ssid, wdev->ssid_len);
+
+ prhex("bssid:", (uchar *)latest_bssid, ETHER_ADDR_LEN);
+ prhex("ssid:", (uchar *)wdev->ssid, wdev->ssid_len);
+ if (!bss) {
+ WL_DBG(("null bss\n"));
+ }
+
+ CFG80211_CONNECT_RESULT(ndev,
+ latest_bssid, bss, NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
+ }
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
wl_clr_drv_status(cfg, READY, iter->ndev);
wl_clr_drv_status(cfg, SCANNING, iter->ndev);
case WL_PROF_CHAN:
rptr = &profile->channel;
break;
+ case WL_PROF_LATEST_BSSID:
+ rptr = profile->latest_bssid;
+ break;
}
spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
if (!rptr)
case WL_PROF_CHAN:
profile->channel = *(const u32*)data;
break;
+ case WL_PROF_LATEST_BSSID:
+ if (data) {
+ memcpy(profile->latest_bssid, data, ETHER_ADDR_LEN);
+ } else {
+ memset(profile->latest_bssid, 0, ETHER_ADDR_LEN);
+ }
+ break;
default:
err = -EOPNOTSUPP;
break;
struct net_info *netinfo;
struct wireless_dev *wdev;
+ if (!cfgdev) {
+ WL_ERR(("cfgdev is NULL\n"));
+ return -EINVAL;
+ }
+
ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
wdev = cfgdev_to_wdev(cfgdev);
wdev = cfg->p2p_wdev;
}
- if (wdev && cfg->down_disc_if) {
+ if (wdev) {
wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
- cfg->down_disc_if = FALSE;
}
}
#endif /* WL_CFG80211_P2P_DEV_IF */
}
#endif /* DHD_LOG_DUMP */
-#ifdef WL_CFGVENDOR_SEND_HANG_EVENT
-static void
-wl_cfgvendor_send_hang_event(struct net_device *dev, u16 reason, char *string, int hang_info_cnt)
-{
- struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
- struct wiphy *wiphy;
- char *hang_info;
- int len = 0;
- int bytes_written;
- uint32 dumy_data = 0;
- int reason_hang_info = 0;
- int cnt = 0;
- dhd_pub_t *dhd;
- int hang_reason_mismatch = FALSE;
-
- if (!cfg || !cfg->wdev) {
- WL_ERR(("cfg=%p wdev=%p\n", cfg, (cfg ? cfg->wdev : NULL)));
- return;
- }
-
- wiphy = cfg->wdev->wiphy;
-
- if (!wiphy) {
- WL_ERR(("wiphy is NULL\n"));
- return;
- }
-
- hang_info = MALLOCZ(cfg->osh, VENDOR_SEND_HANG_EXT_INFO_LEN);
- if (hang_info == NULL) {
- WL_ERR(("alloc hang_info failed\n"));
- return;
- }
-
- dhd = (dhd_pub_t *)(cfg->pub);
-
- sscanf(string, "%d", &reason_hang_info);
- bytes_written = 0;
- len = VENDOR_SEND_HANG_EXT_INFO_LEN - bytes_written;
- if (strlen(string) == 0 || (reason_hang_info != reason)) {
- WL_ERR(("hang reason mismatch: string len %d reason_hang_info %d\n",
- (int)strlen(string), reason_hang_info));
- hang_reason_mismatch = TRUE;
- if (dhd) {
- get_debug_dump_time(dhd->debug_dump_time_hang_str);
- copy_debug_dump_time(dhd->debug_dump_time_str,
- dhd->debug_dump_time_hang_str);
- }
- bytes_written += scnprintf(&hang_info[bytes_written], len,
- "%d %d %s %08x %08x %08x %08x %08x %08x %08x",
- reason, VENDOR_SEND_HANG_EXT_INFO_VER,
- dhd->debug_dump_time_hang_str,
- 0, 0, 0, 0, 0, 0, 0);
- if (dhd) {
- clear_debug_dump_time(dhd->debug_dump_time_hang_str);
- }
- } else {
- bytes_written += scnprintf(&hang_info[bytes_written], len, "%s", string);
- }
-
- WL_ERR(("hang reason: %d info cnt: %d\n", reason, hang_info_cnt));
-
- if (hang_reason_mismatch == FALSE) {
- cnt = hang_info_cnt;
- } else {
- cnt = HANG_FIELD_MISMATCH_CNT;
- }
-
- while (cnt < HANG_FIELD_CNT_MAX) {
- len = VENDOR_SEND_HANG_EXT_INFO_LEN - bytes_written;
- bytes_written += scnprintf(&hang_info[bytes_written], len,
- "%c%08x", HANG_RAW_DEL, dumy_data);
- cnt++;
- }
-
- WL_ERR(("hang info cnt: %d len: %d\n", cnt, (int)strlen(hang_info)));
- WL_ERR(("hang info data: %s\n", hang_info));
-
- wl_cfgvendor_send_async_event(wiphy,
- bcmcfg_to_prmry_ndev(cfg), BRCM_VENDOR_EVENT_HANGED,
- hang_info, (int)strlen(hang_info));
-
- memset(string, 0, VENDOR_SEND_HANG_EXT_INFO_LEN);
-
- if (hang_info) {
- MFREE(cfg->osh, hang_info, VENDOR_SEND_HANG_EXT_INFO_LEN);
- }
-
-#ifdef DHD_LOG_DUMP
- if (dhd->debug_dump_time_hang_str) {
- dhd_logdump_cookie_save(dhd, dhd->debug_dump_time_hang_str, "HANG");
- }
-#endif /* DHD_LOG_DUMP */
-
- if (dhd) {
- clear_debug_dump_time(dhd->debug_dump_time_str);
- }
-}
-
-void
-wl_copy_hang_info_if_falure(struct net_device *dev, u16 reason, s32 ret)
-{
- struct bcm_cfg80211 *cfg = NULL;
- dhd_pub_t *dhd;
- s32 err = 0;
- char ioctl_buf[WLC_IOCTL_SMLEN];
- memuse_info_t mu;
- int bytes_written = 0;
- int remain_len = 0;
-
- if (!dev) {
- WL_ERR(("dev is null"));
- return;
-
- }
-
- cfg = wl_get_cfg(dev);
- if (!cfg) {
- WL_ERR(("dev=%p cfg=%p\n", dev, cfg));
- return;
- }
-
- dhd = (dhd_pub_t *)(cfg->pub);
-
- if (!dhd || !dhd->hang_info) {
- WL_ERR(("%s dhd=%p hang_info=%p\n", __FUNCTION__,
- dhd, (dhd ? dhd->hang_info : NULL)));
- return;
- }
-
- err = wldev_iovar_getbuf_bsscfg(dev, "memuse",
- NULL, 0, ioctl_buf, WLC_IOCTL_SMLEN, 0, NULL);
- if (unlikely(err)) {
- WL_ERR(("error (%d)\n", err));
- return;
- }
-
- memcpy(&mu, ioctl_buf, sizeof(memuse_info_t));
-
- if (mu.len >= sizeof(memuse_info_t)) {
- WL_ERR(("Heap Total: %d(%dK)\n", mu.arena_size, KB(mu.arena_size)));
- WL_ERR(("Free: %d(%dK), LWM: %d(%dK)\n",
- mu.arena_free, KB(mu.arena_free),
- mu.free_lwm, KB(mu.free_lwm)));
- WL_ERR(("In use: %d(%dK), HWM: %d(%dK)\n",
- mu.inuse_size, KB(mu.inuse_size),
- mu.inuse_hwm, KB(mu.inuse_hwm)));
- WL_ERR(("Malloc failure count: %d\n", mu.mf_count));
- }
-
- memset(dhd->hang_info, 0, VENDOR_SEND_HANG_EXT_INFO_LEN);
- remain_len = VENDOR_SEND_HANG_EXT_INFO_LEN - bytes_written;
-
- get_debug_dump_time(dhd->debug_dump_time_hang_str);
- copy_debug_dump_time(dhd->debug_dump_time_str, dhd->debug_dump_time_hang_str);
-
- bytes_written += scnprintf(&dhd->hang_info[bytes_written], remain_len,
- "%d %d %s %d %d %d %d %d %08x %08x",
- reason, VENDOR_SEND_HANG_EXT_INFO_VER,
- dhd->debug_dump_time_hang_str,
- ret, mu.arena_size, mu.arena_free, mu.inuse_size, mu.mf_count, 0, 0);
-
- dhd->hang_info_cnt = HANG_FIELD_IF_FAILURE_CNT;
-
- clear_debug_dump_time(dhd->debug_dump_time_hang_str);
-
- return;
-}
-#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
-
s32
wl_cfg80211_set_dbg_verbose(struct net_device *ndev, u32 level)
{