From: Mahesh Patil Date: Mon, 27 Mar 2017 20:05:09 +0000 (-0700) Subject: Adding NOTASSOCIATED FW error to disconnect wifi X-Git-Url: https://rtime.felk.cvut.cz/gitweb/hercules2020/nv-tegra/linux-4.4.git/commitdiff_plain/a5f451ddf7184807c77fbbac6a386aee620d38ae Adding NOTASSOCIATED FW error to disconnect wifi Adding NOTASSOCIATED error from FW to Disconnect wifi and setting disconnect timer to 5 sec Bug 200215502 Bug 200305758 Bug 200308970 Change-Id: I205f6a73780f5a5980851cb805c263e2ed9270c1 Signed-off-by: Mahesh Patil (cherry pick from commit f3e9994f9d2a12dea5a65df10a268dda5351c5a8) Reviewed-on: http://git-master/r/1482285 Reviewed-by: mobile promotions Tested-by: mobile promotions --- diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 8bb8e16585da..79355cf25302 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -1115,6 +1115,8 @@ int wl_android_wifi_off(struct net_device *dev) DHD_TRACE(("%s: dev is null\n", __FUNCTION__)); return -EINVAL; } + wl_fw_assoc_timeout_cancel(); + #ifdef CONFIG_BCMDHD_CUSTOM_SYSFS_TEGRA tegra_sysfs_off(); #endif diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c old mode 100755 new mode 100644 index eb958a6a802d..75b0f4b13b92 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -2,7 +2,7 @@ * Linux cfg80211 driver * * Copyright (C) 1999-2015, Broadcom Corporation - * + * * Portions contributed by Nvidia * Copyright (C) 2015-2017 NVIDIA Corporation. All rights reserved. * @@ -11,7 +11,7 @@ * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -19,7 +19,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -876,6 +876,10 @@ static const struct { }; #endif +/* watchdog work for disconnecting when fw is not associated +for FW_ASSOC_WATCHDOG_TIME ms */ +static struct fw_assoc_timeout_work fw_assoc_timeout; +#define FW_ASSOC_WATCHDOG_TIME (5 * 1000) /* msec */ static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg, bool add_remove, enum wl_handler_del_type type) @@ -4209,6 +4213,10 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, } RETURN_EIO_IF_NOT_UP(cfg); + /* cancel FW assoc timeout watchdog if set */ + if (fw_assoc_timeout.fw_assoc_watchdog_started) { + wl_fw_assoc_timeout_cancel(); + } /* * Cancel ongoing scan to sync up with sme state machine of cfg80211. @@ -4508,6 +4516,12 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, else TEGRA_SYSFS_HISTOGRAM_STAT_INC(disconnect_rssi_high); #endif + + /* cancel FW assoc timeout watchdog if set */ + if (fw_assoc_timeout.fw_assoc_watchdog_started) { + wl_fw_assoc_timeout_cancel(); + } + RETURN_EIO_IF_NOT_UP(cfg); act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT); curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID); @@ -5015,6 +5029,50 @@ wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, return -EOPNOTSUPP; #endif /* MFP */ } +static void +fw_assoc_timeout_fn(struct work_struct *work) +{ + struct delayed_work *delay_work = container_of(work, struct delayed_work, work); + struct fw_assoc_timeout_work *fw_assoc_timeout = container_of(delay_work, struct fw_assoc_timeout_work, delay_work); + struct bcm_cfg80211 *cfg = fw_assoc_timeout->cfg; + struct net_device *dev = fw_assoc_timeout->dev; + scb_val_t scbval; + s32 err = 0; + u8 *curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID); + + scbval.val = WLAN_REASON_DEAUTH_LEAVING; + memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); + scbval.val = htod32(scbval.val); + err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); + if (err < 0) { + WL_ERR(("WLC_DISASSOC error %d\n", err)); + } + memset(&cfg->last_roamed_addr, 0, ETHER_ADDR_LEN); + /* Disconnect due to zero BSSID */ + wl_clr_drv_status(cfg, CONNECTED, dev); + CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL); + wl_link_down(cfg); + wl_init_prof(cfg, dev); + fw_assoc_timeout->fw_assoc_watchdog_started = FALSE; + WL_ERR(("force cfg80211_disconnected\n")); +} + +void +wl_fw_assoc_timeout_init() +{ + INIT_DELAYED_WORK(&fw_assoc_timeout.delay_work, fw_assoc_timeout_fn); + fw_assoc_timeout.fw_assoc_watchdog_started = FALSE; +} + +void +wl_fw_assoc_timeout_cancel() +{ + if (delayed_work_pending(&fw_assoc_timeout.delay_work)) { + WL_ERR(("cancelling fw_assoc_watchdog work\n")); + cancel_delayed_work_sync(&fw_assoc_timeout.delay_work); + fw_assoc_timeout.fw_assoc_watchdog_started = FALSE; + } +} #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) static s32 @@ -5036,6 +5094,8 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, s8 eabuf[ETHER_ADDR_STR_LEN]; #endif dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + bool fw_assoc_state = FALSE; + u32 dhd_assoc_state = 0; RETURN_EIO_IF_NOT_UP(cfg); if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) { err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac, @@ -5082,14 +5142,38 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, } } } - if (!wl_get_drv_status(cfg, CONNECTED, dev) || - (dhd_is_associated(dhd, NULL, &err) == FALSE)) { - WL_ERR(("NOT assoc\n")); - if (err == -ERESTARTSYS) + dhd_assoc_state = wl_get_drv_status(cfg, CONNECTED, dev); + fw_assoc_state = dhd_is_associated(dhd, NULL, &err); + if (!dhd_assoc_state || !fw_assoc_state) { + WL_ERR(("NOT assoc, error %d\n", err)); + if (err == -ENODATA) return err; + if (!dhd_assoc_state) { + WL_TRACE_HW4(("drv state is not connected \n")); + } + if (!fw_assoc_state) { + WL_TRACE_HW4(("fw state is not associated \n")); + } + /* Disconnect due to fw is not associated for FW_ASSOC_WATCHDOG_TIME ms. + * 'err == 0 or BCME_NOTASSOCIATED' of dhd_is_associated() and '!fw_assoc_state' + * means that BSSID is null. + */ + if (dhd_assoc_state && !fw_assoc_state && (err == BCME_NOTASSOCIATED || !err)) { + if (!fw_assoc_timeout.fw_assoc_watchdog_started) { + fw_assoc_timeout.dev = dev; + fw_assoc_timeout.cfg = cfg; + schedule_delayed_work(&fw_assoc_timeout.delay_work, msecs_to_jiffies(FW_ASSOC_WATCHDOG_TIME)); + fw_assoc_timeout.fw_assoc_watchdog_started = TRUE; + WL_INFORM(("fw_assoc_watchdog_started\n")); + } + } err = -ENODEV; return err; } + if (fw_assoc_timeout.fw_assoc_watchdog_started) { + WL_INFORM(("cancelling fw_assoc_watchdog work\n")); + wl_fw_assoc_timeout_cancel(); + } curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID); if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n", @@ -11848,7 +11932,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *context) cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev); if (!cfg->btcoex_info) goto cfg80211_attach_out; -#endif +#endif g_bcm_cfg = cfg; @@ -11858,7 +11942,8 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *context) if (err) goto cfg80211_attach_out; #endif -#endif +#endif + wl_fw_assoc_timeout_init(); return err; @@ -11876,13 +11961,14 @@ void wl_cfg80211_detach(void *para) cfg = g_bcm_cfg; WL_TRACE(("In\n")); + wl_fw_assoc_timeout_cancel(); wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL); #if defined(COEX_DHCP) wl_cfg80211_btcoex_deinit(); cfg->btcoex_info = NULL; -#endif +#endif wl_setup_rfkill(cfg, FALSE); #ifdef DEBUGFS_CFG80211 diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 25db70a0214c..d2e71252a9ef 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -638,6 +638,15 @@ struct bcm_cfg80211 { struct ether_addr last_roamed_addr; }; +struct fw_assoc_timeout_work { + struct delayed_work delay_work; + struct net_device *dev; + struct bcm_cfg80211 *cfg; + bool fw_assoc_watchdog_started; +}; +void wl_fw_assoc_timeout_init(void); +void wl_fw_assoc_timeout_cancel(void); + static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) {