Bladeren bron

qcacmn: Handle serialization activation and hw mode change resp

Handle the serialization activation callback for connect and
disconnect and hw mode change resp for connect.

Change-Id: I553a650ea04daa5aa22ee43376b9359aed58c59f
CRs-Fixed: 2776022
gaurank kathpalia 4 jaren geleden
bovenliggende
commit
4609c06b56

+ 89 - 24
umac/mlme/connection_mgr/core/src/wlan_cm_connect.c

@@ -44,23 +44,27 @@ cm_ser_connect_cb(struct wlan_serialization_command *cmd,
 
 	switch (reason) {
 	case WLAN_SER_CB_ACTIVATE_CMD:
-		/* Post event to move CM SM to join active */
+		status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_CONNECT_ACTIVE,
+					     sizeof(wlan_cm_id), &cmd->cmd_id);
+		/*
+		 * Handle failure if posting fails, i.e. the SM state has
+		 * changed or head cm_id doesn't match the active cm_id.
+		 * connect active should be handled only in JOIN_PENDING. If
+		 * new command has been received connect activation should be
+		 * aborted from here with connect req cleanup.
+		 */
 		break;
-
 	case WLAN_SER_CB_CANCEL_CMD:
 		/* command removed from pending list. */
 		break;
-
 	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
 		mlme_err("Active command timeout cm_id %d", cmd->cmd_id);
 		QDF_ASSERT(0);
 		break;
-
 	case WLAN_SER_CB_RELEASE_MEM_CMD:
 		/* command completed. Release reference of vdev */
 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
 		break;
-
 	default:
 		QDF_ASSERT(0);
 		status = QDF_STATUS_E_INVAL;
@@ -112,13 +116,93 @@ static QDF_STATUS cm_ser_connect_req(struct wlan_objmgr_pdev *pdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+static QDF_STATUS
+cm_send_connect_start_fail(struct cnx_mgr *cm_ctx,
+			   struct cm_connect_req *req,
+			   enum wlan_cm_connect_fail_reason reason)
+{
+	struct wlan_cm_connect_rsp *resp;
+	QDF_STATUS status;
+
+	resp = qdf_mem_malloc(sizeof(*resp));
+	if (!resp)
+		return QDF_STATUS_E_NOMEM;
+
+	/* fill resp from req */
+
+	status = cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_CONNECT_FAILURE,
+					  sizeof(*resp), resp);
+	qdf_mem_free(resp);
+
+	return status;
+}
+
 #ifdef WLAN_POLICY_MGR_ENABLE
 
+QDF_STATUS cm_handle_hw_mode_change(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id,
+				    enum wlan_cm_sm_evt event)
+{
+	struct cm_req *cm_req;
+	enum wlan_cm_connect_fail_reason reason = CM_GENERIC_FAILURE;
+	struct wlan_objmgr_pdev *pdev;
+	QDF_STATUS status;
+
+	if (!cm_id)
+		return QDF_STATUS_E_FAILURE;
+
+	cm_req = cm_get_req_by_cm_id(cm_ctx, *cm_id);
+	if (!cm_req)
+		return QDF_STATUS_E_INVAL;
+
+	pdev = wlan_vdev_get_pdev(cm_ctx->vdev);
+	if (!pdev) {
+		mlme_err("Failed to find pdev from vdev");
+		goto send_failure;
+	}
+
+	if (event == WLAN_CM_SM_EV_HW_MODE_SUCCESS) {
+		status = cm_ser_connect_req(pdev, cm_ctx, &cm_req->connect_req);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			reason = CM_SER_FAILURE;
+			goto send_failure;
+		}
+		return status;
+	}
+
+	/* Set reason HW mode fail for event WLAN_CM_SM_EV_HW_MODE_FAILURE */
+	reason = CM_HW_MODE_FAILURE;
+
+send_failure:
+	return cm_send_connect_start_fail(cm_ctx, &cm_req->connect_req, reason);
+}
+
 void cm_hw_mode_change_resp(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
 			    wlan_cm_id cm_id, QDF_STATUS status)
 {
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS qdf_status;
+	enum wlan_cm_sm_evt event = WLAN_CM_SM_EV_HW_MODE_SUCCESS;
+
 	mlme_debug("vdev %d cm id %d Continue connect after HW mode change, status %d",
 		   vdev_id, cm_id, status);
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev)
+		return;
+
+	if (QDF_IS_STATUS_ERROR(status))
+		event = WLAN_CM_SM_EV_HW_MODE_FAILURE;
+	qdf_status = cm_sm_deliver_event(vdev, event, sizeof(wlan_cm_id),
+					 &cm_id);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+	/*
+	 * Handle failure if posting fails, i.e. the SM state has
+	 * changed or head cm_id doesn't match the active cm_id.
+	 * hw mode change resp should be handled only in JOIN_PENDING. If
+	 * new command has been received connect should be
+	 * aborted from here with connect req cleanup.
+	 */
 }
 
 static QDF_STATUS cm_check_for_hw_mode_change(struct wlan_objmgr_psoc *psoc,
@@ -236,25 +320,6 @@ static void cm_connect_prepare_scan_fliter(struct cnx_mgr *cm_ctx,
 	/* Fill fils info */
 }
 
-static QDF_STATUS
-cm_send_connect_start_fail(struct cnx_mgr *cm_ctx,
-			   struct cm_connect_req *cm_req,
-			   enum wlan_cm_connect_fail_reason reason)
-{
-	struct wlan_cm_connect_rsp *resp;
-	QDF_STATUS status;
-
-	resp = qdf_mem_malloc(sizeof(*resp));
-	if (!resp)
-		return QDF_STATUS_E_NOMEM;
-
-	status = cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_CONNECT_FAILURE,
-					  sizeof(*resp), resp);
-	qdf_mem_free(resp);
-
-	return status;
-}
-
 static QDF_STATUS cm_connect_get_candidates(struct wlan_objmgr_pdev *pdev,
 					    struct cnx_mgr *cm_ctx,
 					    struct cm_connect_req *cm_req)

