From 533c9da880cb6472408b4f1c43cf9e32563dbdf0 Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Thu, 4 May 2017 10:23:34 +0530 Subject: [PATCH] qcacld-3.0: Wait for roam to get stopped during disconnect In case roaming was in progress when hdd_disconnect was called, avoid defer disconnect as that will call hdd api in mcthread which waits on event for about 5 seconds thus blocking everything. Also defer disconnect makes supplicant and driver state go out of sync. Rather wait in hdd for roaming to complete and then issue disconnect keeping state simple and clean Change-Id: I1b971226187892f32eb493047c13353bb0d1c867 CRs-Fixed: 2042394 --- core/hdd/inc/wlan_hdd_main.h | 25 ++---- core/hdd/src/wlan_hdd_assoc.c | 71 ++++++++--------- core/hdd/src/wlan_hdd_cfg80211.c | 126 +++++++++++-------------------- core/hdd/src/wlan_hdd_main.c | 1 + core/hdd/src/wlan_hdd_power.c | 1 + core/sme/inc/csr_neighbor_roam.h | 1 + core/sme/src/common/sme_api.c | 5 +- core/sme/src/csr/csr_api_roam.c | 2 +- core/wma/src/wma_scan_roam.c | 11 ++- 9 files changed, 102 insertions(+), 141 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index eb27884e3e9c..cc8e3bce1e8e 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -129,6 +129,7 @@ #else #define WLAN_WAIT_TIME_DISCONNECT 5000 #endif +#define WLAN_WAIT_TIME_STOP_ROAM 4000 #define WLAN_WAIT_TIME_STATS 800 #define WLAN_WAIT_TIME_POWER 800 #define WLAN_WAIT_TIME_COUNTRY 1000 @@ -973,6 +974,8 @@ struct hdd_adapter_s { /** completion variable for disconnect callback */ struct completion disconnect_comp_var; + struct completion roaming_comp_var; + /** Completion of change country code */ struct completion change_country_code; @@ -1139,18 +1142,11 @@ struct hdd_adapter_s { 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. + * Indicate if HO fails during disconnect so that + * disconnect is not initiated by HDD as its already + * initiated by CSR */ - uint8_t defer_disconnect; - /* - * cfg80211 issues a reason for disconnect. Store this reason if the - * disconnect is being deferred. - */ - uint8_t cfg80211_disconnect_reason; + bool roam_ho_fail; struct lfr_firmware_status lfr_fw_status; /* * Store the restrict_offchannel count @@ -1159,13 +1155,6 @@ struct hdd_adapter_s { u8 restrict_offchannel_cnt; }; -/* - * 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) diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 62cbcc708a81..b8d5814d9816 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -2034,11 +2034,6 @@ static void hdd_send_re_assoc_event(struct net_device *dev, qdf_mem_zero(&roam_profile, sizeof(roam_profile)); - if (pAdapter->defer_disconnect) { - hdd_debug("Do not send roam event as discon will be processed"); - goto done; - } - if (!rspRsnIe) { hdd_err("Unable to allocate RSN IE"); goto done; @@ -2758,31 +2753,30 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter, QDF_TRACE_LEVEL_DEBUG, pFTAssocReq, assocReqlen); - if (!pAdapter->defer_disconnect) { - roam_bss = hdd_cfg80211_get_bss( - pAdapter->wdev.wiphy, - chan, - pRoamInfo->bssid.bytes, - pRoamInfo->u. - pConnectedProfile->SSID.ssId, - pRoamInfo->u. - pConnectedProfile->SSID.length); - cfg80211_roamed_bss(dev, - roam_bss, - pFTAssocReq, - assocReqlen, - pFTAssocRsp, - assocRsplen, - GFP_KERNEL); - wlan_hdd_send_roam_auth_event( - pAdapter, - pRoamInfo->bssid.bytes, - pFTAssocReq, - assocReqlen, - pFTAssocRsp, - assocRsplen, - pRoamInfo); - } + roam_bss = + hdd_cfg80211_get_bss( + pAdapter->wdev.wiphy, + chan, + pRoamInfo->bssid.bytes, + pRoamInfo->u. + pConnectedProfile->SSID.ssId, + pRoamInfo->u. + pConnectedProfile->SSID.length); + cfg80211_roamed_bss(dev, + roam_bss, + pFTAssocReq, + assocReqlen, + pFTAssocRsp, + assocRsplen, + GFP_KERNEL); + wlan_hdd_send_roam_auth_event( + pAdapter, + pRoamInfo->bssid.bytes, + pFTAssocReq, + assocReqlen, + pFTAssocRsp, + assocRsplen, + pRoamInfo); } if (sme_get_ftptk_state (WLAN_HDD_GET_HAL_CTX(pAdapter), @@ -4923,8 +4917,11 @@ hdd_sme_roam_callback(void *pContext, tCsrRoamInfo *pRoamInfo, uint32_t roamId, hdd_debug("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); + if (roamResult == eCSR_ROAM_RESULT_FAILURE) + pAdapter->roam_ho_fail = true; + else + pAdapter->roam_ho_fail = false; + complete(&pAdapter->roaming_comp_var); break; case eCSR_ROAM_SHOULD_ROAM: /* notify apps that we can't pass traffic anymore */ @@ -4953,7 +4950,8 @@ hdd_sme_roam_callback(void *pContext, tCsrRoamInfo *pRoamInfo, uint32_t roamId, hdd_napi_serialize(0); hdd_set_connection_in_progress(false); hdd_set_roaming_in_progress(false); - pAdapter->defer_disconnect = 0; + pAdapter->roam_ho_fail = false; + complete(&pAdapter->roaming_comp_var); /* Call to clear any MC Addr List filter applied after * successful connection. @@ -5190,11 +5188,8 @@ hdd_sme_roam_callback(void *pContext, tCsrRoamInfo *pRoamInfo, uint32_t roamId, WLAN_CONTROL_PATH); hdd_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); + pAdapter->roam_ho_fail = false; + complete(&pAdapter->roaming_comp_var); break; default: diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 1dd0e6d3d182..64fe97116684 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -4597,19 +4597,6 @@ 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_debug("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 + @@ -14707,27 +14694,28 @@ int wlan_hdd_try_disconnect(hdd_adapter_t *pAdapter) hal = WLAN_HDD_GET_HAL_CTX(pAdapter); if (pAdapter->device_mode == QDF_STA_MODE) { hdd_debug("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. - */ + sme_stop_roaming(hal, pAdapter->sessionId, eCsrForcedDisassoc); - hdd_warn("Roaming in progress, deferred"); - pAdapter->defer_disconnect = DEFER_DISCONNECT_TRY_DISCONNECT; - pAdapter->cfg80211_disconnect_reason = - eCSR_DISCONNECT_REASON_UNSPECIFIED; - return 0; + /* + * If firmware has already started roaming process, driver + * needs to wait for processing of this disconnect request. + * + */ + INIT_COMPLETION(pAdapter->roaming_comp_var); + if (hdd_is_roaming_in_progress(pAdapter)) { + rc = wait_for_completion_timeout( + &pAdapter->roaming_comp_var, + msecs_to_jiffies(WLAN_WAIT_TIME_STOP_ROAM)); + if (!rc) { + hdd_err("roaming comp var timed out session Id: %d", + pAdapter->sessionId); + } + if (pAdapter->roam_ho_fail) { + INIT_COMPLETION(pAdapter->disconnect_comp_var); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_Disconnecting); + } + } } if ((QDF_IBSS_MODE == pAdapter->device_mode) || @@ -15047,25 +15035,32 @@ static int wlan_hdd_disconnect(hdd_adapter_t *pAdapter, u16 reason) if (pAdapter->device_mode == QDF_STA_MODE) { hdd_debug("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)) { + eCsrForcedDisassoc); /* - * 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. + * If firmware has already started roaming process, driver + * needs to wait for processing of this disconnect request. + * */ - hdd_warn("Roaming in progress, disconnect command deferred"); - pAdapter->defer_disconnect = - DEFER_DISCONNECT_CFG80211_DISCONNECT; - pAdapter->cfg80211_disconnect_reason = reason; - return 0; + INIT_COMPLETION(pAdapter->roaming_comp_var); + if (hdd_is_roaming_in_progress(pAdapter)) { + rc = wait_for_completion_timeout( + &pAdapter->roaming_comp_var, + msecs_to_jiffies(WLAN_WAIT_TIME_STOP_ROAM)); + if (!rc) { + hdd_err("roaming comp var timed out session Id: %d", + pAdapter->sessionId); + } + if (pAdapter->roam_ho_fail) { + INIT_COMPLETION(pAdapter->disconnect_comp_var); + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_Disconnecting); + goto wait_for_disconnect; + } + } } prev_conn_state = pHddStaCtx->conn_info.connState; @@ -15101,6 +15096,7 @@ static int wlan_hdd_disconnect(hdd_adapter_t *pAdapter, u16 reason) result = -EINVAL; goto disconnected; } +wait_for_disconnect: rc = wait_for_completion_timeout(&pAdapter->disconnect_comp_var, msecs_to_jiffies (WLAN_WAIT_TIME_DISCONNECT)); @@ -17472,36 +17468,6 @@ 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_debug("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_main.c b/core/hdd/src/wlan_hdd_main.c index bd23ecb21780..fa172ec39584 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -2843,6 +2843,7 @@ static hdd_adapter_t *hdd_alloc_station_adapter(hdd_context_t *hdd_ctx, init_completion(&adapter->session_open_comp_var); init_completion(&adapter->session_close_comp_var); init_completion(&adapter->disconnect_comp_var); + init_completion(&adapter->roaming_comp_var); init_completion(&adapter->linkup_event_var); init_completion(&adapter->cancel_rem_on_chan_var); init_completion(&adapter->rem_on_chan_ready_event); diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index cc27419d29d4..c2259d5b0685 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -1460,6 +1460,7 @@ QDF_STATUS hdd_wlan_re_init(void) pHddCtx->last_scan_reject_timestamp = 0; hdd_set_roaming_in_progress(false); + complete(&pAdapter->roaming_comp_var); pHddCtx->btCoexModeSet = false; /* Allow the phone to go to sleep */ diff --git a/core/sme/inc/csr_neighbor_roam.h b/core/sme/inc/csr_neighbor_roam.h index 74cbfc1e5107..cf9b2576c631 100644 --- a/core/sme/inc/csr_neighbor_roam.h +++ b/core/sme/inc/csr_neighbor_roam.h @@ -325,6 +325,7 @@ void csr_roam_reset_roam_params(tpAniSirGlobal mac_ptr); #define REASON_ROAM_SCAN_STA_ROAM_POLICY_CHANGED 35 #define REASON_ROAM_SYNCH_FAILED 36 #define REASON_ROAM_PSK_PMK_CHANGED 37 +#define REASON_ROAM_STOP_ALL 38 #define REASON_SUPPLICANT_DISABLED_ROAMING 39 #define REASON_CTX_INIT 40 diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 3139dfa10c56..e6fd4c643119 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -8039,7 +8039,10 @@ QDF_STATUS sme_stop_roaming(tHalHandle hHal, uint8_t sessionId, uint8_t reason) } req->Command = ROAM_SCAN_OFFLOAD_STOP; - req->reason = REASON_ROAM_SYNCH_FAILED; + if (reason == eCsrForcedDisassoc) + req->reason = REASON_ROAM_STOP_ALL; + else + req->reason = REASON_ROAM_SYNCH_FAILED; req->sessionId = sessionId; if (csr_neighbor_middle_of_roaming(mac_ctx, sessionId)) req->middle_of_roaming = 1; diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 95c9f5e0376f..4681e3158f11 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -19412,7 +19412,7 @@ void csr_process_ho_fail_ind(tpAniSirGlobal mac_ctx, void *pMsgBuf) csr_roam_roaming_offload_timer_action(mac_ctx, 0, sessionId, ROAMING_OFFLOAD_TIMER_STOP); csr_roam_call_callback(mac_ctx, sessionId, NULL, 0, - eCSR_ROAM_NAPI_OFF, eSIR_SME_SUCCESS); + eCSR_ROAM_NAPI_OFF, eCSR_ROAM_RESULT_FAILURE); csr_roam_synch_clean_up(mac_ctx, sessionId); csr_roaming_report_diag_event(mac_ctx, NULL, eCSR_REASON_ROAM_HO_FAIL); diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c index cf8f24a45d41..9016a23ee3d0 100644 --- a/core/wma/src/wma_scan_roam.c +++ b/core/wma/src/wma_scan_roam.c @@ -1850,13 +1850,18 @@ QDF_STATUS wma_process_roaming_config(tp_wma_handle wma_handle, case ROAM_SCAN_OFFLOAD_STOP: wma_handle->suitable_ap_hb_failure = false; if (wma_handle->roam_offload_enabled) { + uint32_t mode; wma_roam_scan_fill_scan_params(wma_handle, pMac, NULL, &scan_params); + + if (roam_req->reason == REASON_ROAM_STOP_ALL) + mode = WMI_ROAM_SCAN_MODE_NONE; + else + mode = WMI_ROAM_SCAN_MODE_NONE | + WMI_ROAM_SCAN_MODE_ROAMOFFLOAD; qdf_status = wma_roam_scan_offload_mode(wma_handle, - &scan_params, NULL, - WMI_ROAM_SCAN_MODE_NONE | - WMI_ROAM_SCAN_MODE_ROAMOFFLOAD, + &scan_params, NULL, mode, roam_req->sessionId); } /*