Bläddra i källkod

qcacmn: Support roam start and roam abort request in CM

Add support for roam start and roam abort request
in connection manager.

CRs-Fixed: 2882233
Change-Id: I5780e7f22363ee6014d39b0df9cb068b4afdd71c
Amruta Kulkarni 4 år sedan
förälder
incheckning
64b096fde9

+ 29 - 0
os_if/linux/mlme/inc/osif_cm_util.h

@@ -217,6 +217,20 @@ typedef QDF_STATUS
 				       enum netif_action_type action,
 				       enum netif_reason_type reason);
 
+/**
+ * typedef os_if_cm_napi_serialize_ctrl_cb: Callback to update
+ * NAPI serialization
+ * @action: bool action to take on napi serialization
+ *
+ * This callback indicates legacy modules to take the actions
+ * related to napi serialization
+ *
+ * Context: Any context.
+ * Return: QDF_STATUS
+ */
+typedef QDF_STATUS
+	(*os_if_cm_napi_serialize_ctrl_cb)(bool action);
+
 /**
  * osif_cm_unlink_bss() - function to unlink bss from kernel and scan database
  * on connect timeouts reasons
@@ -251,6 +265,8 @@ void osif_cm_unlink_bss(struct wlan_objmgr_vdev *vdev,
  * legacy modules
  * @osif_cm_netif_queue_ctrl_cb: callback to legacy module to take
  * actions on netif queue
+ * @os_if_cm_napi_serialize_ctrl_cb: callback to legacy module to take
+ * actions on napi serialization
  * @save_gtk_cb : callback to legacy module to save gtk
  * @set_hlp_data_cb: callback to legacy module to save hlp data
  */