+ 10 - 5
umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.c

@@ -38,23 +38,28 @@ cm_ser_disconnect_cb(struct wlan_serialization_command *cmd,
 
 	switch (reason) {
 	case WLAN_SER_CB_ACTIVATE_CMD:
-		/* Post event disconnect active to CM SM */
+		status = cm_sm_deliver_event(vdev,
+					     WLAN_CM_SM_EV_DISCONNECT_ACTIVE,
+					     sizeof(wlan_cm_id), &cmd->cmd_id);
+		/*
+		 * Handle failure if posting fails, i.e. the SM state has
+		 * changes. Disconnect shoul dbe handled in JOIN_PENDING,
+		 * JOIN-SCAN state as well apart from DISCONNECTING.
+		 * Also no need to check for head list as diconnect needs to be
+		 * completed always once active.
+		 */
 		break;
-
 	case WLAN_SER_CB_CANCEL_CMD:
 		/* command removed from pending list. */
 		break;
-
 	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
 		mlme_err("Active command timeout cm_id %d", cmd->cmd_id);
 		QDF_ASSERT(0);
 		break;
-
 	case WLAN_SER_CB_RELEASE_MEM_CMD:
 		/* command completed. Release reference of vdev */
 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
 		break;
-
 	default:
 		QDF_ASSERT(0);
 		status = QDF_STATUS_E_INVAL;

+ 34 - 2
umac/mlme/connection_mgr/core/src/wlan_cm_main_api.h

@@ -24,6 +24,7 @@
 #define __WLAN_CM_MAIN_API_H__
 
 #include "wlan_cm_main.h"
+#include "wlan_cm_sm.h"
 #include <include/wlan_mlme_cmn.h>
 
 /*************** CONNECT APIs ****************/
@@ -133,11 +134,27 @@ QDF_STATUS cm_connect_start_req(struct wlan_objmgr_vdev *vdev,
  * @cm_id: connection ID which gave the hw mode change request
  * @status: status of the HW mode change.
  *
- * Return: QDF_STATUS
+ * Return: void
  */
 void cm_hw_mode_change_resp(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
 			    wlan_cm_id cm_id, QDF_STATUS status);
 
+/**
+ * cm_handle_hw_mode_change() - SM handling of hw mode change resp
+ * @cm_ctx: connection manager context
+ * @cm_id: Connection mgr ID assigned to this connect request.
+ * @event: HW mode success or failure event
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS cm_handle_hw_mode_change(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id,
+				    enum wlan_cm_sm_evt event);
+#else
+QDF_STATUS cm_handle_hw_mode_change(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id,
+				    enum wlan_cm_sm_evt event)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif
 
 /*************** DISCONNECT APIs ****************/
@@ -227,7 +244,22 @@ struct cnx_mgr *cm_get_cm_ctx(struct wlan_objmgr_vdev *vdev);
  *
  * Return: true if match else false
  */
-bool cm_check_cmid_match_list_head(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id);
+bool cm_check_cmid_match_list_head(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id);
+
+/**
+ * cm_check_scanid_match_list_head() - check if list head command matches the
+ * given scan_id
+ * @cm_ctx: connection manager context
+ * @scan_id: scan_id of connect req
+ *
+ * Check if front req command is connect command and matches the given
+ * scan_id, this can be used to check if the latest (head) is same we are
+ * trying to processing
+ *
+ * Return: true if match else false
+ */
+bool cm_check_scanid_match_list_head(struct cnx_mgr *cm_ctx,
+				     wlan_scan_id *scan_id);
 
 /**
  * cm_delete_req_from_list() - Delete the request matching cm id

+ 22 - 0
umac/mlme/connection_mgr/core/src/wlan_cm_sm.c

@@ -370,10 +370,25 @@ static bool cm_subst_join_pending_event(void *ctx, uint16_t event,
 		status = true;
 		break;
 	case WLAN_CM_SM_EV_CONNECT_ACTIVE:
+		/* check if cm id is valid for the current req */
+		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
+			status = false;
+			break;
+		}
 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_ACTIVE);
 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
 		status = true;
 		break;
+	case WLAN_CM_SM_EV_HW_MODE_SUCCESS:
+	case WLAN_CM_SM_EV_HW_MODE_FAILURE:
+		/* check if cm id is valid for the current req */
+		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
+			status = false;
+			break;
+		}
+		cm_handle_hw_mode_change(cm_ctx, data, event);
+		status = true;
+		break;
 	case WLAN_CM_SM_EV_SCAN:
 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_SCAN);
 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
