diff --git a/core/hdd/inc/wlan_hdd_assoc.h b/core/hdd/inc/wlan_hdd_assoc.h index 0b9fae19f913..37f0e43f93aa 100644 --- a/core/hdd/inc/wlan_hdd_assoc.h +++ b/core/hdd/inc/wlan_hdd_assoc.h @@ -213,6 +213,7 @@ struct hdd_connection_info { /* Forward declarations */ struct hdd_adapter; struct hdd_station_ctx; +struct hdd_context; /** * hdd_is_connecting() - Function to check connection progress @@ -239,6 +240,16 @@ bool hdd_conn_is_connected(struct hdd_station_ctx *sta_ctx); */ enum band_info hdd_conn_get_connected_band(struct hdd_station_ctx *sta_ctx); +/** + * hdd_get_sta_connection_in_progress() - get STA for which connection + * is in progress + * @hdd_ctx: hdd context + * + * Return: hdd adpater for which connection is in progress + */ +struct hdd_adapter *hdd_get_sta_connection_in_progress( + 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 92b41e82fd87..95214eaadd33 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -304,6 +304,39 @@ hdd_conn_get_connected_cipher_algo(struct hdd_station_ctx *sta_ctx, return fConnected; } +struct hdd_adapter *hdd_get_sta_connection_in_progress( + struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter = NULL; + struct hdd_station_ctx *hdd_sta_ctx; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return NULL; + } + + hdd_for_each_adapter(hdd_ctx, adapter) { + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if ((QDF_STA_MODE == adapter->device_mode) || + (QDF_P2P_CLIENT_MODE == adapter->device_mode) || + (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", + adapter->session_id); + return adapter; + } else if ((eConnectionState_Associated == + hdd_sta_ctx->conn_info.connState) && + !hdd_sta_ctx->conn_info.uIsAuthenticated) { + hdd_debug("session_id %d: Key exchange is in progress", + adapter->session_id); + return adapter; + } + } + } + return NULL; +} + /** * hdd_remove_beacon_filter() - remove beacon filter * @adapter: Pointer to the hdd adapter diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 53df0973064b..b67de63f89f5 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -18284,16 +18284,7 @@ static int wlan_hdd_cfg80211_connect(struct wiphy *wiphy, return ret; } -/** - * wlan_hdd_disconnect() - hdd disconnect api - * @adapter: Pointer to adapter - * @reason: Disconnect reason code - * - * This function is used to issue a disconnect request to SME - * - * Return: 0 for success, non-zero for failure - */ -static int wlan_hdd_disconnect(struct hdd_adapter *adapter, u16 reason) +int wlan_hdd_disconnect(struct hdd_adapter *adapter, u16 reason) { int status, result = 0; unsigned long rc; diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index f125ed0cc061..90e0fb4cd8ae 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -509,6 +509,17 @@ uint8_t hdd_get_sap_operating_band(struct hdd_context *hdd_ctx); */ int wlan_hdd_try_disconnect(struct hdd_adapter *adapter); +/** + * wlan_hdd_disconnect() - hdd disconnect api + * @adapter: Pointer to adapter + * @reason: Disconnect reason code + * + * This function is used to issue a disconnect request to SME + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_disconnect(struct hdd_adapter *adapter, u16 reason); + /** * hdd_update_cca_info_cb() - stores congestion value in station context * @context : HDD context diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index 28d561c46afe..1f81971750b6 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -7650,6 +7650,7 @@ 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; ENTER(); @@ -7665,6 +7666,30 @@ int wlan_hdd_cfg80211_start_bss(struct hdd_adapter *adapter, } } + /* + * For STA+SAP concurrency support from GUI, first STA connection gets + * triggered and while it is in progress, SAP start also comes up. + * Once STA association is successful, STA connect event is sent to + * kernel which gets queued in kernel workqueue and supplicant won't + * process M1 received from AP and send M2 until this NL80211_CONNECT + * event is received. Workqueue is not scheduled as RTNL lock is already + * taken by hostapd thread which has issued start_bss command to driver. + * Driver cannot complete start_bss as the pending command at the head + * of the SME command pending list is hw_mode_update for STA session + * which cannot be processed as SME is in WAITforKey state for STA + * interface. The start_bss command for SAP interface is queued behind + * the hw_mode_update command and so it cannot be processed until + * hw_mode_update command is processed. This is causing a deadlock so + * 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); + } + sme_config = qdf_mem_malloc(sizeof(*sme_config)); if (!sme_config) { hdd_err("failed to allocate memory");