@@ -259,6 +275,7 @@ struct osif_cm_ops {
 	osif_cm_disconnect_comp_cb disconnect_complete_cb;
 #ifdef CONN_MGR_ADV_FEATURE
 	osif_cm_netif_queue_ctrl_cb netif_queue_control_cb;
+	os_if_cm_napi_serialize_ctrl_cb napi_serialize_control_cb;
 #endif
 #ifdef WLAN_FEATURE_FILS_SK
 	osif_cm_save_gtk_cb save_gtk_cb;
@@ -314,6 +331,18 @@ QDF_STATUS osif_cm_disconnect_comp_ind(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS osif_cm_netif_queue_ind(struct wlan_objmgr_vdev *vdev,
 				   enum netif_action_type action,
 				   enum netif_reason_type reason);
+
+/**
+ * osif_cm_napi_serialize() - Function to indicate napi serialize
+ * action to legacy module
+ * @action: Action to take on napi serialization
+ *
+ * This function indicates to take the actions related to napi activities
+ *
+ * Context: Any context.
+ * Return: QDF_STATUS
+ */
+QDF_STATUS osif_cm_napi_serialize(bool action);
 #endif
 
 #ifdef WLAN_FEATURE_FILS_SK

+ 55 - 1
os_if/linux/mlme/src/osif_cm_util.c

@@ -296,6 +296,7 @@ osif_cm_disable_netif_queue(struct wlan_objmgr_vdev *vdev)
 	return QDF_STATUS_SUCCESS;
 }
 #endif
+
 /**
  * osif_cm_disconnect_start_cb() - Disconnect start callback
  * @vdev: vdev pointer
@@ -312,12 +313,53 @@ osif_cm_disconnect_start_cb(struct wlan_objmgr_vdev *vdev)
 	return osif_cm_disable_netif_queue(vdev);
 }
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * osif_cm_roam_start_cb() - Roam start callback
+ * @vdev: vdev pointer
+ *
+ * This callback indicates os_if that roaming has started
+ * so that os_if can stop all the activity on this connection
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+osif_cm_roam_start_cb(struct wlan_objmgr_vdev *vdev)
+{
+	return osif_cm_netif_queue_ind(vdev,
+				       WLAN_STOP_ALL_NETIF_QUEUE,
+				       WLAN_CONTROL_PATH);
+}
+
+/**
+ * osif_cm_roam_abort_cb() - Roam abort callback
+ * @vdev: vdev pointer
+ *
+ * This callback indicates os_if that roaming has been aborted
+ * so that os_if can stop all the activity on this connection
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+osif_cm_roam_abort_cb(struct wlan_objmgr_vdev *vdev)
+{
+	osif_cm_napi_serialize(false);
+	return osif_cm_netif_queue_ind(vdev,
+				       WLAN_WAKE_ALL_NETIF_QUEUE,
+				       WLAN_CONTROL_PATH);
+}
+#endif
+
 static struct mlme_cm_ops cm_ops = {
 	.mlme_cm_connect_complete_cb = osif_cm_connect_complete_cb,
 	.mlme_cm_failed_candidate_cb = osif_cm_failed_candidate_cb,
 	.mlme_cm_update_id_and_src_cb = osif_cm_update_id_and_src_cb,
 	.mlme_cm_disconnect_complete_cb = osif_cm_disconnect_complete_cb,
 	.mlme_cm_disconnect_start_cb = osif_cm_disconnect_start_cb,
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+	.mlme_cm_roam_start_cb = osif_cm_roam_start_cb,
+	.mlme_cm_roam_abort_cb = osif_cm_roam_abort_cb,
+#endif
 };
 
 /**
@@ -417,8 +459,20 @@ QDF_STATUS osif_cm_netif_queue_ind(struct wlan_objmgr_vdev *vdev,
 
 	return ret;
 }
-#endif
 
+QDF_STATUS osif_cm_napi_serialize(bool action)
+{
+	os_if_cm_napi_serialize_ctrl_cb cb = NULL;
+	QDF_STATUS ret = QDF_STATUS_SUCCESS;
+
+	if (osif_cm_legacy_ops)
+		cb = osif_cm_legacy_ops->napi_serialize_control_cb;
+	if (cb)
+		ret = cb(action);
+
+	return ret;
+}
+#endif
 #ifdef WLAN_FEATURE_FILS_SK
 QDF_STATUS osif_cm_save_gtk(struct wlan_objmgr_vdev *vdev,
 			    struct wlan_cm_connect_resp *rsp)

+ 6 - 0
umac/mlme/connection_mgr/core/src/wlan_cm_connect.c

@@ -20,6 +20,7 @@
 
 #include "wlan_cm_main_api.h"
 #include "wlan_scan_api.h"
+#include "wlan_cm_roam.h"
 #include "wlan_cm_sm.h"
 #ifdef WLAN_POLICY_MGR_ENABLE
 #include "wlan_policy_mgr_api.h"
@@ -994,6 +995,11 @@ cm_handle_connect_req_in_non_init_state(struct cnx_mgr *cm_ctx,
 {
 	switch (cm_state_substate) {
 	case WLAN_CM_S_ROAMING:
+		/* for FW roam/LFR3 remove the req from the list */
+		if (cm_roam_offload_enabled(wlan_vdev_get_psoc(cm_ctx->vdev)))
+			cm_flush_pending_request(cm_ctx, ROAM_REQ_PREFIX,
+						 false);
+		/* fallthrough */
 	case WLAN_CM_S_CONNECTED:
 	case WLAN_CM_SS_JOIN_ACTIVE:
 		/*

+ 7 - 1
umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.c

@@ -19,6 +19,7 @@
  */
 #include "wlan_cm_main_api.h"
 #include "wlan_cm_sm.h"
+#include "wlan_cm_roam.h"
 #include <wlan_serialization_api.h>
 #include "wlan_utility.h"
 #include "wlan_scan_api.h"
@@ -527,8 +528,13 @@ cm_handle_discon_req_in_non_connected_state(struct cnx_mgr *cm_ctx,
 			cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX,
 						 true);
 		break;
-	case WLAN_CM_SS_JOIN_ACTIVE:
 	case WLAN_CM_S_ROAMING:
+		/* for FW roam/LFR3 remove the req from the list */
+		if (cm_roam_offload_enabled(wlan_vdev_get_psoc(cm_ctx->vdev)))
+			cm_flush_pending_request(cm_ctx, ROAM_REQ_PREFIX,
+						 false);
+		/* fallthrough */
+	case WLAN_CM_SS_JOIN_ACTIVE:
 		/*
 		 * In join active/roaming state, there would be no pending
 		 * command, so no action required. so for new disconnect

+ 50 - 1
umac/mlme/connection_mgr/core/src/wlan_cm_roam.h

@@ -23,6 +23,8 @@
 #ifndef __WLAN_CM_ROAM_H__
 #define __WLAN_CM_ROAM_H__
 
+#include "wlan_cm_main.h"
+
 #ifdef WLAN_FEATURE_HOST_ROAM
 /**
  * cm_roam_bss_peer_create_rsp() - handle bss peer create response for roam
@@ -83,7 +85,6 @@ QDF_STATUS cm_reassoc_complete(struct cnx_mgr *cm_ctx,
  */
 bool cm_get_active_reassoc_req(struct wlan_objmgr_vdev *vdev,
 			       struct wlan_cm_vdev_reassoc_req *req);
-
 /**
  * cm_host_roam_start_req() - Start host roam request
  * @cm_ctx: Connection manager context
@@ -237,6 +238,16 @@ cm_fill_bss_info_in_roam_rsp_by_cm_id(struct cnx_mgr *cm_ctx,
 				      struct wlan_cm_connect_resp *resp);
 
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * cm_fw_roam_start() - Handle roam start event
+ * @cm_ctx: connection mgr context
+ *
+ * This function handles the roam start event received from FW.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS cm_fw_roam_start(struct cnx_mgr *cm_ctx);
+
 /**
  * cm_send_roam_invoke_req() - Send Roam invoke req to FW
  * @cm_ctx: connection manager context
@@ -246,6 +257,7 @@ cm_fill_bss_info_in_roam_rsp_by_cm_id(struct cnx_mgr *cm_ctx,
  */
 QDF_STATUS
 cm_send_roam_invoke_req(struct cnx_mgr *cm_ctx, struct cm_req *req);
+
 /**
  * cm_roam_offload_enabled() - check if roam offload(LFR3) is enabled
  * @psoc: psoc pointer to get the INI
@@ -254,6 +266,43 @@ cm_send_roam_invoke_req(struct cnx_mgr *cm_ctx, struct cm_req *req);
  */
 bool cm_roam_offload_enabled(struct wlan_objmgr_psoc *psoc);
 
+/**
+ * cm_get_first_roam_command() - Get first roam request from list
+ * @vdev: vdev pointer
+ *
+ * Context: Can be called from any context and to be used only after posting a
+ * msg to SM (ie holding the SM lock) to avoid use after free. also returned req
+ * should only be used till SM lock is hold.
+ *
+ * Return: cm roam req from the req list
+ */
+struct cm_roam_req *cm_get_first_roam_command(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * cm_prepare_roam_cmd() - Prepare roam req
+ * @cm_ctx: connection mgr context
+ * @cm_req: connection mgr req
+ * @source: connection mgr req source
+ *
+ * This function prepares roam request when roam start ind is received
+ * when CM SM is in connected state.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS cm_prepare_roam_cmd(struct cnx_mgr *cm_ctx,
+			       struct cm_req **roam_req,
+			       enum wlan_cm_source source);
+/**
+ * cm_add_fw_roam_cmd_to_list_n_ser() - Add roam req to list and serialize req
+ * @cm_ctx: connection mgr context
+ * @cm_req: connection mgr req
+ *
+ * This function adds roam request to list and the serialization queue.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS cm_add_fw_roam_cmd_to_list_n_ser(struct cnx_mgr *cm_ctx,
+					    struct cm_req *cm_req);
 #else
 static inline bool cm_roam_offload_enabled(struct wlan_objmgr_psoc *psoc)
 {

+ 59 - 13
umac/mlme/connection_mgr/core/src/wlan_cm_roam_sm.c

@@ -35,6 +35,58 @@ void cm_state_roaming_exit(void *ctx)
 {
 }
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+static
+bool cm_handle_fw_roaming_event(struct cnx_mgr *cm_ctx, uint16_t event,
+				uint16_t data_len, void *data)
+{
+	bool event_handled = true;
+	QDF_STATUS status;
+
+	switch (event) {
+	case WLAN_CM_SM_EV_ROAM_INVOKE:
+		status = cm_add_fw_roam_cmd_to_list_n_ser(cm_ctx, data);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			event_handled = false;
+			break;
+		}
+		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_ROAM_STARTED);
+		cm_sm_deliver_event_sync(cm_ctx,
+					 WLAN_CM_SM_EV_ROAM_INVOKE,
+					 data_len, data);
+		break;
+	case WLAN_CM_SM_EV_ROAM_START:
+		status = cm_add_fw_roam_cmd_to_list_n_ser(cm_ctx, data);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			event_handled = false;
+			break;
+		}
+		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_ROAM_STARTED);
+		cm_sm_deliver_event_sync(cm_ctx,
+					 WLAN_CM_SM_EV_ROAM_START,
+					 0, NULL);
+		break;
+	case WLAN_CM_SM_EV_ROAM_ABORT:
+		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
+		cm_sm_deliver_event_sync(cm_ctx, event,
+					 data_len, data);
+		break;
+	default:
+		event_handled = false;
+		break;
+	}
+
+	return event_handled;
+}
+#else
+static inline
+bool cm_handle_fw_roaming_event(struct cnx_mgr *cm_ctx, uint16_t event,
+				uint16_t data_len, void *data)
+{
+	return false;
+}
+#endif
+
 bool cm_state_roaming_event(void *ctx, uint16_t event,
 			    uint16_t data_len, void *data)
 {
@@ -61,19 +113,9 @@ bool cm_state_roaming_event(void *ctx, uint16_t event,
 						 data_len, data);
 		}
 		break;
-	case WLAN_CM_SM_EV_ROAM_INVOKE:
-		cm_add_roam_req_to_list(cm_ctx, data);
-		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_ROAM_STARTED);
-		cm_sm_deliver_event_sync(cm_ctx,
-					 WLAN_CM_SM_EV_ROAM_INVOKE,
-					 data_len, data);
-		break;
-	case WLAN_CM_SM_EV_ROAM_START:
-		cm_add_roam_req_to_list(cm_ctx, data);
-		/* cm_fw_roam_start(cm_ctx); define in LFR3/FW roam file */
-		break;
 	default:
-		event_handled = false;
+		event_handled = cm_handle_fw_roaming_event(cm_ctx, event,
+							   data_len, data);
 		break;
 	}
 
@@ -260,12 +302,16 @@ bool cm_subst_roam_start_event(void *ctx, uint16_t event,
 			cm_handle_connect_disconnect_in_roam(cm_ctx, event,
 							     data_len, data);
 		break;
+	case WLAN_CM_SM_EV_ROAM_START:
+		cm_fw_roam_start(ctx);
+		break;
 	case WLAN_CM_SM_EV_ROAM_INVOKE:
 		cm_send_roam_invoke_req(cm_ctx, data);
 		break;
+	case WLAN_CM_SM_EV_ROAM_ABORT:
 	case WLAN_CM_SM_EV_ROAM_INVOKE_FAIL:
 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
-		cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_ROAM_INVOKE_FAIL,
+		cm_sm_deliver_event_sync(cm_ctx, event,
 					 data_len, data);
 		break;
 	default:

+ 32 - 1
umac/mlme/connection_mgr/core/src/wlan_cm_roam_util.c

@@ -164,7 +164,6 @@ bool cm_get_active_reassoc_req(struct wlan_objmgr_vdev *vdev,
 	return status;
 }
 #endif
-
 QDF_STATUS
 cm_fill_bss_info_in_roam_rsp_by_cm_id(struct cnx_mgr *cm_ctx,
 				      wlan_cm_id cm_id,
@@ -204,3 +203,35 @@ cm_fill_bss_info_in_roam_rsp_by_cm_id(struct cnx_mgr *cm_ctx,
 
 	return QDF_STATUS_E_FAILURE;
 }
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+struct cm_roam_req *cm_get_first_roam_command(struct wlan_objmgr_vdev *vdev)
+{
+	struct cnx_mgr *cm_ctx;
+	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
+	struct cm_req *cm_req = NULL;
+	uint32_t cm_id_prefix;
+
+	cm_ctx = cm_get_cm_ctx(vdev);
+
+	cm_req_lock_acquire(cm_ctx);
+	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
+	while (cur_node) {
+		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
+
+		cm_req = qdf_container_of(cur_node, struct cm_req, node);
+		cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id));
+
+		if (cm_id_prefix == ROAM_REQ_PREFIX) {
+			cm_req_lock_release(cm_ctx);
+			return &cm_req->roam_req;
+		}
+
+		cur_node = next_node;
+		next_node = NULL;
+	}
+	cm_req_lock_release(cm_ctx);
+
+	return NULL;
+}
+#endif

+ 52 - 12
umac/mlme/connection_mgr/core/src/wlan_cm_sm.c

@@ -217,6 +217,54 @@ static void cm_state_connected_exit(void *ctx)
 {
 }
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+static
+bool cm_handle_fw_roam_connected_event(struct cnx_mgr *cm_ctx, uint16_t event,
+				       uint16_t data_len, void *data)
+{
+	bool event_handled = true;
+	QDF_STATUS status;
+	struct cm_req *roam_cm_req;
+
+	switch (event) {
+	case WLAN_CM_SM_EV_ROAM_INVOKE:
+		cm_sm_transition_to(cm_ctx, WLAN_CM_S_ROAMING);
+		cm_sm_deliver_event_sync(cm_ctx,
+					 WLAN_CM_SM_EV_ROAM_INVOKE,
+					 data_len, data);
+		break;
+	case WLAN_CM_SM_EV_ROAM_ABORT:
+	case WLAN_CM_SM_EV_ROAM_INVOKE_FAIL:
+		cm_remove_cmd(cm_ctx, data);
+		break;
+	case WLAN_CM_SM_EV_ROAM_START:
+		status = cm_prepare_roam_cmd(cm_ctx, &roam_cm_req,
+					     CM_ROAMING_FW);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			event_handled = false;
+			break;
+		}
+		cm_sm_transition_to(cm_ctx, WLAN_CM_S_ROAMING);
+		cm_sm_deliver_event_sync(cm_ctx,
+					 WLAN_CM_SM_EV_ROAM_START,
+					 sizeof(*roam_cm_req), roam_cm_req);
+		break;
+	default:
+		event_handled = false;
+		break;
+	}
+
+	return event_handled;
+}
+#else
+static inline
+bool cm_handle_fw_roam_connected_event(struct cnx_mgr *cm_ctx, uint16_t event,
+				       uint16_t data_len, void *data)
+{
+	return false;
+}
+#endif
+
 /**
  * cm_state_connected_event() - Connected State event handler for
  * connection mgr
@@ -235,12 +283,6 @@ static bool cm_state_connected_event(void *ctx, uint16_t event,
 	struct cm_req *roam_cm_req;
 
 	switch (event) {
-	case WLAN_CM_SM_EV_ROAM_INVOKE:
-		cm_sm_transition_to(cm_ctx, WLAN_CM_S_ROAMING);
-		cm_sm_deliver_event_sync(cm_ctx,
-					 WLAN_CM_SM_EV_ROAM_INVOKE,
-					 data_len, data);
-		break;
 	case WLAN_CM_SM_EV_ROAM_REQ:
 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_ROAMING);
 		cm_sm_deliver_event_sync(cm_ctx,
@@ -288,15 +330,12 @@ static bool cm_state_connected_event(void *ctx, uint16_t event,
 	case WLAN_CM_SM_EV_REASSOC_DONE:
 		cm_reassoc_complete(cm_ctx, data);
 		break;
-	case WLAN_CM_SM_EV_ROAM_INVOKE_FAIL:
-		cm_remove_cmd(cm_ctx, data);
-		break;
-
 	default:
-		event_handled = false;
+		event_handled =
+			cm_handle_fw_roam_connected_event(cm_ctx, event,
+							  data_len, data);
 		break;
 	}
-
 	return event_handled;
 }
 
@@ -952,6 +991,7 @@ static const char *cm_sm_event_names[] = {
 	"EV_ROAM_COMPLETE",
 	"EV_ROAM_REQ",
 	"EV_ROAM_INVOKE",
+	"EV_ROAM_ABORT",
 };
 
 enum wlan_cm_sm_state cm_get_state(struct cnx_mgr *cm_ctx)

+ 6 - 3
umac/mlme/connection_mgr/core/src/wlan_cm_sm.h

@@ -28,6 +28,7 @@
 
 /**
  * enum wlan_cm_sm_evt - connection manager related events
+ * Note: make sure to update cm_sm_event_names on updating this enum
  * @WLAN_CM_SM_EV_CONNECT_REQ:            Connect request event from requester
  * @WLAN_CM_SM_EV_SCAN:                   Event to start connect scan
  * @WLAN_CM_SM_EV_SCAN_SUCCESS:           Connect scan success event
@@ -47,9 +48,9 @@
  * @WLAN_CM_SM_EV_DISCONNECT_ACTIVE:      Process disconnect after in active cmd
  * @WLAN_CM_SM_EV_DISCONNECT_DONE:        Disconnect done event
  * @WLAN_CM_SM_EV_ROAM_START:             Roam start event for LFR2 and LFR3
- * @WLAN_CM_SM_EV_ROAM_SYNC:              Roam sync event fro LFR3
+ * @WLAN_CM_SM_EV_ROAM_SYNC:              Roam sync event for LFR3
  * @WLAN_CM_SM_EV_ROAM_INVOKE_FAIL:       Roam invoke fail event
- * @WLAN_CM_SM_EV_ROAM_HO_FAIL:           Hand off failed event
+ * @WLAN_CM_SM_EV_ROAM_HO_FAIL:           Hands off failed event
  * @WLAN_CM_SM_EV_PREAUTH_DONE:           Preauth is completed
  * @WLAN_CM_SM_EV_GET_NEXT_PREAUTH_AP:    Get next candidate as preauth failed
  * @WLAN_CM_SM_EV_PREAUTH_FAIL:           Preauth failed for all candidate
@@ -58,9 +59,10 @@
  * @WLAN_CM_SM_EV_REASSOC_DONE:           Reassoc completed
  * @WLAN_CM_SM_EV_REASSOC_FAILURE:        Reassoc failed
  * @WLAN_CM_SM_EV_ROAM_COMPLETE:          Roaming completed
- * @WLAN_CM_SM_EV_ROAM_REQ:               LFR3/FW roam - Roam req from FW
+ * @WLAN_CM_SM_EV_ROAM_REQ:               LFR3/FW roam - Roam req from connect
  *                                        LFR2/Host roam - Roam req from host/FW
  * @WLAN_CM_SM_EV_ROAM_INVOKE:            Host initiated LFR3/FW roam req
+ * @WLAN_CM_SM_EV_ROAM_ABORT:             Roam abort
  * @WLAN_CM_SM_EV_MAX:                    Max event
  */
 enum wlan_cm_sm_evt {
@@ -95,6 +97,7 @@ enum wlan_cm_sm_evt {
 	WLAN_CM_SM_EV_ROAM_COMPLETE = 28,
 	WLAN_CM_SM_EV_ROAM_REQ = 29,
 	WLAN_CM_SM_EV_ROAM_INVOKE = 30,
+	WLAN_CM_SM_EV_ROAM_ABORT = 31,
 	WLAN_CM_SM_EV_MAX,
 };
 

+ 27 - 2
umac/mlme/connection_mgr/core/src/wlan_cm_util.c

@@ -532,6 +532,11 @@ cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t prefix,
 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
 	struct cm_req *cm_req;
 	uint32_t req_prefix;
+	bool roam_offload = false;
+
+	if (cm_roam_offload_enabled(wlan_vdev_get_psoc(cm_ctx->vdev)) &&
+	     prefix == ROAM_REQ_PREFIX)
+		roam_offload = true;
 
 	cm_req_lock_acquire(cm_ctx);
 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
@@ -541,9 +546,14 @@ cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t prefix,
 
 		req_prefix = CM_ID_GET_PREFIX(cm_req->cm_id);
 
-		/* Only remove the pending requests matching the flush prefix */
+		/*
+		 * Only remove requests matching the flush prefix and
+		 * the pending req for non roam offload(LFR3) commands
+		 * (roam command is dummy in FW roam/LFR3 so active
+		 * command can be removed)
+		 */
 		if (req_prefix != prefix ||
-		    cm_req->cm_id == cm_ctx->active_cm_id)
+		    (!roam_offload && cm_req->cm_id == cm_ctx->active_cm_id))
 			goto next;
 
 		/* If only_failed_req is set flush only failed req */