@@ -453,6 +468,11 @@ static bool cm_subst_scan_event(void *ctx, uint16_t event,
 		break;
 	case WLAN_CM_SM_EV_SCAN_SUCCESS:
 	case WLAN_CM_SM_EV_SCAN_FAILURE:
+		/* check if scan id is valid for the current req */
+		if (!cm_check_scanid_match_list_head(cm_ctx, data)) {
+			status = false;
+			break;
+		}
 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING);
 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
 		status = true;
@@ -697,6 +717,8 @@ static const char *cm_sm_event_names[] = {
 	"EV_SCAN",
 	"EV_SCAN_SUCCESS",
 	"EV_SCAN_FAILURE",
+	"EV_HW_MODE_SUCCESS",
+	"EV_HW_MODE_FAILURE",
 	"EV_CONNECT_START",
 	"EV_CONNECT_ACTIVE",
 	"EV_CONNECT_SUCCESS",

+ 24 - 20
umac/mlme/connection_mgr/core/src/wlan_cm_sm.h

@@ -32,6 +32,8 @@
  * @WLAN_CM_SM_EV_SCAN:                   Event to start connect scan
  * @WLAN_CM_SM_EV_SCAN_SUCCESS:           Connect scan success event
  * @WLAN_CM_SM_EV_SCAN_FAILURE:           Connect scan fail event
+ * @WLAN_CM_SM_EV_HW_MODE_SUCCESS:        Hw mode change is success
+ * @WLAN_CM_SM_EV_HW_MODE_FAILURE:        Hw mode change is failure
  * @WLAN_CM_SM_EV_CONNECT_START:          Connect start process initiate
  * @WLAN_CM_SM_EV_CONNECT_ACTIVE:         Connect request is activated
  * @WLAN_CM_SM_EV_CONNECT_SUCCESS:        Connect success
@@ -60,26 +62,28 @@ enum wlan_cm_sm_evt {
 	WLAN_CM_SM_EV_SCAN = 1,
 	WLAN_CM_SM_EV_SCAN_SUCCESS = 2,
 	WLAN_CM_SM_EV_SCAN_FAILURE = 3,
-	WLAN_CM_SM_EV_CONNECT_START = 4,
-	WLAN_CM_SM_EV_CONNECT_ACTIVE = 5,
-	WLAN_CM_SM_EV_CONNECT_SUCCESS = 6,
-	WLAN_CM_SM_EV_CONNECT_GET_NEXT_CANDIDATE = 7,
-	WLAN_CM_SM_EV_CONNECT_FAILURE = 8,
-	WLAN_CM_SM_EV_DISCONNECT_REQ = 9,
-	WLAN_CM_SM_EV_DISCONNECT_START = 10,
-	WLAN_CM_SM_EV_DISCONNECT_ACTIVE = 11,
-	WLAN_CM_SM_EV_DISCONNECT_DONE = 12,
-	WLAN_CM_SM_EV_ROAM_START = 13,
-	WLAN_CM_SM_EV_ROAM_SYNC = 14,
-	WLAN_CM_SM_EV_ROAM_INVOKE_FAIL = 15,
-	WLAN_CM_SM_EV_ROAM_HO_FAIL = 16,
-	WLAN_CM_SM_EV_PREAUTH_DONE = 17,
-	WLAN_CM_SM_EV_GET_NEXT_PREAUTH_AP = 18,
-	WLAN_CM_SM_EV_PREAUTH_FAIL = 19,
-	WLAN_CM_SM_EV_START_REASSOC = 20,
-	WLAN_CM_SM_EV_REASSOC_DONE = 21,
-	WLAN_CM_SM_EV_REASSOC_FAILURE = 22,
-	WLAN_CM_SM_EV_ROAM_COMPLETE = 23,
+	WLAN_CM_SM_EV_HW_MODE_SUCCESS = 4,
+	WLAN_CM_SM_EV_HW_MODE_FAILURE = 5,
+	WLAN_CM_SM_EV_CONNECT_START = 6,
+	WLAN_CM_SM_EV_CONNECT_ACTIVE = 7,
+	WLAN_CM_SM_EV_CONNECT_SUCCESS = 8,
+	WLAN_CM_SM_EV_CONNECT_GET_NEXT_CANDIDATE = 9,
+	WLAN_CM_SM_EV_CONNECT_FAILURE = 10,
+	WLAN_CM_SM_EV_DISCONNECT_REQ = 11,
+	WLAN_CM_SM_EV_DISCONNECT_START = 12,
+	WLAN_CM_SM_EV_DISCONNECT_ACTIVE = 13,
+	WLAN_CM_SM_EV_DISCONNECT_DONE = 14,
+	WLAN_CM_SM_EV_ROAM_START = 15,
+	WLAN_CM_SM_EV_ROAM_SYNC = 16,
+	WLAN_CM_SM_EV_ROAM_INVOKE_FAIL = 17,
+	WLAN_CM_SM_EV_ROAM_HO_FAIL = 18,
+	WLAN_CM_SM_EV_PREAUTH_DONE = 19,
+	WLAN_CM_SM_EV_GET_NEXT_PREAUTH_AP = 20,
+	WLAN_CM_SM_EV_PREAUTH_FAIL = 21,
+	WLAN_CM_SM_EV_START_REASSOC = 22,
+	WLAN_CM_SM_EV_REASSOC_DONE = 23,
+	WLAN_CM_SM_EV_REASSOC_FAILURE = 24,
+	WLAN_CM_SM_EV_ROAM_COMPLETE = 25,
 	WLAN_CM_SM_EV_MAX,
 };
 

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

@@ -102,11 +102,46 @@ static inline void cm_req_lock_release(struct cnx_mgr *cm_ctx)
 }
 #endif /* WLAN_CM_USE_SPINLOCK */
 
