diff --git a/core/cds/src/cds_concurrency.c b/core/cds/src/cds_concurrency.c index c7e759134386..e9a130221ed1 100644 --- a/core/cds/src/cds_concurrency.c +++ b/core/cds/src/cds_concurrency.c @@ -899,10 +899,15 @@ bool cds_is_connection_in_progress(uint8_t *session_id, } return true; } - if ((QDF_STA_MODE == adapter->device_mode) && + /* + * sme_neighbor_middle_of_roaming is for LFR2 + * hdd_is_roaming_in_progress is for LFR3 + */ + if (((QDF_STA_MODE == adapter->device_mode) && sme_neighbor_middle_of_roaming( WLAN_HDD_GET_HAL_CTX(adapter), - adapter->sessionId)) { + adapter->sessionId)) || + hdd_is_roaming_in_progress(adapter)) { cds_err("%p(%d) Reassociation in progress", WLAN_HDD_GET_STATION_CTX_PTR(adapter), adapter->sessionId); diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 666880ff4bec..41ad81e49114 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1144,8 +1144,28 @@ struct hdd_adapter_s { struct hdd_connect_pm_context connect_rpm_ctx; bool fast_roaming_allowed; + /* + * defer disconnect is used as a flag by roaming to check + * if any disconnect has been deferred because of roaming + * and handle it. It stores the source of the disconnect. + * Based on the source, it will appropriately handle the + * disconnect. + */ + uint8_t defer_disconnect; + /* + * cfg80211 issues a reason for disconnect. Store this reason if the + * disconnect is being deferred. + */ + uint8_t cfg80211_disconnect_reason; }; +/* + * Below two definitions are useful to distinguish the + * source of the disconnect when a disconnect is deferred + */ +#define DEFER_DISCONNECT_TRY_DISCONNECT 1 +#define DEFER_DISCONNECT_CFG80211_DISCONNECT 2 + #define WLAN_HDD_GET_STATION_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.station) #define WLAN_HDD_GET_AP_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.ap) #define WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter) (&(pAdapter)->sessionCtx.station.WextState) @@ -2163,7 +2183,7 @@ static inline int wlan_hdd_validate_session_id(u8 session_id) return -EINVAL; } -bool hdd_is_roaming_in_progress(void); +bool hdd_is_roaming_in_progress(hdd_adapter_t *adapter); void hdd_set_roaming_in_progress(bool value); /** diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 088353e88f16..e0382defc474 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -2040,9 +2040,10 @@ static void hdd_send_re_assoc_event(struct net_device *dev, hdd_notice("Req RSN IE:"); QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, final_req_ie, (ssid_ie_len + reqRsnLength)); - cfg80211_roamed_bss(dev, bss, - final_req_ie, (ssid_ie_len + reqRsnLength), - rspRsnIe, rspRsnLength, GFP_KERNEL); + if (!pAdapter->defer_disconnect) + cfg80211_roamed_bss(dev, bss, + final_req_ie, (ssid_ie_len + reqRsnLength), + rspRsnIe, rspRsnLength, GFP_KERNEL); qdf_mem_copy(assoc_req_ies, (u8 *)pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength, @@ -2637,7 +2638,8 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter, pConnectedProfile->SSID.ssId, pRoamInfo->u. pConnectedProfile->SSID.length); - cfg80211_roamed_bss(dev, + if (!pAdapter->defer_disconnect) + cfg80211_roamed_bss(dev, roam_bss, pFTAssocReq, assocReqlen, @@ -4786,6 +4788,8 @@ hdd_sme_roam_callback(void *pContext, tCsrRoamInfo *pRoamInfo, uint32_t roamId, hdd_info("After Roam Synch Comp: NAPI Serialize OFF"); hdd_napi_serialize(0); hdd_set_roaming_in_progress(false); + if (pAdapter->defer_disconnect) + hdd_process_defer_disconnect(pAdapter); break; case eCSR_ROAM_SHOULD_ROAM: /* notify apps that we can't pass traffic anymore */ @@ -5046,6 +5050,11 @@ hdd_sme_roam_callback(void *pContext, tCsrRoamInfo *pRoamInfo, uint32_t roamId, WLAN_CONTROL_PATH); cds_set_connection_in_progress(false); hdd_set_roaming_in_progress(false); + /* + * If disconnect operation is in deferred state, do it now. + */ + if (pAdapter->defer_disconnect) + hdd_process_defer_disconnect(pAdapter); break; default: diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index e1d9c446fb7e..d1afb355d7fc 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -4335,6 +4335,19 @@ int wlan_hdd_send_roam_auth_event(hdd_adapter_t *adapter, uint8_t *bssid, !roam_info_ptr->roamSynchInProgress) return 0; + /* + * The user space has issued a disconnect when roaming is in + * progress. The disconnect should be honored gracefully. + * If the roaming is complete and the roam event is sent + * back to the user space, it will get confused as it is + * expecting a disconnect event. So, do not send the event + * and handle the disconnect later. + */ + if (adapter->defer_disconnect) { + hdd_notice("LFR3:Do not send roam auth event"); + return 0; + } + skb = cfg80211_vendor_event_alloc(hdd_ctx_ptr->wiphy, &(adapter->wdev), ETH_ALEN + req_rsn_len + rsp_rsn_len + @@ -13904,8 +13917,34 @@ int wlan_hdd_try_disconnect(hdd_adapter_t *pAdapter) unsigned long rc; hdd_station_ctx_t *pHddStaCtx; int status, result = 0; + tHalHandle hal; pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hal = WLAN_HDD_GET_HAL_CTX(pAdapter); + if (pAdapter->device_mode == QDF_STA_MODE) { + hdd_notice("Stop firmware roaming"); + sme_stop_roaming(hal, pAdapter->sessionId, eCsrHddIssued); + } + /* + * If firmware has already started roaming process, driver + * needs to defer the processing of this disconnect request. + * + */ + if (hdd_is_roaming_in_progress(pAdapter)) { + /* + * Defer the disconnect action until firmware roaming + * result is received. If STA is in connected state after + * that, send the disconnect command to CSR, otherwise + * CSR would have already sent disconnect event to upper + * layer. + */ + + hdd_err("Roaming in progress, deferred."); + pAdapter->defer_disconnect = DEFER_DISCONNECT_TRY_DISCONNECT; + pAdapter->cfg80211_disconnect_reason = + eCSR_DISCONNECT_REASON_UNSPECIFIED; + return 0; + } if ((QDF_IBSS_MODE == pAdapter->device_mode) || (eConnectionState_Associated == pHddStaCtx->conn_info.connState) || @@ -14156,6 +14195,7 @@ static int wlan_hdd_disconnect(hdd_adapter_t *pAdapter, u16 reason) hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); eConnectionState prev_conn_state; + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(pAdapter); ENTER(); @@ -14163,18 +14203,41 @@ static int wlan_hdd_disconnect(hdd_adapter_t *pAdapter, u16 reason) if (0 != status) return status; + if (pAdapter->device_mode == QDF_STA_MODE) { + hdd_notice("Stop firmware roaming"); + status = sme_stop_roaming(hal, pAdapter->sessionId, + eCsrHddIssued); + } + /* + * If firmware has already started roaming process, driver + * needs to defer the processing of this disconnect request. + */ + if (hdd_is_roaming_in_progress(pAdapter)) { + /* + * Defer the disconnect action until firmware roaming + * result is received. If STA is in connected state after + * that, send the disconnect command to CSR, otherwise + * CSR would have already sent disconnect event to upper + * layer. + */ + hdd_err("Roaming in progress, disconnect command deferred."); + pAdapter->defer_disconnect = + DEFER_DISCONNECT_CFG80211_DISCONNECT; + pAdapter->cfg80211_disconnect_reason = reason; + return 0; + } prev_conn_state = pHddStaCtx->conn_info.connState; - /*stop tx queues */ + /* stop tx queues */ hdd_notice("Disabling queues"); - wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_TX_DISABLE_N_CARRIER, - WLAN_CONTROL_PATH); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_NETIF_TX_DISABLE_N_CARRIER, WLAN_CONTROL_PATH); hdd_notice("Set HDD connState to eConnectionState_Disconnecting"); pHddStaCtx->conn_info.connState = eConnectionState_Disconnecting; INIT_COMPLETION(pAdapter->disconnect_comp_var); - /*issue disconnect */ + /* issue disconnect */ status = sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, reason); @@ -14326,11 +14389,6 @@ static int __wlan_hdd_cfg80211_disconnect(struct wiphy *wiphy, status = wlan_hdd_validate_context(pHddCtx); - if (hdd_is_roaming_in_progress()) { - hdd_err("Roaming In Progress. Ignore!!!"); - return -EAGAIN; - } - if (0 != status) return status; @@ -16564,6 +16622,36 @@ void wlan_hdd_clear_link_layer_stats(hdd_adapter_t *adapter) return; } +/** + * hdd_process_defer_disconnect() - Handle the deferred disconnect + * @adapter: HDD Adapter + * + * If roaming is in progress and there is a request to + * disconnect the session, then it is deferred. Once + * roaming is complete/aborted, then this routine is + * used to resume the disconnect that was deferred + * + * Return: None + */ +void hdd_process_defer_disconnect(hdd_adapter_t *adapter) +{ + switch (adapter->defer_disconnect) { + case DEFER_DISCONNECT_CFG80211_DISCONNECT: + adapter->defer_disconnect = 0; + wlan_hdd_disconnect(adapter, + adapter->cfg80211_disconnect_reason); + break; + case DEFER_DISCONNECT_TRY_DISCONNECT: + wlan_hdd_try_disconnect(adapter); + adapter->defer_disconnect = 0; + break; + default: + hdd_info("Invalid source to defer:%d. Hence not handling it", + adapter->defer_disconnect); + break; + } +} + #define CNT_DIFF(cur, prev) \ ((cur >= prev) ? (cur - prev) : (cur + (MAX_COUNT - (prev) + 1))) #define MAX_COUNT 0xffffffff diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index ae20a13094d8..71d447d360c5 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -404,4 +404,18 @@ uint8_t hdd_get_sap_operating_band(hdd_context_t *hdd_ctx); * Return: 0 for success, non-zero for failure */ int wlan_hdd_try_disconnect(hdd_adapter_t *adapter); + +/** + * hdd_process_defer_disconnect() - Handle the deferred disconnect + * @adapter: HDD Adapter + * + * If roaming is in progress and there is a request to + * disconnect the session, then it is deferred. Once + * roaming is complete/aborted, then this routine is + * used to resume the disconnect that was deferred + * + * Return: None + */ +void hdd_process_defer_disconnect(hdd_adapter_t *adapter); + #endif diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index dab1caeb7d08..dbe598bcb04b 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -10709,20 +10709,26 @@ void hdd_set_roaming_in_progress(bool value) /** * hdd_is_roaming_in_progress() - check if roaming is in progress - * @hdd_ctx - HDD context + * @adapter - HDD adapter * - * Return: true if roaming is in progress else false + * Return: true if roaming is in progress for STA type, else false */ -bool hdd_is_roaming_in_progress(void) +bool hdd_is_roaming_in_progress(hdd_adapter_t *adapter) { hdd_context_t *hdd_ctx; + bool ret_status = false; hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); if (!hdd_ctx) { hdd_err("HDD context is NULL"); - return false; + return ret_status; } - return hdd_ctx->roaming_in_progress; + hdd_info("dev mode = %d, roaming_in_progress = %d", + adapter->device_mode, hdd_ctx->roaming_in_progress); + ret_status = ((adapter->device_mode == QDF_STA_MODE) && + hdd_ctx->roaming_in_progress); + + return ret_status; } /* Register the module init/exit functions */ diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 11f3d695c551..78acae99fed5 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -17745,19 +17745,6 @@ csr_roam_offload_scan(tpAniSirGlobal mac_ctx, uint8_t session_id, FL("Supplicant disabled driver roaming")); return QDF_STATUS_E_FAILURE; } -#ifdef WLAN_FEATURE_ROAM_OFFLOAD - if (session->roam_synch_in_progress - && (ROAM_SCAN_OFFLOAD_STOP == command)) { - /* - * When roam synch is in progress for propagation, there is no - * need to send down the STOP command since the firmware is not - * expecting any WMI commands when the roam synch is in progress - */ - b_roam_scan_offload_started = false; - sms_log(mac_ctx, LOG1, FL("Roam sync in progress")); - return QDF_STATUS_SUCCESS; - } -#endif if (0 == csr_roam_is_roam_offload_scan_enabled(mac_ctx)) { sms_log(mac_ctx, LOGE, "isRoamOffloadScanEnabled not set"); return QDF_STATUS_E_FAILURE;