From 83195cc8a83df3546d72873ca2aed51f97b0c901 Mon Sep 17 00:00:00 2001 From: Vipin Mehta Date: Fri, 18 Feb 2011 13:13:05 -0800 Subject: [PATCH] staging: ath6kl: Fixing target crash due to mismatch connect/disconnect Firmware design requires a WMI_DISCONNECT_CMD for every WMI_CONNECT_CMD to clear the firmware previous profile state. There is one case in linux host driver where two WMI_CONNECT_CMD are given without a WMI_DISCONNECT_CMD. This causes firmware state to mismatch causing an ASSERT. Use the driver state variable arConnectPending to track whether a WMI_CONNECT_CMD is issued to firmware. Signed-off-by: Vipin Mehta Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ath6kl/os/linux/ar6000_drv.c | 50 ++++++++++--------- drivers/staging/ath6kl/os/linux/cfg80211.c | 7 +-- .../ath6kl/os/linux/include/ar6xapi_linux.h | 1 + .../staging/ath6kl/os/linux/wireless_ext.c | 11 ++-- 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/drivers/staging/ath6kl/os/linux/ar6000_drv.c b/drivers/staging/ath6kl/os/linux/ar6000_drv.c index 4f6ddf759493..df9badbc052c 100644 --- a/drivers/staging/ath6kl/os/linux/ar6000_drv.c +++ b/drivers/staging/ath6kl/os/linux/ar6000_drv.c @@ -1943,15 +1943,12 @@ ar6000_stop_endpoint(struct net_device *dev, bool keepprofile, bool getdbglogs) { if (!bypasswmi) { - if (ar->arConnected == true || ar->arConnectPending == true) - { - AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("%s(): Disconnect\n", __func__)); - if (!keepprofile) { - AR6000_SPIN_LOCK(&ar->arLock, 0); - ar6000_init_profile_info(ar); - AR6000_SPIN_UNLOCK(&ar->arLock, 0); - } - wmi_disconnect_cmd(ar->arWmi); + bool disconnectIssued; + + disconnectIssued = (ar->arConnected) || (ar->arConnectPending); + ar6000_disconnect(ar); + if (!keepprofile) { + ar6000_init_profile_info(ar); } A_UNTIMEOUT(&ar->disconnect_timer); @@ -1973,14 +1970,12 @@ ar6000_stop_endpoint(struct net_device *dev, bool keepprofile, bool getdbglogs) * Sometimes disconnect_event will be received when the debug logs * are collected. */ - if (ar->arConnected == true || ar->arConnectPending == true) { + if (disconnectIssued) { if(ar->arNetworkType & AP_NETWORK) { ar6000_disconnect_event(ar, DISCONNECT_CMD, bcast_mac, 0, NULL, 0); } else { ar6000_disconnect_event(ar, DISCONNECT_CMD, ar->arBssid, 0, NULL, 0); } - ar->arConnected = false; - ar->arConnectPending = false; } #ifdef USER_KEYS ar->user_savedkeys_stat = USER_SAVEDKEYS_STAT_INIT; @@ -2163,7 +2158,7 @@ static void disconnect_timer_handler(unsigned long ptr) A_UNTIMEOUT(&ar->disconnect_timer); ar6000_init_profile_info(ar); - wmi_disconnect_cmd(ar->arWmi); + ar6000_disconnect(ar); } static void ar6000_detect_error(unsigned long ptr) @@ -2235,7 +2230,6 @@ void ar6000_init_profile_info(AR_SOFTC_T *ar) A_MEMZERO(ar->arReqBssid, sizeof(ar->arReqBssid)); A_MEMZERO(ar->arBssid, sizeof(ar->arBssid)); ar->arBssChannel = 0; - ar->arConnected = false; } static void @@ -2322,13 +2316,7 @@ ar6000_close(struct net_device *dev) netif_stop_queue(dev); #ifdef ATH6K_CONFIG_CFG80211 - AR6000_SPIN_LOCK(&ar->arLock, 0); - if (ar->arConnected == true || ar->arConnectPending == true) { - AR6000_SPIN_UNLOCK(&ar->arLock, 0); - wmi_disconnect_cmd(ar->arWmi); - } else { - AR6000_SPIN_UNLOCK(&ar->arLock, 0); - } + ar6000_disconnect(ar); if(ar->arWmiReady == true) { if (wmi_scanparams_cmd(ar->arWmi, 0xFFFF, 0, @@ -4608,6 +4596,8 @@ ar6000_disconnect_event(AR_SOFTC_T *ar, u8 reason, u8 *bssid, A_MEMCPY(wrqu.addr.sa_data, bssid, ATH_MAC_LEN); wireless_send_event(ar->arNetDev, IWEVEXPIRED, &wrqu, NULL); } + + ar->arConnected = false; return; } @@ -4652,7 +4642,6 @@ ar6000_disconnect_event(AR_SOFTC_T *ar, u8 reason, u8 *bssid, */ if( reason == DISCONNECT_CMD) { - ar->arConnectPending = false; if ((!ar->arUserBssFilter) && (ar->arWmiReady)) { wmi_bssfilter_cmd(ar->arWmi, NONE_BSS_FILTER, 0); } @@ -6084,8 +6073,6 @@ ar6000_ap_mode_profile_commit(struct ar6_softc *ar) p.groupCryptoLen = ar->arGroupCryptoLen; p.ctrl_flags = ar->arConnectCtrlFlags; - ar->arConnected = false; - wmi_ap_profile_commit(ar->arWmi, &p); spin_lock_irqsave(&ar->arLock, flags); ar->arConnected = true; @@ -6166,6 +6153,21 @@ ar6000_connect_to_ap(struct ar6_softc *ar) return A_ERROR; } +int +ar6000_disconnect(struct ar6_softc *ar) +{ + if ((ar->arConnected == true) || (ar->arConnectPending == true)) { + wmi_disconnect_cmd(ar->arWmi); + /* + * Disconnect cmd is issued, clear connectPending. + * arConnected will be cleard in disconnect_event notification. + */ + ar->arConnectPending = false; + } + + return 0; +} + int ar6000_ap_mode_get_wpa_ie(struct ar6_softc *ar, struct ieee80211req_wpaie *wpaie) { diff --git a/drivers/staging/ath6kl/os/linux/cfg80211.c b/drivers/staging/ath6kl/os/linux/cfg80211.c index bc5f6a7afc19..0f8f868c9a5a 100644 --- a/drivers/staging/ath6kl/os/linux/cfg80211.c +++ b/drivers/staging/ath6kl/os/linux/cfg80211.c @@ -318,7 +318,7 @@ ar6k_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return 0; } else if(ar->arSsidLen == sme->ssid_len && !A_MEMCMP(ar->arSsid, sme->ssid, ar->arSsidLen)) { - wmi_disconnect_cmd(ar->arWmi); + ar6000_disconnect(ar); } A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); @@ -604,7 +604,7 @@ ar6k_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, } reconnect_flag = 0; - wmi_disconnect_cmd(ar->arWmi); + ar6000_disconnect(ar); A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); ar->arSsidLen = 0; @@ -1341,6 +1341,7 @@ ar6k_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, ar->arSsidLen, ar->arSsid, ar->arReqBssid, ar->arChannelHint, ar->arConnectCtrlFlags); + ar->arConnectPending = true; return 0; } @@ -1362,7 +1363,7 @@ ar6k_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) return -EIO; } - wmi_disconnect_cmd(ar->arWmi); + ar6000_disconnect(ar); A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); ar->arSsidLen = 0; diff --git a/drivers/staging/ath6kl/os/linux/include/ar6xapi_linux.h b/drivers/staging/ath6kl/os/linux/include/ar6xapi_linux.h index a8d3f5498227..1acfb9cb7c73 100644 --- a/drivers/staging/ath6kl/os/linux/include/ar6xapi_linux.h +++ b/drivers/staging/ath6kl/os/linux/include/ar6xapi_linux.h @@ -171,6 +171,7 @@ void ap_wapi_rekey_event(struct ar6_softc *ar, u8 type, u8 *mac); #endif int ar6000_connect_to_ap(struct ar6_softc *ar); +int ar6000_disconnect(struct ar6_softc *ar); int ar6000_update_wlan_pwr_state(struct ar6_softc *ar, AR6000_WLAN_STATE state, bool suspending); int ar6000_set_wlan_state(struct ar6_softc *ar, AR6000_WLAN_STATE state); int ar6000_set_bt_hw_state(struct ar6_softc *ar, u32 state); diff --git a/drivers/staging/ath6kl/os/linux/wireless_ext.c b/drivers/staging/ath6kl/os/linux/wireless_ext.c index 1f858ca87a01..baa86633b2a0 100644 --- a/drivers/staging/ath6kl/os/linux/wireless_ext.c +++ b/drivers/staging/ath6kl/os/linux/wireless_ext.c @@ -575,9 +575,10 @@ ar6000_ioctl_siwessid(struct net_device *dev, /* Update the arNetworkType */ ar->arNetworkType = ar->arNextMode; - if ((prevMode != AP_NETWORK) && - ((ar->arSsidLen) || ((ar->arSsidLen == 0) && ar->arConnected) || (!data->flags))) + ((ar->arSsidLen) || + ((ar->arSsidLen == 0) && (ar->arConnected || ar->arConnectPending)) || + (!data->flags))) { if ((!data->flags) || (A_MEMCMP(ar->arSsid, ssid, ar->arSsidLen) != 0) || @@ -594,7 +595,7 @@ ar6000_ioctl_siwessid(struct net_device *dev, if (ar->arWmiReady == true) { reconnect_flag = 0; status = wmi_setPmkid_cmd(ar->arWmi, ar->arBssid, NULL, 0); - status = wmi_disconnect_cmd(ar->arWmi); + ar6000_disconnect(ar); A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); ar->arSsidLen = 0; if (ar->arSkipScan == false) { @@ -2414,7 +2415,7 @@ ar6000_ioctl_siwmlme(struct net_device *dev, ar6000_init_profile_info(ar); ar->arNetworkType = arNetworkType; reconnect_flag = 0; - wmi_disconnect_cmd(ar->arWmi); + ar6000_disconnect(ar); A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); ar->arSsidLen = 0; if (ar->arSkipScan == false) { @@ -2614,8 +2615,6 @@ ar6000_ioctl_siwcommit(struct net_device *dev, * update the host driver association state for the STA|IBSS mode. */ if (ar->arNetworkType != AP_NETWORK && ar->arNextMode == AP_NETWORK) { - ar->arConnectPending = false; - ar->arConnected = false; /* Stop getting pkts from upper stack */ netif_stop_queue(ar->arNetDev); A_MEMZERO(ar->arBssid, sizeof(ar->arBssid)); -- 2.34.1