diff --git a/core/hdd/inc/wlan_hdd_assoc.h b/core/hdd/inc/wlan_hdd_assoc.h index 21e57f68c384..8aec59e1f708 100644 --- a/core/hdd/inc/wlan_hdd_assoc.h +++ b/core/hdd/inc/wlan_hdd_assoc.h @@ -278,6 +278,16 @@ enum band_info hdd_conn_get_connected_band(struct hdd_station_ctx *sta_ctx); struct hdd_adapter *hdd_get_sta_connection_in_progress( struct hdd_context *hdd_ctx); +/** + * hdd_abort_ongoing_sta_connection() - Disconnect the sta for which the + * connection is in progress. + * + * @hdd_ctx: hdd context + * + * Return: none + */ +void hdd_abort_ongoing_sta_connection(struct hdd_context *hdd_ctx); + /** * hdd_sme_roam_callback() - hdd sme roam callback * @pContext: pointer to adapter context diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 963c04af1227..add3490681a3 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -381,7 +381,7 @@ struct hdd_adapter *hdd_get_sta_connection_in_progress( (QDF_P2P_DEVICE_MODE == adapter->device_mode)) { if (eConnectionState_Connecting == hdd_sta_ctx->conn_info.connState) { - hdd_debug("session_id %d: Connection is in progress", + hdd_debug("vdev_id %d: Connection is in progress", adapter->session_id); return adapter; } else if ((eConnectionState_Associated == @@ -389,7 +389,7 @@ struct hdd_adapter *hdd_get_sta_connection_in_progress( sme_is_sta_key_exchange_in_progress( hdd_ctx->mac_handle, adapter->session_id)) { - hdd_debug("session_id %d: Key exchange is in progress", + hdd_debug("vdev_id %d: Key exchange is in progress", adapter->session_id); return adapter; } @@ -398,6 +398,24 @@ struct hdd_adapter *hdd_get_sta_connection_in_progress( return NULL; } +void hdd_abort_ongoing_sta_connection(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *sta_adapter; + QDF_STATUS status; + + sta_adapter = hdd_get_sta_connection_in_progress(hdd_ctx); + if (sta_adapter) { + hdd_debug("Disconnecting STA on vdev: %d", + sta_adapter->session_id); + status = wlan_hdd_disconnect(sta_adapter, + eCSR_DISCONNECT_REASON_DEAUTH); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("wlan_hdd_disconnect failed, status: %d", + status); + } + } +} + /** * hdd_remove_beacon_filter() - remove beacon filter * @adapter: Pointer to the hdd adapter diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index bd24dcf05c7c..51aefb7d220d 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -4720,7 +4720,6 @@ int wlan_hdd_cfg80211_start_bss(struct hdd_adapter *adapter, bool MFPRequired = false; uint16_t prev_rsn_length = 0; enum dfs_mode mode; - struct hdd_adapter *sta_adapter; bool ignore_cac = 0; uint8_t is_overlap_enable = 0, scc_on_dfs_chan = 0; uint8_t beacon_fixed_len, indoor_chnl_marking = 0; @@ -4769,12 +4768,7 @@ int wlan_hdd_cfg80211_start_bss(struct hdd_adapter *adapter, * disconnect the STA interface first if connection or key exchange is * in progress and then start SAP interface. */ - sta_adapter = hdd_get_sta_connection_in_progress(hdd_ctx); - if (sta_adapter) { - hdd_debug("Disconnecting STA with session id: %d", - sta_adapter->session_id); - wlan_hdd_disconnect(sta_adapter, eCSR_DISCONNECT_REASON_DEAUTH); - } + hdd_abort_ongoing_sta_connection(hdd_ctx); /* * Reject start bss if reassoc in progress on any adapter. @@ -5520,7 +5514,6 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) { struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); - struct hdd_adapter *sta_adapter; struct hdd_context *hdd_ctx = wiphy_priv(wiphy); QDF_STATUS status = QDF_STATUS_E_FAILURE; QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; @@ -5571,12 +5564,7 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, * the STA and complete the SAP operation. STA will reconnect * after SAP stop is done. */ - sta_adapter = hdd_get_sta_connection_in_progress(hdd_ctx); - if (sta_adapter) { - hdd_debug("Disconnecting STA with session id: %d", - sta_adapter->session_id); - wlan_hdd_disconnect(sta_adapter, eCSR_DISCONNECT_REASON_DEAUTH); - } + hdd_abort_ongoing_sta_connection(hdd_ctx); if (adapter->device_mode == QDF_SAP_MODE) wlan_hdd_del_station(adapter); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index e5aeb0bda904..ac3f273f97e2 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -5453,10 +5453,22 @@ QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx, } } - if (wlan_hdd_try_disconnect(adapter)) { - hdd_err("Can't disconnect adapter"); - return QDF_STATUS_E_FAILURE; - } + /* + * During vdev destroy, if any STA is in connecting state the + * roam command will be in active queue and thus vdev destroy is + * queued in pending queue. In case STA tries to connect to + * multiple BSSID and fails to connect, due to auth/assoc + * timeouts it may take more than vdev destroy time to get + * completed. On vdev destroy timeout vdev is moved to logically + * deleted state. Once connection is completed, vdev destroy is + * activated and to release the self-peer ref count it try to + * get the ref of the vdev, which fails as vdev is logically + * deleted and this leads to peer ref leak. So before vdev + * destroy is queued abort any STA ongoing connection to avoid + * vdev destroy timeout. + */ + if (test_bit(SME_SESSION_OPENED, &adapter->event_flags)) + hdd_abort_ongoing_sta_connection(hdd_ctx); hdd_vdev_destroy(adapter); break; @@ -5495,6 +5507,23 @@ QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx, hdd_deregister_tx_flow_control(adapter); hdd_destroy_acs_timer(adapter); + /** + * During vdev destroy, If any STA is in connecting state the + * roam command will be in active queue and thus vdev destroy is + * queued in pending queue. In case STA is tries to connected to + * multiple BSSID and fails to connect, due to auth/assoc + * timeouts it may take more than vdev destroy time to get + * completes. If vdev destroy timeout vdev is moved to logically + * deleted state. Once connection is completed, vdev destroy is + * activated and to release the self-peer ref count it try to + * get the ref of the vdev, which fails as vdev is logically + * deleted and this leads to peer ref leak. So before vdev + * destroy is queued abort any STA ongoing connection to avoid + * vdev destroy timeout. + */ + if (test_bit(SME_SESSION_OPENED, &adapter->event_flags)) + hdd_abort_ongoing_sta_connection(hdd_ctx); + mutex_lock(&hdd_ctx->sap_lock); if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { status = wlansap_stop_bss(