summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVarun Reddy Yeturu <varunreddy.yeturu@codeaurora.org>2016-12-06 19:38:09 -0800
committerqcabuildsw <qcabuildsw@localhost>2017-01-28 03:40:48 -0800
commit9b65457f66c1c0c6c63722f41ab886dedba9ebef (patch)
treec9d7e61ee36f9be308fab880606c04998a905e59
parent6881fd8e175fa52f084aaf2518caabb3b57f4cda (diff)
qcacld-3.0: Handle disconnect requests during LFR3 roaming
Upper layer can send cfg80211 disconnect command anytime in the life of a connection. It arrive when firmware roaming may have started, completed, failed, etc. Processing of roam events may collide with processing of disconnect command in the host driver. Defer the hdd disconnect command if roaming has started. Upon completing roaming send the deferred disconnect command to sme which will eventually complete the requested disconnect. If disconnect is deferred during roaming, then do not send the new roam event to supplicant since it is not expected and upon honoring the disconnect later, a disconnect event would be sent to supplicant. Remove the earlier workaround done to send a try again error message to upper layers upon receiving a disconnect request when roaming is in progress Firmware can now handle the ROAM_SCAN_OFFLOAD_STOP command even if it is in the middle of roaming operation. Hence remove this check in SME. Add LFR3 roaming state to the cds_is_connection_in_progress API since it currently captures only LFR2 roaming states. Change-Id: Id352d94b41f0766889ceebd0b57b2c566ce3ca42 CRs-Fixed: 1114853
-rw-r--r--core/cds/src/cds_concurrency.c9
-rw-r--r--core/hdd/inc/wlan_hdd_main.h23
-rw-r--r--core/hdd/src/wlan_hdd_assoc.c17
-rw-r--r--core/hdd/src/wlan_hdd_cfg80211.c108
-rw-r--r--core/hdd/src/wlan_hdd_cfg80211.h14
-rw-r--r--core/hdd/src/wlan_hdd_main.c15
-rw-r--r--core/sme/src/csr/csr_api_roam.c13
7 files changed, 166 insertions, 33 deletions
diff --git a/core/cds/src/cds_concurrency.c b/core/cds/src/cds_concurrency.c
index f8a7c017171d..cc0d6941bac7 100644
--- a/core/cds/src/cds_concurrency.c
+++ b/core/cds/src/cds_concurrency.c
@@ -2742,10 +2742,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 83840acac954..04b193aeebab 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -1160,8 +1160,29 @@ struct hdd_adapter_s {
/* rcpi information */
struct rcpi_info rcpi;
+ /*
+ * 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)
@@ -2073,7 +2094,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);
/**
* hdd_check_for_opened_interfaces()- Check for interface up
diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c
index 5e96aac9d535..66ef50acf29c 100644
--- a/core/hdd/src/wlan_hdd_assoc.c
+++ b/core/hdd/src/wlan_hdd_assoc.c
@@ -1989,9 +1989,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,
@@ -2538,7 +2539,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,
@@ -4651,6 +4653,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 */
@@ -4931,6 +4935,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 d2a7697578a9..fad7d67798f1 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -3884,6 +3884,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 +
@@ -12881,8 +12894,34 @@ static 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, <try disconnect> 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) ||
@@ -13133,6 +13172,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();
@@ -13140,18 +13180,43 @@ 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 */
hdd_notice("Disabling queues");
wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_TX_DISABLE_N_CARRIER,
- WLAN_CONTROL_PATH);
+ 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);
@@ -13303,11 +13368,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;
@@ -15590,6 +15650,38 @@ void wlan_hdd_clear_link_layer_stats(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)
+{
+ 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;
+ }
+
+}
+
+
+/**
* struct cfg80211_ops - cfg80211_ops
*
* @add_virtual_intf: Add virtual interface
diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h
index 49bc6b354259..a417778c61ed 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.h
+++ b/core/hdd/src/wlan_hdd_cfg80211.h
@@ -3507,4 +3507,18 @@ void hdd_lost_link_info_cb(void *context,
* Return : Corresponding band for SAP operating channel
*/
uint8_t hdd_get_sap_operating_band(hdd_context_t *hdd_ctx);
+
+/**
+ * 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 13c914bd2778..048b8a2867fa 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -10082,20 +10082,25 @@ 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 2e69c7b0f680..c4d5c762b868 100644
--- a/core/sme/src/csr/csr_api_roam.c
+++ b/core/sme/src/csr/csr_api_roam.c
@@ -17884,19 +17884,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;