@@ -554,6 +564,8 @@ cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t prefix,
 			cm_handle_connect_flush(cm_ctx, cm_req);
 			cm_ctx->connect_count--;
 			cm_free_connect_req_mem(&cm_req->connect_req);
+		} else if (req_prefix == ROAM_REQ_PREFIX) {
+			cm_free_roam_req_mem(&cm_req->roam_req);
 		} else {
 			cm_handle_disconnect_flush(cm_ctx, cm_req);
 			cm_ctx->disconnect_count--;
@@ -762,6 +774,19 @@ void cm_remove_cmd(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id)
 	struct wlan_objmgr_psoc *psoc;
 	QDF_STATUS status;
 
+	if (!cm_id) {
+		mlme_err("cmd_id is null");
+		return;
+	}
+
+	/* return if zero or invalid cm_id */
+	if (!*cm_id || *cm_id == CM_ID_INVALID) {
+		mlme_debug(CM_PREFIX_FMT " Invalid cm_id",
+			   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
+					 *cm_id));
+		return;
+	}
+
 	psoc = wlan_vdev_get_psoc(cm_ctx->vdev);
 	if (!psoc) {
 		mlme_err(CM_PREFIX_FMT "Failed to find psoc",

+ 27 - 0
umac/mlme/include/wlan_mlme_cmn.h

@@ -52,6 +52,11 @@
  * @mlme_cm_disconnect_start_cb: Disconnect start callback
  * @vdev: vdev pointer
  *
+ * @mlme_cm_roam_start_cb: Roam start callback
+ * @vdev: vdev pointer
+ *
+ * @mlme_cm_roam_abort_cb: Roam abort callback
+ * @vdev: vdev pointer
  */
 struct mlme_cm_ops {
 	QDF_STATUS (*mlme_cm_connect_complete_cb)(
@@ -69,6 +74,10 @@ struct mlme_cm_ops {
 					struct wlan_cm_discon_rsp *rsp);
 	QDF_STATUS (*mlme_cm_disconnect_start_cb)(
 					struct wlan_objmgr_vdev *vdev);
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+	QDF_STATUS (*mlme_cm_roam_start_cb)(struct wlan_objmgr_vdev *vdev);
+	QDF_STATUS (*mlme_cm_roam_abort_cb)(struct wlan_objmgr_vdev *vdev);
+#endif
 };
 #endif
 
@@ -589,6 +598,24 @@ mlme_cm_osif_disconnect_complete(struct wlan_objmgr_vdev *vdev,
  */
 QDF_STATUS mlme_cm_osif_disconnect_start_ind(struct wlan_objmgr_vdev *vdev);
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * mlme_cm_osif_roam_start_ind() - osif Roam start indication
+ * @vdev: vdev pointer
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS mlme_cm_osif_roam_start_ind(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * mlme_cm_osif_roam_abort_ind() - osif Roam abort indication
+ * @vdev: vdev pointer
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS mlme_cm_osif_roam_abort_ind(struct wlan_objmgr_vdev *vdev);
+#endif
+
 /**
  * typedef osif_cm_get_global_ops_cb() - Callback to get connection manager
  * global ops

+ 23 - 0
umac/mlme/mlme_objmgr/dispatcher/src/wlan_cmn_mlme_main.c

@@ -459,6 +459,29 @@ QDF_STATUS mlme_cm_osif_disconnect_start_ind(struct wlan_objmgr_vdev *vdev)
 	return ret;
 }
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+QDF_STATUS mlme_cm_osif_roam_start_ind(struct wlan_objmgr_vdev *vdev)
+{
+	QDF_STATUS ret = QDF_STATUS_SUCCESS;
+
+	if (glbl_cm_ops &&
+	    glbl_cm_ops->mlme_cm_roam_start_cb)
+		ret = glbl_cm_ops->mlme_cm_roam_start_cb(vdev);
+
+	return ret;
+}
+
+QDF_STATUS mlme_cm_osif_roam_abort_ind(struct wlan_objmgr_vdev *vdev)
+{
+	QDF_STATUS ret = QDF_STATUS_SUCCESS;
+
+	if (glbl_cm_ops &&
+	    glbl_cm_ops->mlme_cm_roam_abort_cb)
+		ret = glbl_cm_ops->mlme_cm_roam_abort_cb(vdev);
+
+	return ret;
+}
+#endif
 void mlme_set_osif_cm_cb(osif_cm_get_global_ops_cb osif_cm_ops)
 {
 	glbl_cm_ops_cb = osif_cm_ops;