-bool cm_check_cmid_match_list_head(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
+bool cm_check_cmid_match_list_head(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id)
 {
 	qdf_list_node_t *cur_node = NULL;
 	struct cm_req *cm_req;
 	bool match = false;
+	wlan_cm_id head_cm_id = 0;
+
+	if (!cm_id)
+		return false;
+
+	cm_req_lock_acquire(cm_ctx);
+	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
+	if (!cur_node)
+		goto exit;
+
+	cm_req = qdf_container_of(cur_node, struct cm_req, node);
+	head_cm_id = cm_req->cm_id;
+	if (head_cm_id == *cm_id)
+		match = true;
+
+exit:
+	cm_req_lock_release(cm_ctx);
+	if (!match)
+		mlme_info("head_cm_id %d didn't match the given cm_id %d",
+			  head_cm_id, *cm_id);
+
+	return match;
+}
+
+bool cm_check_scanid_match_list_head(struct cnx_mgr *cm_ctx,
+				     wlan_scan_id *scan_id)
+{
+	qdf_list_node_t *cur_node = NULL;
+	struct cm_req *cm_req;
+	bool match = false;
+	wlan_cm_id head_scan_id = 0;
+	uint32_t prefix = 0;
+
+	if (!scan_id)
+		return false;
 
 	cm_req_lock_acquire(cm_ctx);
 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
@@ -114,11 +149,19 @@ bool cm_check_cmid_match_list_head(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
 		goto exit;
 
 	cm_req = qdf_container_of(cur_node, struct cm_req, node);
-	if (cm_req->cm_id == cm_id)
+	prefix = CM_ID_GET_PREFIX(cm_req->cm_id);
+	/* Check only if head is connect req */
+	if (prefix != CONNECT_REQ_PREFIX)
+		goto exit;
+	head_scan_id = cm_req->connect_req.scan_id;
+	if (head_scan_id == *scan_id)
 		match = true;
 
 exit:
 	cm_req_lock_release(cm_ctx);
+	if (!match)
+		mlme_info("head_scan_id %d didn't match the given scan_id %d prefix %x",
+			  head_scan_id, *scan_id, prefix);
 
 	return match;
 }