瀏覽代碼

qcacld-3.0: Handle disconnect requests during LFR3 roaming

Propagation from cld3.0-1.1 to cld3.0-2.0

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
Varun Reddy Yeturu 8 年之前
父節點
當前提交
a578414c8a

+ 7 - 2
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);

+ 21 - 1
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);
 
 /**

+ 13 - 4
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:

+ 97 - 9
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, <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) ||
@@ -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

+ 14 - 0
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

+ 11 - 5
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 */

+ 0 - 13
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;