Commit 83195cc8 authored by Vipin Mehta's avatar Vipin Mehta Committed by Greg Kroah-Hartman

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: default avatarVipin Mehta <vmehta@atheros.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 3f2fd78e
...@@ -1943,15 +1943,12 @@ ar6000_stop_endpoint(struct net_device *dev, bool keepprofile, bool getdbglogs) ...@@ -1943,15 +1943,12 @@ ar6000_stop_endpoint(struct net_device *dev, bool keepprofile, bool getdbglogs)
{ {
if (!bypasswmi) if (!bypasswmi)
{ {
if (ar->arConnected == true || ar->arConnectPending == true) bool disconnectIssued;
{
AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("%s(): Disconnect\n", __func__)); disconnectIssued = (ar->arConnected) || (ar->arConnectPending);
if (!keepprofile) { ar6000_disconnect(ar);
AR6000_SPIN_LOCK(&ar->arLock, 0); if (!keepprofile) {
ar6000_init_profile_info(ar); ar6000_init_profile_info(ar);
AR6000_SPIN_UNLOCK(&ar->arLock, 0);
}
wmi_disconnect_cmd(ar->arWmi);
} }
A_UNTIMEOUT(&ar->disconnect_timer); A_UNTIMEOUT(&ar->disconnect_timer);
...@@ -1973,14 +1970,12 @@ ar6000_stop_endpoint(struct net_device *dev, bool keepprofile, bool getdbglogs) ...@@ -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 * Sometimes disconnect_event will be received when the debug logs
* are collected. * are collected.
*/ */
if (ar->arConnected == true || ar->arConnectPending == true) { if (disconnectIssued) {
if(ar->arNetworkType & AP_NETWORK) { if(ar->arNetworkType & AP_NETWORK) {
ar6000_disconnect_event(ar, DISCONNECT_CMD, bcast_mac, 0, NULL, 0); ar6000_disconnect_event(ar, DISCONNECT_CMD, bcast_mac, 0, NULL, 0);
} else { } else {
ar6000_disconnect_event(ar, DISCONNECT_CMD, ar->arBssid, 0, NULL, 0); ar6000_disconnect_event(ar, DISCONNECT_CMD, ar->arBssid, 0, NULL, 0);
} }
ar->arConnected = false;
ar->arConnectPending = false;
} }
#ifdef USER_KEYS #ifdef USER_KEYS
ar->user_savedkeys_stat = USER_SAVEDKEYS_STAT_INIT; ar->user_savedkeys_stat = USER_SAVEDKEYS_STAT_INIT;
...@@ -2163,7 +2158,7 @@ static void disconnect_timer_handler(unsigned long ptr) ...@@ -2163,7 +2158,7 @@ static void disconnect_timer_handler(unsigned long ptr)
A_UNTIMEOUT(&ar->disconnect_timer); A_UNTIMEOUT(&ar->disconnect_timer);
ar6000_init_profile_info(ar); ar6000_init_profile_info(ar);
wmi_disconnect_cmd(ar->arWmi); ar6000_disconnect(ar);
} }
static void ar6000_detect_error(unsigned long ptr) static void ar6000_detect_error(unsigned long ptr)
...@@ -2235,7 +2230,6 @@ void ar6000_init_profile_info(AR_SOFTC_T *ar) ...@@ -2235,7 +2230,6 @@ void ar6000_init_profile_info(AR_SOFTC_T *ar)
A_MEMZERO(ar->arReqBssid, sizeof(ar->arReqBssid)); A_MEMZERO(ar->arReqBssid, sizeof(ar->arReqBssid));
A_MEMZERO(ar->arBssid, sizeof(ar->arBssid)); A_MEMZERO(ar->arBssid, sizeof(ar->arBssid));
ar->arBssChannel = 0; ar->arBssChannel = 0;
ar->arConnected = false;
} }
static void static void
...@@ -2322,13 +2316,7 @@ ar6000_close(struct net_device *dev) ...@@ -2322,13 +2316,7 @@ ar6000_close(struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
#ifdef ATH6K_CONFIG_CFG80211 #ifdef ATH6K_CONFIG_CFG80211
AR6000_SPIN_LOCK(&ar->arLock, 0); ar6000_disconnect(ar);
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);
}
if(ar->arWmiReady == true) { if(ar->arWmiReady == true) {
if (wmi_scanparams_cmd(ar->arWmi, 0xFFFF, 0, if (wmi_scanparams_cmd(ar->arWmi, 0xFFFF, 0,
...@@ -4608,6 +4596,8 @@ ar6000_disconnect_event(AR_SOFTC_T *ar, u8 reason, u8 *bssid, ...@@ -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); A_MEMCPY(wrqu.addr.sa_data, bssid, ATH_MAC_LEN);
wireless_send_event(ar->arNetDev, IWEVEXPIRED, &wrqu, NULL); wireless_send_event(ar->arNetDev, IWEVEXPIRED, &wrqu, NULL);
} }
ar->arConnected = false;
return; return;
} }
...@@ -4652,7 +4642,6 @@ ar6000_disconnect_event(AR_SOFTC_T *ar, u8 reason, u8 *bssid, ...@@ -4652,7 +4642,6 @@ ar6000_disconnect_event(AR_SOFTC_T *ar, u8 reason, u8 *bssid,
*/ */
if( reason == DISCONNECT_CMD) if( reason == DISCONNECT_CMD)
{ {
ar->arConnectPending = false;
if ((!ar->arUserBssFilter) && (ar->arWmiReady)) { if ((!ar->arUserBssFilter) && (ar->arWmiReady)) {
wmi_bssfilter_cmd(ar->arWmi, NONE_BSS_FILTER, 0); wmi_bssfilter_cmd(ar->arWmi, NONE_BSS_FILTER, 0);
} }
...@@ -6084,8 +6073,6 @@ ar6000_ap_mode_profile_commit(struct ar6_softc *ar) ...@@ -6084,8 +6073,6 @@ ar6000_ap_mode_profile_commit(struct ar6_softc *ar)
p.groupCryptoLen = ar->arGroupCryptoLen; p.groupCryptoLen = ar->arGroupCryptoLen;
p.ctrl_flags = ar->arConnectCtrlFlags; p.ctrl_flags = ar->arConnectCtrlFlags;
ar->arConnected = false;
wmi_ap_profile_commit(ar->arWmi, &p); wmi_ap_profile_commit(ar->arWmi, &p);
spin_lock_irqsave(&ar->arLock, flags); spin_lock_irqsave(&ar->arLock, flags);
ar->arConnected = true; ar->arConnected = true;
...@@ -6166,6 +6153,21 @@ ar6000_connect_to_ap(struct ar6_softc *ar) ...@@ -6166,6 +6153,21 @@ ar6000_connect_to_ap(struct ar6_softc *ar)
return A_ERROR; 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 int
ar6000_ap_mode_get_wpa_ie(struct ar6_softc *ar, struct ieee80211req_wpaie *wpaie) ar6000_ap_mode_get_wpa_ie(struct ar6_softc *ar, struct ieee80211req_wpaie *wpaie)
{ {
......
...@@ -318,7 +318,7 @@ ar6k_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ...@@ -318,7 +318,7 @@ ar6k_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
return 0; return 0;
} else if(ar->arSsidLen == sme->ssid_len && } else if(ar->arSsidLen == sme->ssid_len &&
!A_MEMCMP(ar->arSsid, sme->ssid, ar->arSsidLen)) { !A_MEMCMP(ar->arSsid, sme->ssid, ar->arSsidLen)) {
wmi_disconnect_cmd(ar->arWmi); ar6000_disconnect(ar);
} }
A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); A_MEMZERO(ar->arSsid, sizeof(ar->arSsid));
...@@ -604,7 +604,7 @@ ar6k_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, ...@@ -604,7 +604,7 @@ ar6k_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
} }
reconnect_flag = 0; reconnect_flag = 0;
wmi_disconnect_cmd(ar->arWmi); ar6000_disconnect(ar);
A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); A_MEMZERO(ar->arSsid, sizeof(ar->arSsid));
ar->arSsidLen = 0; ar->arSsidLen = 0;
...@@ -1341,6 +1341,7 @@ ar6k_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, ...@@ -1341,6 +1341,7 @@ ar6k_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
ar->arSsidLen, ar->arSsid, ar->arSsidLen, ar->arSsid,
ar->arReqBssid, ar->arChannelHint, ar->arReqBssid, ar->arChannelHint,
ar->arConnectCtrlFlags); ar->arConnectCtrlFlags);
ar->arConnectPending = true;
return 0; return 0;
} }
...@@ -1362,7 +1363,7 @@ ar6k_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) ...@@ -1362,7 +1363,7 @@ ar6k_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
return -EIO; return -EIO;
} }
wmi_disconnect_cmd(ar->arWmi); ar6000_disconnect(ar);
A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); A_MEMZERO(ar->arSsid, sizeof(ar->arSsid));
ar->arSsidLen = 0; ar->arSsidLen = 0;
......
...@@ -171,6 +171,7 @@ void ap_wapi_rekey_event(struct ar6_softc *ar, u8 type, u8 *mac); ...@@ -171,6 +171,7 @@ void ap_wapi_rekey_event(struct ar6_softc *ar, u8 type, u8 *mac);
#endif #endif
int ar6000_connect_to_ap(struct ar6_softc *ar); 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_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_wlan_state(struct ar6_softc *ar, AR6000_WLAN_STATE state);
int ar6000_set_bt_hw_state(struct ar6_softc *ar, u32 state); int ar6000_set_bt_hw_state(struct ar6_softc *ar, u32 state);
......
...@@ -575,9 +575,10 @@ ar6000_ioctl_siwessid(struct net_device *dev, ...@@ -575,9 +575,10 @@ ar6000_ioctl_siwessid(struct net_device *dev,
/* Update the arNetworkType */ /* Update the arNetworkType */
ar->arNetworkType = ar->arNextMode; ar->arNetworkType = ar->arNextMode;
if ((prevMode != AP_NETWORK) && 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) || if ((!data->flags) ||
(A_MEMCMP(ar->arSsid, ssid, ar->arSsidLen) != 0) || (A_MEMCMP(ar->arSsid, ssid, ar->arSsidLen) != 0) ||
...@@ -594,7 +595,7 @@ ar6000_ioctl_siwessid(struct net_device *dev, ...@@ -594,7 +595,7 @@ ar6000_ioctl_siwessid(struct net_device *dev,
if (ar->arWmiReady == true) { if (ar->arWmiReady == true) {
reconnect_flag = 0; reconnect_flag = 0;
status = wmi_setPmkid_cmd(ar->arWmi, ar->arBssid, NULL, 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)); A_MEMZERO(ar->arSsid, sizeof(ar->arSsid));
ar->arSsidLen = 0; ar->arSsidLen = 0;
if (ar->arSkipScan == false) { if (ar->arSkipScan == false) {
...@@ -2414,7 +2415,7 @@ ar6000_ioctl_siwmlme(struct net_device *dev, ...@@ -2414,7 +2415,7 @@ ar6000_ioctl_siwmlme(struct net_device *dev,
ar6000_init_profile_info(ar); ar6000_init_profile_info(ar);
ar->arNetworkType = arNetworkType; ar->arNetworkType = arNetworkType;
reconnect_flag = 0; reconnect_flag = 0;
wmi_disconnect_cmd(ar->arWmi); ar6000_disconnect(ar);
A_MEMZERO(ar->arSsid, sizeof(ar->arSsid)); A_MEMZERO(ar->arSsid, sizeof(ar->arSsid));
ar->arSsidLen = 0; ar->arSsidLen = 0;
if (ar->arSkipScan == false) { if (ar->arSkipScan == false) {
...@@ -2614,8 +2615,6 @@ ar6000_ioctl_siwcommit(struct net_device *dev, ...@@ -2614,8 +2615,6 @@ ar6000_ioctl_siwcommit(struct net_device *dev,
* update the host driver association state for the STA|IBSS mode. * update the host driver association state for the STA|IBSS mode.
*/ */
if (ar->arNetworkType != AP_NETWORK && ar->arNextMode == AP_NETWORK) { if (ar->arNetworkType != AP_NETWORK && ar->arNextMode == AP_NETWORK) {
ar->arConnectPending = false;
ar->arConnected = false;
/* Stop getting pkts from upper stack */ /* Stop getting pkts from upper stack */
netif_stop_queue(ar->arNetDev); netif_stop_queue(ar->arNetDev);
A_MEMZERO(ar->arBssid, sizeof(ar->arBssid)); A_MEMZERO(ar->arBssid, sizeof(ar->arBssid));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment