瀏覽代碼

qcacld-3.0: Add host roam preauth handling code for connection manager

Add host roam preauth handling code for connection manager.

Change-Id: Id97d716a6c47ba08b2e8ef5e3ed675c5dcf88ed8
CRs-Fixed: 2954515
Huashan Qu 4 年之前
父節點
當前提交
1557129851

+ 8 - 0
Kbuild

@@ -1460,6 +1460,14 @@ MLME_OBJS +=    $(CM_TGT_IF_DIR)/src/target_if_cm_roam_event.o \
 		$(CM_DIR)/core/src/wlan_cm_roam_offload_event.o
 endif
 
+ifeq ($(CONFIG_CM_ENABLE), y)
+ifeq ($(CONFIG_QCACLD_WLAN_LFR2), y)
+# Add LFR2/host roam specific connection manager files here
+MLME_OBJS +=    $(CM_DIR)/core/src/wlan_cm_host_roam_preauth.o \
+		$(CM_DIR)/core/src/wlan_cm_host_util.o
+endif
+endif
+
 ####### WFA_CONFIG ########
 
 WFA_DIR := components/umac/mlme/wfa_config

+ 0 - 1
components/mlme/core/inc/wlan_mlme_main.h

@@ -303,7 +303,6 @@ struct ft_context {
 	enum ft_ie_state ft_state;
 	bool add_mdie;
 #endif
-
 };
 
 /**

+ 3 - 0
components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c

@@ -1821,5 +1821,8 @@ static struct mlme_ext_ops ext_ops = {
 	.mlme_cm_ext_disconnect_complete_ind_cb = cm_disconnect_complete_ind,
 	.mlme_cm_ext_vdev_down_req_cb = cm_send_vdev_down_req,
 	.mlme_cm_ext_reassoc_req_cb = cm_handle_reassoc_req,
+#ifdef WLAN_FEATURE_HOST_ROAM
+	.mlme_cm_ext_roam_start_ind_cb = cm_handle_roam_start,
+#endif
 #endif
 };

+ 678 - 0
components/umac/mlme/connection_mgr/core/src/wlan_cm_host_roam_preauth.c

@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) 2021 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_cm_host_roam_preauth.c
+ *
+ * Implements general roam pre-auth functionality for connection manager
+ */
+
+#include "wlan_cm_vdev_api.h"
+#include "wni_api.h"
+#include <wlan_cm_api.h>
+#include "wlan_cm_roam_api.h"
+#include "wlan_cm_roam_public_struct.h"
+#include "wlan_cm_public_struct.h"
+#include "connection_mgr/core/src/wlan_cm_roam.h"
+#include "connection_mgr/core/src/wlan_cm_sm.h"
+#include "connection_mgr/core/src/wlan_cm_main_api.h"
+
+#define MAX_NUM_PREAUTH_RETRIES 3
+#define CM_PREAUTH_TIMEOUT 10000
+#define REASSOC_TIMER_DURATION 60
+
+static QDF_STATUS cm_get_valid_preauth_candidate(struct cm_roam_req *cm_req)
+{
+	qdf_list_t *candidate_list;
+	qdf_list_node_t *cur_node = NULL;
+	struct scan_cache_node *prev_candidate;
+	bool new_candidate = false;
+	uint8_t vdev_id = cm_req->req.vdev_id;
+
+	candidate_list = cm_req->candidate_list;
+	if (!candidate_list || !qdf_list_size(candidate_list)) {
+		mlme_info(CM_PREFIX_FMT "no valid candidate found",
+			  CM_PREFIX_REF(vdev_id, cm_req->cm_id));
+		return QDF_STATUS_E_EMPTY;
+	}
+
+	prev_candidate = cm_req->cur_candidate;
+	if (!prev_candidate) {
+		qdf_list_peek_front(candidate_list, &cur_node);
+		new_candidate = true;
+	} else if (cm_req->num_preauth_retry >= MAX_NUM_PREAUTH_RETRIES) {
+		qdf_list_peek_next(candidate_list, &prev_candidate->node,
+				   &cur_node);
+		new_candidate = true;
+	}
+
+	if (new_candidate) {
+		if (!cur_node) {
+			mlme_debug(CM_PREFIX_FMT "All canidate tried",
+				   CM_PREFIX_REF(vdev_id, cm_req->cm_id));
+			return QDF_STATUS_E_FAILURE;
+		}
+		cm_req->num_preauth_retry = 0;
+		cm_req->cur_candidate = qdf_container_of(cur_node,
+							 struct scan_cache_node,
+							 node);
+	}
+
+	cm_req->num_preauth_retry++;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void cm_preauth_fail(struct cnx_mgr *cm_ctx,
+		     struct wlan_cm_preauth_fail *preauth_fail_rsp)
+{
+	struct cm_req *cm_req;
+	wlan_cm_id cm_id;
+
+	cm_id = preauth_fail_rsp->cm_id;
+	cm_req = cm_get_req_by_cm_id(cm_ctx, cm_id);
+	/*
+	 * If the entry is not present in the list, it must have been cleared
+	 * already.
+	 */
+	if (!cm_req)
+		return;
+
+	if (cm_get_state(cm_ctx) == WLAN_CM_S_CONNECTED)
+		cm_mlme_roam_preauth_fail(cm_ctx->vdev, &cm_req->roam_req.req,
+					  preauth_fail_rsp->reason);
+
+	mlme_debug(CM_PREFIX_FMT,
+		   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id));
+
+	if (cm_req->roam_req.req.source == CM_ROAMING_HOST &&
+	    cm_get_state(cm_ctx) == WLAN_CM_S_CONNECTED)
+		wlan_cm_disconnect(cm_ctx->vdev, CM_ROAM_DISCONNECT,
+				   REASON_USER_TRIGGERED_ROAM_FAILURE, NULL);
+
+	cm_remove_cmd(cm_ctx, &cm_id);
+}
+
+static void
+cm_preauth_handle_event_post_fail(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
+{
+	struct wlan_cm_preauth_fail preauth_fail_rsp;
+
+	preauth_fail_rsp.cm_id = cm_id;
+	preauth_fail_rsp.reason = CM_ABORT_DUE_TO_NEW_REQ_RECVD;
+
+	cm_preauth_fail(cm_ctx, &preauth_fail_rsp);
+}
+
+static QDF_STATUS
+cm_preauth_cmd_timeout(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
+{
+	QDF_STATUS status;
+	struct wlan_cm_preauth_fail preauth_fail_rsp;
+
+	preauth_fail_rsp.cm_id = cm_id;
+	preauth_fail_rsp.reason = CM_SER_TIMEOUT;
+
+	status = cm_sm_deliver_event(
+			cm_ctx->vdev, WLAN_CM_SM_EV_PREAUTH_FAIL,
+			sizeof(struct wlan_cm_preauth_fail), &preauth_fail_rsp);
+	if (QDF_IS_STATUS_ERROR(status))
+		cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
+
+	return status;
+}
+
+static QDF_STATUS
+cm_ser_preauth_cb(struct wlan_serialization_command *cmd,
+		  enum wlan_serialization_cb_reason reason)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct wlan_objmgr_vdev *vdev;
+	struct cnx_mgr *cm_ctx;
+
+	if (!cmd) {
+		mlme_err("cmd is NULL, reason: %d", reason);
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	vdev = cmd->vdev;
+	cm_ctx = cm_get_cm_ctx(vdev);
+	if (!cm_ctx)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	switch (reason) {
+	case WLAN_SER_CB_ACTIVATE_CMD:
+		if (cmd->activation_reason == SER_PENDING_TO_ACTIVE)
+			status = cm_sm_deliver_event(
+					vdev, WLAN_CM_SM_EV_PREAUTH_ACTIVE,
+					sizeof(wlan_cm_id), &cmd->cmd_id);
+		else
+			status = cm_sm_deliver_event_sync(
+					cm_ctx, WLAN_CM_SM_EV_PREAUTH_ACTIVE,
+					sizeof(wlan_cm_id), &cmd->cmd_id);
+		if (QDF_IS_STATUS_SUCCESS(status))
+			break;
+		/*
+		 * 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.
+		 */
+		cm_preauth_handle_event_post_fail(cm_ctx, cmd->cmd_id);
+		break;
+	case WLAN_SER_CB_CANCEL_CMD:
+		/* command removed from pending list. */
+		break;
+	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
+		mlme_err(CM_PREFIX_FMT "Active command timeout",
+			 CM_PREFIX_REF(wlan_vdev_get_id(vdev), cmd->cmd_id));
+		QDF_ASSERT(0);
+
+		cm_preauth_cmd_timeout(cm_ctx, cmd->cmd_id);
+		break;
+	case WLAN_SER_CB_RELEASE_MEM_CMD:
+		cm_reset_active_cm_id(vdev, cmd->cmd_id);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+		break;
+	default:
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+
+	return status;
+}
+
+static QDF_STATUS cm_ser_preauth_req(struct cnx_mgr *cm_ctx,
+				     struct cm_req *cm_req)
+{
+	struct wlan_serialization_command cmd = {0, };
+	enum wlan_serialization_status ser_cmd_status;
+	QDF_STATUS status;
+	uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
+
+	status = wlan_objmgr_vdev_try_get_ref(cm_ctx->vdev, WLAN_MLME_CM_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlme_err(CM_PREFIX_FMT "unable to get reference",
+			 CM_PREFIX_REF(vdev_id, cm_req->cm_id));
+		return status;
+	}
+
+	cmd.cmd_type = WLAN_SER_CMD_PERFORM_PRE_AUTH;
+	cmd.cmd_id = cm_req->cm_id;
+	cmd.cmd_cb = cm_ser_preauth_cb;
+	cmd.source = WLAN_UMAC_COMP_MLME;
+	cmd.is_high_priority = false;
+	cmd.cmd_timeout_duration = CM_PREAUTH_TIMEOUT;
+	cmd.vdev = cm_ctx->vdev;
+	cmd.is_blocking = true;
+
+	ser_cmd_status = wlan_serialization_request(&cmd);
+	switch (ser_cmd_status) {
+	case WLAN_SER_CMD_PENDING:
+		/* command moved to pending list.Do nothing */
+		break;
+	case WLAN_SER_CMD_ACTIVE:
+		/* command moved to active list. Do nothing */
+		break;
+	default:
+		mlme_err(CM_PREFIX_FMT "ser cmd status %d",
+			 CM_PREFIX_REF(vdev_id, cm_req->cm_id), ser_cmd_status);
+		wlan_objmgr_vdev_release_ref(cm_ctx->vdev, WLAN_MLME_CM_ID);
+
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cm_send_preauth_start_fail(struct cnx_mgr *cm_ctx,
+			   wlan_cm_id cm_id,
+			   enum wlan_cm_connect_fail_reason reason)
+{
+	QDF_STATUS status;
+	struct wlan_cm_preauth_fail preauth_fail_rsp;
+
+	preauth_fail_rsp.cm_id = cm_id;
+	preauth_fail_rsp.reason = reason;
+
+	status = cm_sm_deliver_event_sync(
+			cm_ctx, WLAN_CM_SM_EV_PREAUTH_FAIL,
+			sizeof(struct wlan_cm_preauth_fail), &preauth_fail_rsp);
+	if (QDF_IS_STATUS_ERROR(status))
+		cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
+
+	return status;
+}
+
+QDF_STATUS cm_host_roam_preauth_start(struct cnx_mgr *cm_ctx,
+				      struct cm_req *cm_req)
+{
+	QDF_STATUS status;
+
+	status = cm_get_valid_preauth_candidate(&cm_req->roam_req);
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
+
+	return cm_ser_preauth_req(cm_ctx, cm_req);
+}
+
+void cm_free_preauth_req(struct wlan_preauth_req *preauth_req)
+{
+	if (!preauth_req)
+		return;
+
+	util_scan_free_cache_entry(preauth_req->entry);
+	preauth_req->entry = NULL;
+	qdf_mem_free(preauth_req);
+}
+
+static QDF_STATUS cm_flush_preauth_req(struct scheduler_msg *msg)
+{
+	struct wlan_preauth_req *preauth_req;
+
+	if (!msg || !msg->bodyptr) {
+		mlme_err("msg or msg->bodyptr is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	preauth_req = msg->bodyptr;
+	cm_free_preauth_req(preauth_req);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+cm_issue_preauth_req(struct cnx_mgr *cm_ctx, struct cm_roam_req *roam_req)
+{
+	struct wlan_preauth_req *preauth_req;
+	struct scheduler_msg msg;
+	QDF_STATUS status;
+
+	qdf_mem_zero(&msg, sizeof(msg));
+	preauth_req = qdf_mem_malloc(sizeof(*preauth_req));
+	if (!preauth_req)
+		return QDF_STATUS_E_NOMEM;
+
+	preauth_req->vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
+	preauth_req->entry =
+		util_scan_copy_cache_entry(roam_req->cur_candidate->entry);
+
+	if (!preauth_req->entry) {
+		qdf_mem_free(preauth_req);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	msg.bodyptr = preauth_req;
+	msg.type = CM_PREAUTH_REQ;
+	msg.flush_callback = cm_flush_preauth_req;
+
+	status = scheduler_post_message(QDF_MODULE_ID_MLME,
+					QDF_MODULE_ID_PE,
+					QDF_MODULE_ID_PE, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlme_err(CM_PREFIX_FMT "msg post fail",
+			 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
+				       roam_req->cm_id));
+		cm_free_preauth_req(preauth_req);
+	}
+
+	return status;
+}
+
+QDF_STATUS cm_preauth_active(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id)
+{
+	struct cm_req *cm_req;
+	struct cm_roam_req *roam_req;
+	QDF_STATUS status;
+
+	cm_req = cm_get_req_by_cm_id(cm_ctx, *cm_id);
+	if (!cm_req)
+		return QDF_STATUS_E_INVAL;
+
+	cm_ctx->active_cm_id = *cm_id;
+	roam_req = &cm_req->roam_req;
+
+	status = cm_issue_preauth_req(cm_ctx, roam_req);
+	if (QDF_IS_STATUS_ERROR(status))
+		cm_send_preauth_start_fail(cm_ctx, *cm_id, CM_GENERIC_FAILURE);
+
+	return status;
+}
+
+#ifdef FEATURE_WLAN_ESE
+static void cm_update_cckmtsf(uint32_t *timestamp0, uint32_t *timestamp1,
+			      uint64_t *incr)
+{
+	uint64_t timestamp64 = ((uint64_t)*timestamp1 << 32) | (*timestamp0);
+
+	timestamp64 = (uint64_t)(timestamp64 + (*incr));
+	*timestamp0 = (uint32_t)(timestamp64 & 0xffffffff);
+	*timestamp1 = (uint32_t)((timestamp64 >> 32) & 0xffffffff);
+}
+
+/**
+ * cm_roam_read_tsf() - read TSF
+ * @cm_ctx: connection manager context
+ * @rsp: preauth response
+ *
+ * This function reads the TSF and also add the time elapsed since last
+ * beacon or probe response reception from the hand off AP to arrive at
+ * the latest TSF value.
+ *
+ * Return: none
+ */
+static void cm_roam_read_tsf(struct cnx_mgr *cm_ctx,
+			     struct wlan_preauth_rsp *rsp)
+{
+	struct cm_req *cm_req;
+	struct scan_cache_entry *scan_entry;
+	uint64_t timer_diff = 0;
+
+	cm_req = cm_get_req_by_cm_id(cm_ctx, rsp->cm_id);
+	if (!cm_req)
+		return;
+	if (!cm_req->roam_req.cur_candidate ||
+	    !cm_req->roam_req.cur_candidate->entry)
+		return;
+
+	scan_entry = cm_req->roam_req.cur_candidate->entry;
+	qdf_mem_copy(rsp->timestamp, scan_entry->tsf_info.data, 8);
+
+	/* Get the time diff in nano seconds */
+	timer_diff = qdf_get_monotonic_boottime_ns() - scan_entry->boottime_ns;
+	/* Convert msec to micro sec timer */
+	timer_diff = do_div(timer_diff, SYSTEM_TIME_NSEC_TO_USEC);
+	/*  Update the TSF with the difference in system time */
+	cm_update_cckmtsf(&rsp->timestamp[0], &rsp->timestamp[1],
+			  &timer_diff);
+}
+#else
+static inline void cm_roam_read_tsf(struct cnx_mgr *cm_ctx,
+				    struct wlan_preauth_rsp *rsp)
+{}
+#endif
+
+#define MD_IE_ID 54
+
+void cm_reassoc_timer_callback(void *context)
+{
+	QDF_STATUS status;
+	struct reassoc_timer_ctx *ctx = context;
+	struct cnx_mgr *cm_ctx;
+	struct wlan_objmgr_vdev *vdev;
+	wlan_cm_id cm_id = ctx->cm_id;
+	uint8_t vdev_id = ctx->vdev_id;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(ctx->pdev, vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev) {
+		mlme_err(CM_PREFIX_FMT "vdev object is NULL",
+			 CM_PREFIX_REF(vdev_id, cm_id));
+		return;
+	}
+
+	cm_ctx = cm_get_cm_ctx(vdev);
+	if (!cm_ctx)
+		goto rel_ref;
+
+	status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_REASSOC_TIMER,
+				     sizeof(wlan_cm_id), &cm_id);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
+
+rel_ref:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+}
+
+void cm_preauth_success(struct cnx_mgr *cm_ctx, struct wlan_preauth_rsp *rsp)
+{
+	QDF_STATUS status;
+	struct mlme_legacy_priv *mlme_priv;
+	struct rso_config *rso_cfg;
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_objmgr_vdev *vdev;
+	uint8_t vdev_id = rsp->vdev_id;
+	wlan_cm_id cm_id = rsp->cm_id;
+	struct cm_roam_values_copy config;
+	bool is_11r;
+
+	vdev = cm_ctx->vdev;
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev || !rsp->psoc) {
+		mlme_err(CM_PREFIX_FMT "pdev or psoc is NULL",
+			 CM_PREFIX_REF(vdev_id, cm_id));
+		goto err;
+	}
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_err(CM_PREFIX_FMT "vdev ext priv is NULL",
+			 CM_PREFIX_REF(vdev_id, cm_id));
+		goto err;
+	}
+
+	rso_cfg = wlan_cm_get_rso_config(vdev);
+	if (!rso_cfg) {
+		mlme_err(CM_PREFIX_FMT "rso_cfg is NULL",
+			 CM_PREFIX_REF(vdev_id, cm_id));
+		goto err;
+	}
+
+	mlme_err(CM_PREFIX_FMT "Preauth success with " QDF_MAC_ADDR_FMT,
+		 CM_PREFIX_REF(vdev_id, rsp->cm_id),
+		 QDF_MAC_ADDR_REF(rsp->pre_auth_bssid.bytes));
+
+	cm_csr_preauth_done(vdev);
+
+	qdf_mem_copy(rsp->ric_ies,
+		     mlme_priv->connect_info.ft_info.ric_ies,
+		     mlme_priv->connect_info.ft_info.ric_ies_length);
+	rsp->ric_ies_length = mlme_priv->connect_info.ft_info.ric_ies_length;
+
+	mlme_priv->connect_info.ft_info.ft_state = FT_REASSOC_REQ_WAIT;
+
+	/* start reassoc timer */
+	rso_cfg->ctx.pdev = pdev;
+	rso_cfg->ctx.vdev_id = vdev_id;
+	rso_cfg->ctx.cm_id = cm_id;
+
+	status = qdf_mc_timer_start(&rso_cfg->reassoc_timer,
+				    REASSOC_TIMER_DURATION);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlme_err(CM_PREFIX_FMT "start reassoc timer failed, status %d",
+			 CM_PREFIX_REF(vdev_id, cm_id), status);
+		goto err;
+	}
+
+	wlan_cm_roam_cfg_get_value(rsp->psoc, vdev_id, IS_11R_CONNECTION,
+				   &config);
+	is_11r = config.bool_value;
+	if (is_11r)
+		mlme_cm_osif_ft_preauth_complete(vdev, rsp);
+
+	if (wlan_cm_get_ese_assoc(pdev, vdev_id)) {
+		cm_roam_read_tsf(cm_ctx, rsp);
+		mlme_cm_osif_cckm_preauth_complete(vdev, rsp);
+	}
+
+	if (cm_is_fast_roam_enabled(rsp->psoc) &&
+	    cm_is_rsn_or_8021x_sha256_auth_type(vdev))
+		mlme_cm_osif_pmksa_candidate_notify(vdev, &rsp->pre_auth_bssid,
+						    1, false);
+
+	mlme_priv->connect_info.ft_info.add_mdie = false;
+	if (!is_11r && !cm_is_open_mode(vdev))
+		return;
+
+	qdf_mem_zero(mlme_priv->connect_info.ft_info.reassoc_ft_ie,
+		     MAX_FTIE_SIZE);
+	mlme_priv->connect_info.ft_info.reassoc_ie_len = 0;
+
+	if (wlan_get_ie_ptr_from_eid(MD_IE_ID, rsp->ft_ie, rsp->ft_ie_length))
+		mlme_priv->connect_info.ft_info.add_mdie = true;
+
+	if (!mlme_priv->connect_info.ft_info.ric_ies_length)
+		return;
+
+	/* Copy the RIC IEs to reassoc IEs */
+	qdf_mem_copy(mlme_priv->connect_info.ft_info.reassoc_ft_ie,
+		     mlme_priv->connect_info.ft_info.ric_ies,
+		     mlme_priv->connect_info.ft_info.ric_ies_length);
+	mlme_priv->connect_info.ft_info.reassoc_ie_len =
+			mlme_priv->connect_info.ft_info.ric_ies_length;
+	mlme_priv->connect_info.ft_info.add_mdie = true;
+		return;
+
+err:
+	rsp->status = QDF_STATUS_E_ABORTED;
+	status = cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_PREAUTH_RESP,
+					  sizeof(*rsp), rsp);
+	if (QDF_IS_STATUS_ERROR(status))
+		cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
+}
+
+static QDF_STATUS
+cm_hanlde_preauth_failure(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
+{
+	QDF_STATUS status;
+	struct wlan_cm_preauth_fail preauth_fail_rsp;
+
+	preauth_fail_rsp.cm_id = cm_id;
+	preauth_fail_rsp.reason = CM_GENERIC_FAILURE;
+
+	status = cm_sm_deliver_event_sync(
+			cm_ctx, WLAN_CM_SM_EV_PREAUTH_FAIL,
+			sizeof(struct wlan_cm_preauth_fail), &preauth_fail_rsp);
+	if (QDF_IS_STATUS_ERROR(status))
+		cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
+
+	return status;
+}
+
+void cm_preauth_done_resp(struct cnx_mgr *cm_ctx, struct wlan_preauth_rsp *rsp)
+{
+	QDF_STATUS status;
+	struct cm_req *cm_req;
+	wlan_cm_id cm_id = rsp->cm_id;
+
+	if (QDF_IS_STATUS_ERROR(rsp->status)) {
+		cm_req = cm_get_req_by_cm_id(cm_ctx, cm_id);
+		if (!cm_req)
+			return;
+
+		/* retry again with same or new candidate */
+		status = cm_host_roam_preauth_start(cm_ctx, cm_req);
+		if (QDF_IS_STATUS_ERROR(status))
+			cm_hanlde_preauth_failure(cm_ctx, cm_id);
+	} else {
+		status = cm_sm_deliver_event_sync(cm_ctx,
+						  WLAN_CM_SM_EV_PREAUTH_DONE,
+						  sizeof(*rsp), rsp);
+		if (QDF_IS_STATUS_ERROR(status))
+			cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
+	}
+}
+
+/**
+ * cm_remove_preauth_cmd_from_serialization() - Remove preauth cmd
+ * from serialization
+ * @cm_ctx: connection manager context
+ * @cm_id: cm id of roam req
+ *
+ * Return: void
+ */
+static void cm_remove_preauth_cmd_from_serialization(struct cnx_mgr *cm_ctx,
+						     wlan_cm_id cm_id)
+{
+	struct wlan_serialization_queued_cmd_info cmd_info;
+
+	qdf_mem_zero(&cmd_info, sizeof(cmd_info));
+	cmd_info.cmd_id = cm_id;
+	cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD;
+	cmd_info.cmd_type = WLAN_SER_CMD_PERFORM_PRE_AUTH;
+
+	mlme_debug(CM_PREFIX_FMT "Remove cmd type %d from active",
+		   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id),
+		   cmd_info.cmd_type);
+	cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE;
+	wlan_serialization_remove_cmd(&cmd_info);
+}
+
+static QDF_STATUS cm_preauth_rsp(struct wlan_objmgr_vdev *vdev,
+				 struct wlan_preauth_rsp *rsp)
+{
+	QDF_STATUS status;
+	struct cnx_mgr *cm_ctx;
+	wlan_cm_id cm_id;
+	uint32_t prefix;
+
+	cm_ctx = cm_get_cm_ctx(vdev);
+	if (!cm_ctx)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	cm_id = cm_ctx->active_cm_id;
+	prefix = CM_ID_GET_PREFIX(cm_id);
+
+	if (prefix != ROAM_REQ_PREFIX) {
+		mlme_err(CM_PREFIX_FMT "active req is not roam req",
+			 CM_PREFIX_REF(wlan_vdev_get_id(vdev), cm_id));
+		return QDF_STATUS_E_INVAL;
+	}
+	rsp->cm_id = cm_id;
+
+	cm_remove_preauth_cmd_from_serialization(cm_ctx, cm_id);
+
+	status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_PREAUTH_RESP,
+				     sizeof(*rsp), rsp);
+	if (QDF_IS_STATUS_ERROR(status))
+		cm_preauth_handle_event_post_fail(cm_ctx, cm_id);
+
+	return status;
+}
+
+QDF_STATUS cm_handle_preauth_rsp(struct scheduler_msg *msg)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct wlan_preauth_rsp *rsp = NULL;
+	struct wlan_objmgr_vdev *vdev;
+
+	if (!msg || !msg->bodyptr) {
+		status = QDF_STATUS_E_FAILURE;
+		goto end;
+	}
+
+	rsp = (struct wlan_preauth_rsp *)msg->bodyptr;
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(rsp->psoc, rsp->vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev) {
+		mlme_err("vdev_id: %d : vdev not found", rsp->vdev_id);
+		status = QDF_STATUS_E_INVAL;
+		goto end;
+	}
+
+	status = cm_preauth_rsp(vdev, rsp);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+end:
+	if (rsp)
+		qdf_mem_free(rsp);
+
+	return status;
+}

+ 122 - 0
components/umac/mlme/connection_mgr/core/src/wlan_cm_host_util.c

@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2021 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_cm_host_util.c
+ *
+ * Implements Host roam (LFR2) utils for connection manager
+ */
+
+#include "wlan_cm_roam_api.h"
+#include "connection_mgr/core/src/wlan_cm_roam.h"
+
+/*
+ * cm_copy_ssids_from_rso_config_params() - copy SSID from rso_config_params
+ * to scan filter
+ * @rso_usr_cfg: rso user config
+ * @filter: scan filter
+ *
+ * Return void
+ */
+static void
+cm_copy_ssids_from_rso_config_params(struct rso_config_params *rso_usr_cfg,
+				     struct scan_filter *filter)
+{
+	uint8_t i;
+	uint8_t max_ssid;
+
+	if (!rso_usr_cfg->num_ssid_allowed_list)
+		return;
+	max_ssid = QDF_MIN(WLAN_SCAN_FILTER_NUM_SSID, MAX_SSID_ALLOWED_LIST);
+
+	filter->num_of_ssid = rso_usr_cfg->num_ssid_allowed_list;
+	if (filter->num_of_ssid > max_ssid)
+		filter->num_of_ssid = max_ssid;
+	for  (i = 0; i < filter->num_of_ssid; i++)
+		qdf_mem_copy(&filter->ssid_list[i],
+			     &rso_usr_cfg->ssid_allowed_list[i],
+			     sizeof(struct wlan_ssid));
+}
+
+QDF_STATUS cm_update_advance_roam_scan_filter(
+		struct wlan_objmgr_vdev *vdev, struct scan_filter *filter)
+{
+	uint8_t num_ch = 0;
+	struct wlan_objmgr_psoc *psoc;
+	struct rso_config *rso_cfg;
+	struct rso_chan_info *chan_lst;
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+	struct rso_config_params *rso_usr_cfg;
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		mlme_debug("psoc is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	if (!mlme_obj)
+		return QDF_STATUS_E_FAILURE;
+
+	rso_usr_cfg = &mlme_obj->cfg.lfr.rso_user_config;
+
+	mlme_debug("No of Allowed SSID List:%d",
+		   rso_usr_cfg->num_ssid_allowed_list);
+
+	if (rso_usr_cfg->num_ssid_allowed_list) {
+		cm_copy_ssids_from_rso_config_params(rso_usr_cfg, filter);
+	} else {
+		filter->num_of_ssid = 1;
+		wlan_vdev_mlme_get_ssid(vdev, filter->ssid_list[0].ssid,
+					&filter->ssid_list[0].length);
+
+		mlme_debug("Filtering for SSID %.*s,length of SSID = %u",
+			   filter->ssid_list[0].length,
+			   filter->ssid_list[0].ssid,
+			   filter->ssid_list[0].length);
+	}
+
+	rso_cfg = wlan_cm_get_rso_config(vdev);
+	if (!rso_cfg)
+		return QDF_STATUS_E_FAILURE;
+
+	chan_lst = &rso_cfg->roam_scan_freq_lst;
+	num_ch = chan_lst->num_chan;
+	if (num_ch) {
+		filter->num_of_channels = num_ch;
+		if (filter->num_of_channels > NUM_CHANNELS)
+			filter->num_of_channels = NUM_CHANNELS;
+		qdf_mem_copy(filter->chan_freq_list, chan_lst->freq_list,
+			     filter->num_of_channels *
+			     sizeof(filter->chan_freq_list[0]));
+	}
+
+	if (rso_cfg->is_11r_assoc)
+		/*
+		 * MDIE should be added as a part of profile. This should be
+		 * added as a part of filter as well
+		 */
+		filter->mobility_domain = rso_cfg->mdid.mobility_domain;
+	filter->enable_adaptive_11r =
+		wlan_mlme_adaptive_11r_enabled(psoc);
+
+	if (rso_cfg->rsn_cap & WLAN_CRYPTO_RSN_CAP_MFP_REQUIRED)
+		filter->pmf_cap = WLAN_PMF_REQUIRED;
+	else if (rso_cfg->rsn_cap & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)
+		filter->pmf_cap = WLAN_PMF_CAPABLE;
+
+	return QDF_STATUS_SUCCESS;
+}

+ 24 - 1
components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_api.h

@@ -526,6 +526,16 @@ void cm_free_join_req(struct cm_vdev_join_req *join_req);
 QDF_STATUS cm_process_join_req(struct scheduler_msg *msg);
 
 #ifdef WLAN_FEATURE_HOST_ROAM
+/**
+ * cm_process_preauth_req() - Process preauth request
+ * @msg: scheduler message
+ *
+ * Process preauth request in LIM.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS cm_process_preauth_req(struct scheduler_msg *msg);
+
 /**
  * cm_process_reassoc_req() - Process vdev reassoc req
  * @msg: scheduler message
@@ -547,11 +557,25 @@ QDF_STATUS cm_process_reassoc_req(struct scheduler_msg *msg);
 QDF_STATUS
 cm_handle_reassoc_req(struct wlan_objmgr_vdev *vdev,
 		      struct wlan_cm_vdev_reassoc_req *req);
+
+/**
+ * cm_csr_preauth_done() - Process preauth done from csr part
+ * @vdev: vdev object pointer
+ *
+ * Return: void
+ */
+void cm_csr_preauth_done(struct wlan_objmgr_vdev *vdev);
 #else
+static inline QDF_STATUS cm_process_preauth_req(struct scheduler_msg *msg)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
 static inline QDF_STATUS cm_process_reassoc_req(struct scheduler_msg *msg)
 {
 	return QDF_STATUS_SUCCESS;
 }
+
 static inline QDF_STATUS
 cm_handle_reassoc_req(struct wlan_objmgr_vdev *vdev,
 		      struct wlan_cm_vdev_reassoc_req *req)
@@ -637,6 +661,5 @@ QDF_STATUS wlan_cm_send_connect_rsp(struct scheduler_msg *msg);
  * Return: void
  */
 void wlan_cm_free_connect_rsp(struct cm_vdev_join_rsp *rsp);
-
 #endif /* FEATURE_CM_ENABLE */
 #endif /* __WLAN_CM_VDEV_API_H__ */

+ 73 - 0
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h

@@ -636,6 +636,7 @@ void cm_roam_start_init_on_connect(struct wlan_objmgr_pdev *pdev,
 void cm_update_session_assoc_ie(struct wlan_objmgr_psoc *psoc,
 				uint8_t vdev_id,
 				struct element_info *assoc_ie);
+
 #ifdef FEATURE_CM_ENABLE
 /**
  * wlan_cm_roam_invoke() - Validate and send Roam invoke req to CM
@@ -652,6 +653,23 @@ wlan_cm_roam_invoke(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
 		    struct qdf_mac_addr *bssid, qdf_freq_t chan_freq,
 		    enum wlan_cm_source source);
 
+/**
+ * cm_is_fast_roam_enabled() - check fast roam enabled or not
+ * @psoc: psoc pointer
+ *
+ * Return: true or false
+ */
+bool cm_is_fast_roam_enabled(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * cm_is_rsn_or_8021x_sha256_auth_type() - check whether auth type is rsn
+ * or 8021x_sha256 or not
+ * @vdev: vdev object pointer
+ *
+ * Return: true, if auth type is rsn/8021x_sha256, false otherwise
+ */
+bool cm_is_rsn_or_8021x_sha256_auth_type(struct wlan_objmgr_vdev *vdev);
+
 #ifdef WLAN_FEATURE_HOST_ROAM
 /**
  * wlan_cm_host_roam_start() - fw host roam start handler
@@ -660,6 +678,61 @@ wlan_cm_roam_invoke(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
  * Return: QDF_STATUS
  */
 QDF_STATUS wlan_cm_host_roam_start(struct scheduler_msg *msg);
+
+/**
+ * cm_handle_roam_start() - roam start indication
+ * @vdev: VDEV object
+ * @req: Connection manager roam request
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+cm_handle_roam_start(struct wlan_objmgr_vdev *vdev,
+		     struct wlan_cm_roam_req *req);
+
+/**
+ * cm_mlme_roam_preauth_fail() - roam preauth fail
+ * @vdev: VDEV object
+ * @req: Connection manager roam request
+ * @reason: connection manager connect fail reason
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+cm_mlme_roam_preauth_fail(struct wlan_objmgr_vdev *vdev,
+			  struct wlan_cm_roam_req *req,
+			  enum wlan_cm_connect_fail_reason reason);
+
+/**
+ * cm_free_preauth_req() - free preauth request related memory
+ * @preauth_req: preauth request
+ *
+ * Return: void
+ */
+void cm_free_preauth_req(struct wlan_preauth_req *preauth_req);
+
+/**
+ * cm_handle_preauth_rsp() - Process vdev preauth rsp and send to CM
+ * @msg: scheduler message
+ *
+ * Process preauth rsp and send it to CM SM.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS cm_handle_preauth_rsp(struct scheduler_msg *msg);
+
+/**
+ * cm_reassoc_timer_callback() - reassoc timer callback, gets called at time out
+ * @context: context
+ *
+ * Timer callback for the timer that is started between the preauth completion
+ * and reassoc request. In this interval, it is expected that the
+ * pre-auth response and RIC IEs are passed up to the WPA supplicant and
+ * received back the necessary FTIEs required to be sent in the reassoc request
+ *
+ * Return: None
+ */
+void cm_reassoc_timer_callback(void *context);
 #else
 static inline QDF_STATUS wlan_cm_host_roam_start(struct scheduler_msg *msg)
 {

+ 25 - 0
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h

@@ -113,7 +113,12 @@
 #define MAX_BSSID_AVOID_LIST     16
 #define MAX_BSSID_FAVORED      16
 
+#if defined(FEATURE_CM_ENABLE) && defined(WLAN_FEATURE_HOST_ROAM)
+#define MAX_FTIE_SIZE CM_MAX_FTIE_SIZE
+#else
 #define MAX_FTIE_SIZE 384
+#endif
+
 #define ESE_MAX_TSPEC_IES 4
 
 /*
@@ -262,9 +267,25 @@ enum roam_fail_params {
 	ROAM_FAIL_REASON,
 };
 
+#if defined(FEATURE_CM_ENABLE) && defined(WLAN_FEATURE_HOST_ROAM)
+/**
+ * srtuct reassoc_timer_ctx - reassoc timer context
+ * @pdev: pdev object pointer
+ * @vdev_id: vdev id
+ * @cm_id: cm id to find cm_roam_req
+ */
+struct reassoc_timer_ctx {
+	struct wlan_objmgr_pdev *pdev;
+	uint8_t vdev_id;
+	wlan_cm_id cm_id;
+};
+#endif
+
 /**
  * struct rso_config - connect config to be used to send info in
  * RSO. This is the info we dont have in VDEV or CM ctx
+ * @reassoc_timer: reassoc timer
+ * @ctx: reassoc timer context
  * @cm_rso_lock: RSO lock
  * @rsn_cap: original rsn caps from the connect req from supplicant
  * @disable_hi_rssi: disable high rssi
@@ -309,6 +330,10 @@ enum roam_fail_params {
  * @lost_link_rssi: lost link RSSI
  */
 struct rso_config {
+#if defined(FEATURE_CM_ENABLE) && defined(WLAN_FEATURE_HOST_ROAM)
+	qdf_mc_timer_t reassoc_timer;
+	struct reassoc_timer_ctx ctx;
+#endif
 	qdf_mutex_t cm_rso_lock;
 	uint8_t rsn_cap;
 	bool disable_hi_rssi;

+ 123 - 7
components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c

@@ -1220,9 +1220,35 @@ static void cm_rso_chan_to_freq_list(struct wlan_objmgr_pdev *pdev,
 			wlan_reg_legacy_chan_to_freq(pdev, chan_list[count]);
 }
 
+#if defined(FEATURE_CM_ENABLE) && defined(WLAN_FEATURE_HOST_ROAM)
+static QDF_STATUS wlan_cm_init_reassoc_timer(struct rso_config *rso_cfg)
+{
+	QDF_STATUS status;
+
+	status = qdf_mc_timer_init(&rso_cfg->reassoc_timer, QDF_TIMER_TYPE_SW,
+				   cm_reassoc_timer_callback, &rso_cfg->ctx);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		mlme_err("Preauth Reassoc interval Timer allocation failed");
+
+	return status;
+}
+
+static void wlan_cm_deinit_reassoc_timer(struct rso_config *rso_cfg)
+{
+	/* check if the timer is running */
+	if (QDF_TIMER_STATE_RUNNING ==
+	    qdf_mc_timer_get_current_state(&rso_cfg->reassoc_timer))
+		qdf_mc_timer_stop(&rso_cfg->reassoc_timer);
+
+	qdf_mc_timer_destroy(&rso_cfg->reassoc_timer);
+}
+#endif
+
 QDF_STATUS wlan_cm_rso_config_init(struct wlan_objmgr_vdev *vdev,
 				   struct rso_config *rso_cfg)
 {
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	struct rso_chan_info *chan_info;
 	struct rso_cfg_params *cfg_params;
 	struct wlan_mlme_psoc_ext_obj *mlme_obj;
@@ -1241,6 +1267,14 @@ QDF_STATUS wlan_cm_rso_config_init(struct wlan_objmgr_vdev *vdev,
 	if (!mlme_obj)
 		return QDF_STATUS_E_INVAL;
 
+#ifdef FEATURE_CM_ENABLE
+#ifdef WLAN_FEATURE_HOST_ROAM
+	status = wlan_cm_init_reassoc_timer(rso_cfg);
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
+#endif
+	qdf_mutex_create(&rso_cfg->cm_rso_lock);
+#endif
 	cfg_params = &rso_cfg->cfg_param;
 	cfg_params->max_chan_scan_time =
 		mlme_obj->cfg.lfr.neighbor_scan_max_chan_time;
@@ -1317,10 +1351,8 @@ QDF_STATUS wlan_cm_rso_config_init(struct wlan_objmgr_vdev *vdev,
 		mlme_obj->cfg.lfr.roam_rssi_diff;
 	cfg_params->bg_rssi_threshold =
 		mlme_obj->cfg.lfr.bg_rssi_threshold;
-#ifdef FEATURE_CM_ENABLE
-	qdf_mutex_create(&rso_cfg->cm_rso_lock);
-#endif
-	return QDF_STATUS_SUCCESS;
+
+	return status;
 }
 
 void wlan_cm_rso_config_deinit(struct wlan_objmgr_vdev *vdev,
@@ -1328,9 +1360,6 @@ void wlan_cm_rso_config_deinit(struct wlan_objmgr_vdev *vdev,
 {
 	struct rso_cfg_params *cfg_params;
 
-#ifdef FEATURE_CM_ENABLE
-	qdf_mutex_destroy(&rso_cfg->cm_rso_lock);
-#endif
 	cfg_params = &rso_cfg->cfg_param;
 	if (rso_cfg->assoc_ie.ptr) {
 		qdf_mem_free(rso_cfg->assoc_ie.ptr);
@@ -1349,6 +1378,14 @@ void wlan_cm_rso_config_deinit(struct wlan_objmgr_vdev *vdev,
 
 	cm_flush_roam_channel_list(&cfg_params->specific_chan_info);
 	cm_flush_roam_channel_list(&cfg_params->pref_chan_info);
+
+#ifdef FEATURE_CM_ENABLE
+	qdf_mutex_destroy(&rso_cfg->cm_rso_lock);
+#ifdef WLAN_FEATURE_HOST_ROAM
+	wlan_cm_deinit_reassoc_timer(rso_cfg);
+#endif
+#endif
+
 }
 
 #ifdef FEATURE_CM_ENABLE
@@ -1420,6 +1457,38 @@ wlan_cm_roam_invoke(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
 	return status;
 }
 
+bool cm_is_fast_roam_enabled(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	if (!mlme_obj)
+		return false;
+
+	if (!mlme_obj->cfg.lfr.lfr_enabled)
+		return false;
+
+	if (mlme_obj->cfg.lfr.enable_fast_roam_in_concurrency)
+		return true;
+	/* return true if no concurency */
+	if (policy_mgr_get_connection_count(psoc) < 2)
+		return true;
+
+	return false;
+}
+
+bool cm_is_rsn_or_8021x_sha256_auth_type(struct wlan_objmgr_vdev *vdev)
+{
+	int32_t akm;
+
+	akm = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT);
+	if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256) ||
+	    QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X))
+		return true;
+
+	return false;
+}
+
 #ifdef WLAN_FEATURE_HOST_ROAM
 QDF_STATUS wlan_cm_host_roam_start(struct scheduler_msg *msg)
 {
@@ -1433,6 +1502,53 @@ QDF_STATUS wlan_cm_host_roam_start(struct scheduler_msg *msg)
 	return wlan_cm_roam_invoke(req->pdev, req->vdev_id, &bssid, 0,
 				   CM_ROAMING_FW);
 }
+
+QDF_STATUS cm_handle_roam_start(struct wlan_objmgr_vdev *vdev,
+				struct wlan_cm_roam_req *req)
+{
+	if (!vdev || !req) {
+		mlme_err("vdev or req is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (req->source == CM_ROAMING_HOST)
+		cm_roam_state_change(wlan_vdev_get_pdev(vdev),
+				     wlan_vdev_get_id(vdev),
+				     WLAN_ROAM_RSO_STOPPED,
+				     REASON_OS_REQUESTED_ROAMING_NOW);
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS cm_mlme_roam_preauth_fail(struct wlan_objmgr_vdev *vdev,
+				     struct wlan_cm_roam_req *req,
+				     enum wlan_cm_connect_fail_reason reason)
+{
+	uint8_t vdev_id, roam_reason;
+	struct wlan_objmgr_pdev *pdev;
+
+	if (!vdev || !req) {
+		mlme_err("vdev or req is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (reason == CM_NO_CANDIDATE_FOUND)
+		roam_reason = REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW;
+	else
+		roam_reason = REASON_PREAUTH_FAILED_FOR_ALL;
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	vdev_id = wlan_vdev_get_id(vdev);
+
+	if (req->source == CM_ROAMING_FW)
+		cm_roam_state_change(pdev, vdev_id,
+				     ROAM_SCAN_OFFLOAD_RESTART,
+				     roam_reason);
+	else
+		cm_roam_state_change(pdev, vdev_id,
+				     ROAM_SCAN_OFFLOAD_START,
+				     roam_reason);
+	return QDF_STATUS_SUCCESS;
+}
 #endif
 
 #else

+ 6 - 0
core/hdd/src/wlan_hdd_assoc.c

@@ -5211,6 +5211,12 @@ struct osif_cm_ops osif_ops = {
 #ifdef WLAN_FEATURE_FILS_SK
 	.set_hlp_data_cb = hdd_cm_set_hlp_data,
 #endif
+#ifdef WLAN_FEATURE_PREAUTH_ENABLE
+	.ft_preauth_complete_cb = hdd_cm_ft_preauth_complete,
+#ifdef FEATURE_WLAN_ESE
+	.cckm_preauth_complete_cb = hdd_cm_cckm_preauth_complete,
+#endif
+#endif
 };
 
 QDF_STATUS hdd_cm_register_cb(void)

+ 30 - 0
core/hdd/src/wlan_hdd_cm_api.h

@@ -120,6 +120,36 @@ QDF_STATUS hdd_cm_set_hlp_data(struct net_device *dev,
 			       struct wlan_objmgr_vdev *vdev,
 			       struct wlan_cm_connect_resp *rsp);
 #endif
+
+#ifdef WLAN_FEATURE_PREAUTH_ENABLE
+/**
+ * hdd_cm_ft_preauth_complete() - send fast transition event
+ * @vdev: Pointer to vdev
+ * @rsp: Pointer to preauth rsp
+ *
+ * This function is used to send fast transition event in legacy mode
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hdd_cm_ft_preauth_complete(struct wlan_objmgr_vdev *vdev,
+				      struct wlan_preauth_rsp *rsp);
+
+#ifdef FEATURE_WLAN_ESE
+/**
+ * hdd_cm_cckm_preauth_complete() - send cckm preauth indication to
+ * the supplicant via wireless custom event
+ * @vdev: Pointer to vdev
+ * @rsp: Pointer to preauth rsp
+ *
+ * This function is used to send cckm preauth indication to
+ * the supplicant via wireless custom event in legacy mode
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hdd_cm_cckm_preauth_complete(struct wlan_objmgr_vdev *vdev,
+					struct wlan_preauth_rsp *rsp);
+#endif
+#endif
 #endif
 
 #ifdef WLAN_FEATURE_MSCS

+ 234 - 0
core/hdd/src/wlan_hdd_cm_connect.c

@@ -42,6 +42,7 @@
 #include "sme_qos_internal.h"
 #include "wlan_blm_ucfg_api.h"
 #include "wlan_hdd_scan.h"
+#include "wlan_osif_priv.h"
 #include <enet.h>
 #include <wlan_mlme_twt_ucfg_api.h>
 #include "wlan_roam_debug.h"
@@ -1241,4 +1242,237 @@ QDF_STATUS hdd_cm_set_hlp_data(struct net_device *dev,
 	return QDF_STATUS_SUCCESS;
 }
 #endif
+
+#ifdef WLAN_FEATURE_PREAUTH_ENABLE
+/**
+ * hdd_cm_get_ft_preauth_response() - get ft preauth response
+ * related information
+ * @vdev: vdev pointer
+ * @rsp: preauth response
+ * @ft_ie: ft ie
+ * @ft_ie_ip_len: ft ie ip length
+ * @ft_ie_length: ft ies length
+ *
+ * This function is used to get ft ie related information
+ *
+ * Return: none
+ */
+static void
+hdd_cm_get_ft_preauth_response(struct wlan_objmgr_vdev *vdev,
+			       struct wlan_preauth_rsp *rsp, uint8_t *ft_ie,
+			       uint32_t ft_ie_ip_len, uint16_t *ft_ie_length)
+{
+	struct mlme_legacy_priv *mlme_priv;
+
+	*ft_ie_length = 0;
+
+	if (!vdev)
+		return;
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv)
+		return;
+
+	/* All or nothing - proceed only if both BSSID and FT IE fit */
+	if ((QDF_MAC_ADDR_SIZE + rsp->ft_ie_length) > ft_ie_ip_len)
+		return;
+	/*
+	 * hdd needs to pack the bssid also along with the
+	 * auth response to supplicant
+	 */
+	qdf_mem_copy(ft_ie, rsp->pre_auth_bssid.bytes, QDF_MAC_ADDR_SIZE);
+
+	/* Copy the auth resp FTIEs */
+	qdf_mem_copy(&ft_ie[QDF_MAC_ADDR_SIZE],
+		     rsp->ft_ie, rsp->ft_ie_length);
+
+	*ft_ie_length = QDF_MAC_ADDR_SIZE + rsp->ft_ie_length;
+
+	hdd_debug("Filled auth resp: %d", *ft_ie_length);
+}
+
+#if defined(KERNEL_SUPPORT_11R_CFG80211)
+QDF_STATUS hdd_cm_ft_preauth_complete(struct wlan_objmgr_vdev *vdev,
+				      struct wlan_preauth_rsp *rsp)
+{
+	mac_handle_t mac_handle;
+	struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev);
+	struct wireless_dev *wdev;
+	uint16_t auth_resp_len = 0;
+	uint32_t ric_ies_length = 0;
+	struct cfg80211_ft_event_params ft_event;
+	uint8_t ft_ie[DOT11F_IE_FTINFO_MAX_LEN];
+	uint8_t ric_ies[DOT11F_IE_RICDESCRIPTOR_MAX_LEN];
+
+	mac_handle = cds_get_context(QDF_MODULE_ID_SME);
+	if (!mac_handle) {
+		hdd_err("mac_handle is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!osif_priv) {
+		hdd_err("Invalid vdev osif priv");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wdev = osif_priv->wdev;
+	if (!wdev) {
+		hdd_err("wdev is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	qdf_mem_zero(ft_ie, DOT11F_IE_FTINFO_MAX_LEN);
+	qdf_mem_zero(ric_ies, DOT11F_IE_RICDESCRIPTOR_MAX_LEN);
+
+	if (rsp->ric_ies_length &&
+	    rsp->ric_ies_length <= DOT11F_IE_RICDESCRIPTOR_MAX_LEN) {
+		qdf_mem_copy(ric_ies, rsp->ric_ies, rsp->ric_ies_length);
+		ric_ies_length = rsp->ric_ies_length;
+	} else {
+		hdd_warn("Do not send RIC IEs as length is 0");
+	}
+
+	ft_event.ric_ies = ric_ies;
+	ft_event.ric_ies_len = ric_ies_length;
+	hdd_debug("RIC IEs is of length %d", ric_ies_length);
+
+	hdd_cm_get_ft_preauth_response(vdev, rsp, ft_ie,
+				       DOT11F_IE_FTINFO_MAX_LEN,
+				       &auth_resp_len);
+	if (!auth_resp_len) {
+		hdd_debug("AuthRsp FTIES is of length 0");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	sme_set_ft_pre_auth_state(mac_handle, wlan_vdev_get_id(vdev), true);
+
+	ft_event.target_ap = ft_ie;
+	ft_event.ies = (u8 *)(ft_ie + QDF_MAC_ADDR_SIZE);
+	ft_event.ies_len = auth_resp_len - QDF_MAC_ADDR_SIZE;
+
+	hdd_debug("ftEvent.ies_len %zu", ft_event.ies_len);
+	hdd_debug("ftEvent.ric_ies_len %zu", ft_event.ric_ies_len);
+	hdd_debug("ftEvent.target_ap %2x-%2x-%2x-%2x-%2x-%2x",
+		  ft_event.target_ap[0], ft_event.target_ap[1],
+		  ft_event.target_ap[2], ft_event.target_ap[3],
+		  ft_event.target_ap[4], ft_event.target_ap[5]);
+
+	(void)cfg80211_ft_event(wdev->netdev, &ft_event);
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+QDF_STATUS hdd_cm_ft_preauth_complete(struct wlan_objmgr_vdev *vdev,
+				      struct wlan_preauth_rsp *rsp)
+{
+	struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev);
+	struct wireless_dev *wdev;
+	uint16_t auth_resp_len = 0;
+	uint32_t ric_ies_length = 0;
+	char *buff;
+	union iwreq_data wrqu;
+	uint16_t str_len;
+
+	if (!osif_priv) {
+		hdd_err("Invalid vdev osif priv");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wdev = osif_priv->wdev;
+	if (!wdev) {
+		hdd_err("wdev is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* need to send the IEs to the supplicant */
+	buff = qdf_mem_malloc(IW_CUSTOM_MAX);
+	if (!buff)
+		return QDF_STATUS_E_NOMEM;
+
+	/* need to send the RIC IEs first */
+	str_len = strlcpy(buff, "RIC=", IW_CUSTOM_MAX);
+	if (rsp->ric_ies_length &&
+	    (rsp->ric_ies_length <= (IW_CUSTOM_MAX - str_len))) {
+		qdf_mem_copy(&buff[str_len], rsp->ric_ies,
+			     rsp->ric_ies_length);
+		ric_ies_length = rsp->ric_ies_length;
+		wrqu.data.length = str_len + ric_ies_length;
+		hdd_wext_send_event(wdev->netdev, IWEVCUSTOM, &wrqu, buff);
+	} else {
+		hdd_warn("Do not send RIC IEs as length is 0");
+	}
+
+	/* need to provide the Auth Resp */
+	qdf_mem_zero(buff, IW_CUSTOM_MAX);
+	str_len = strlcpy(buff, "AUTH=", IW_CUSTOM_MAX);
+	hdd_cm_get_ft_preauth_response(vdev, rsp, &buff[str_len],
+				       (IW_CUSTOM_MAX - str_len),
+				       &auth_resp_len);
+	if (!auth_resp_len) {
+		qdf_mem_free(buff);
+		hdd_debug("AuthRsp FTIES is of length 0");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	wrqu.data.length = str_len + auth_resp_len;
+	hdd_wext_send_event(wdev->netdev, IWEVCUSTOM, &wrqu, buff);
+
+	qdf_mem_free(buff);
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
+#ifdef FEATURE_WLAN_ESE
+QDF_STATUS hdd_cm_cckm_preauth_complete(struct wlan_objmgr_vdev *vdev,
+					struct wlan_preauth_rsp *rsp)
+{
+	struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev);
+	struct wireless_dev *wdev;
+	union iwreq_data wrqu;
+	char buf[IW_CUSTOM_MAX + 1];
+	char *pos = buf;
+	int nbytes = 0, freebytes = IW_CUSTOM_MAX;
+
+	if (!osif_priv) {
+		hdd_err("Invalid vdev osif priv");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wdev = osif_priv->wdev;
+	if (!wdev) {
+		hdd_err("wdev is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* create the event */
+	memset(&wrqu, '\0', sizeof(wrqu));
+	memset(buf, '\0', sizeof(buf));
+
+	/* timestamp0 is lower 32 bits and timestamp1 is upper 32 bits */
+	hdd_debug("CCXPREAUTHNOTIFY=" QDF_MAC_ADDR_FMT " %d:%d",
+		  QDF_MAC_ADDR_REF(rsp->pre_auth_bssid.bytes),
+		  rsp->timestamp[0], rsp->timestamp[1]);
+
+	nbytes = snprintf(pos, freebytes, "CCXPREAUTHNOTIFY=");
+	pos += nbytes;
+	freebytes -= nbytes;
+
+	qdf_mem_copy(pos, rsp->pre_auth_bssid.bytes, QDF_MAC_ADDR_SIZE);
+	pos += QDF_MAC_ADDR_SIZE;
+	freebytes -= QDF_MAC_ADDR_SIZE;
+
+	nbytes = snprintf(pos, freebytes, " %u:%u",
+			  rsp->timestamp[0], rsp->timestamp[1]);
+	freebytes -= nbytes;
+
+	wrqu.data.pointer = buf;
+	wrqu.data.length = (IW_CUSTOM_MAX - freebytes);
+
+	/* send the event */
+	hdd_wext_send_event(wdev->netdev, IWEVCUSTOM, &wrqu, buf);
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif /* FEATURE_WLAN_ESE */
+#endif /* WLAN_FEATURE_PREAUTH_ENABLE */
 #endif

+ 2 - 1
core/mac/inc/wni_api.h

@@ -254,7 +254,8 @@ enum eWniMsgTypes {
 	CM_CONNECT_REQ = SIR_SME_MSG_TYPES_BEGIN + 172,
 	CM_DISCONNECT_REQ = SIR_SME_MSG_TYPES_BEGIN + 173,
 	CM_REASSOC_REQ = SIR_SME_MSG_TYPES_BEGIN + 174,
-	eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 175
+	CM_PREAUTH_REQ = SIR_SME_MSG_TYPES_BEGIN + 175,
+	eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 176
 };
 
 typedef struct sAniCfgTxRateCtrs {

+ 6 - 6
core/mac/src/pe/include/lim_ft.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -38,8 +38,8 @@ void lim_ft_cleanup(struct mac_context *mac, struct pe_session *pe_session);
 #ifdef WLAN_FEATURE_HOST_ROAM
 void lim_ft_cleanup_pre_auth_info(struct mac_context *mac,
 		struct pe_session *pe_session);
-int lim_process_ft_pre_auth_req(struct mac_context *mac,
-				struct scheduler_msg *pMsg);
+bool lim_process_ft_pre_auth_req(struct mac_context *mac,
+				 tpSirFTPreAuthReq ft_pre_auth_req);
 void lim_process_ft_preauth_rsp_timeout(struct mac_context *mac);
 
 /**
@@ -128,10 +128,10 @@ static inline void lim_preauth_scan_event_handler(struct mac_context *mac_ctx,
 		enum sir_scan_event_type event,
 		uint8_t vdev_id, uint32_t scan_id)
 {}
-static inline int lim_process_ft_pre_auth_req(struct mac_context *mac,
-		struct scheduler_msg *pMsg)
+static inline bool lim_process_ft_pre_auth_req(
+		struct mac_context *mac, tpSirFTPreAuthReq ft_pre_auth_req)
 {
-	return 0;
+	return false;
 }
 #endif
 

+ 73 - 6
core/mac/src/pe/lim/lim_ft_preauth.c

@@ -114,7 +114,7 @@ void lim_ft_cleanup_pre_auth_info(struct mac_context *mac,
  * lim_process_ft_pre_auth_req() - process ft pre auth req
  *
  * @mac_ctx:    global mac ctx
- * @msg:        pointer to message
+ * @ft_pre_auth_req:  ft preauth request
  *
  * In this function, we process the FT Pre Auth Req:
  *   We receive Pre-Auth, suspend link, register a call back. In the call back,
@@ -124,13 +124,12 @@ void lim_ft_cleanup_pre_auth_info(struct mac_context *mac,
  *
  * Return: value to indicate if buffer was consumed
  */
-int lim_process_ft_pre_auth_req(struct mac_context *mac_ctx,
-				struct scheduler_msg *msg)
+bool lim_process_ft_pre_auth_req(struct mac_context *mac_ctx,
+				 tpSirFTPreAuthReq ft_pre_auth_req)
 {
-	int buf_consumed = false;
+	bool buf_consumed = false;
 	struct pe_session *session;
 	uint8_t session_id;
-	tpSirFTPreAuthReq ft_pre_auth_req = (tSirFTPreAuthReq *) msg->bodyptr;
 
 	if (!ft_pre_auth_req) {
 		pe_err("tSirFTPreAuthReq is NULL");
@@ -569,6 +568,74 @@ void lim_process_ft_preauth_rsp_timeout(struct mac_context *mac_ctx)
 	lim_handle_ft_pre_auth_rsp(mac_ctx, QDF_STATUS_E_FAILURE, NULL, 0, session);
 }
 
+#ifdef FEATURE_CM_ENABLE
+/*
+ * lim_cm_post_preauth_rsp() - post preauth response to osif.
+ *
+ * @mac_ctx:		global mac ctx
+ * @status:		status code to post in auth rsp
+ * @auth_rsp:		pointer to auth rsp FT ie
+ * @auth_rsp_length:	len of the IE field
+ * @session:	        pe session
+ *
+ * post preauth response to osif.
+ *
+ * Return: void
+ */
+static void
+lim_cm_post_preauth_rsp(struct mac_context *mac_ctx, QDF_STATUS status,
+			uint8_t *auth_rsp, uint16_t auth_rsp_length,
+			struct pe_session *session)
+{
+	QDF_STATUS qdf_status;
+	struct scheduler_msg rsp_msg = {0};
+	struct wlan_preauth_rsp *rsp;
+
+	rsp = qdf_mem_malloc(sizeof(*rsp));
+	if (!rsp)
+		return;
+
+	rsp->psoc = mac_ctx->psoc;
+	if (session) {
+		/* Nothing to be done if the session is not in STA mode */
+		if (!LIM_IS_STA_ROLE(session)) {
+			pe_err("session is not in STA mode");
+			qdf_mem_free(rsp);
+			return;
+		}
+		rsp->vdev_id = session->vdev_id;
+		/* The bssid of the AP we are sending Auth1 to. */
+		if (session->ftPEContext.pFTPreAuthReq)
+			qdf_mem_copy(rsp->pre_auth_bssid.bytes,
+				     session->ftPEContext.
+						pFTPreAuthReq->preAuthbssId,
+				     QDF_MAC_ADDR_SIZE);
+	}
+	rsp->status = status;
+
+	/* Attach the auth response now back to osif */
+	rsp->ft_ie_length = 0;
+	if (auth_rsp && (auth_rsp_length < MAX_FTIE_SIZE)) {
+		/* Only 11r assoc has FT IEs */
+		qdf_mem_copy(rsp->ft_ie, auth_rsp, auth_rsp_length);
+		rsp->ft_ie_length = auth_rsp_length;
+	}
+
+	rsp_msg.bodyptr = rsp;
+	rsp_msg.callback = cm_handle_preauth_rsp;
+
+	qdf_status = scheduler_post_message(
+				QDF_MODULE_ID_PE, QDF_MODULE_ID_OS_IF,
+				QDF_MODULE_ID_OS_IF, &rsp_msg);
+
+	if (QDF_IS_STATUS_ERROR(qdf_status)) {
+		pe_err("Failed to post preauth rsp to sme vdev_id %d",
+		       rsp->vdev_id);
+		qdf_mem_free(rsp);
+	}
+}
+#endif
+
 /*
  * lim_post_ft_pre_auth_rsp() - post ft pre auth response to SME.
  *
@@ -656,7 +723,7 @@ void lim_post_ft_pre_auth_rsp(struct mac_context *mac_ctx,
 		lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_PREAUTH_DONE,
 				      session, status, 0);
 #endif
-	/* post msg to osif to cm */
+lim_cm_post_preauth_rsp(mac_ctx, status, auth_rsp, auth_rsp_length, session);
 #endif
 }
 

+ 3 - 0
core/mac/src/pe/lim/lim_process_message_queue.c

@@ -2112,6 +2112,9 @@ static void lim_process_messages(struct mac_context *mac_ctx,
 	case CM_DISCONNECT_REQ:
 		cm_process_disconnect_req(msg);
 		break;
+	case CM_PREAUTH_REQ:
+		cm_process_preauth_req(msg);
+		break;
 #endif
 	default:
 		qdf_mem_free((void *)msg->bodyptr);

+ 145 - 1
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -4224,7 +4224,150 @@ QDF_STATUS cm_process_reassoc_req(struct scheduler_msg *msg)
 
 	return QDF_STATUS_SUCCESS;
 }
+
+static QDF_STATUS
+lim_fill_preauth_req_dot11_mode(struct mac_context *mac_ctx,
+				tpSirFTPreAuthReq req)
+{
+	QDF_STATUS status;
+	tDot11fBeaconIEs *ie_struct;
+	enum mlme_dot11_mode self_dot11_mode;
+	enum mlme_dot11_mode bss_dot11_mode;
+	enum mlme_dot11_mode intersected_mode;
+	struct bss_description *bss_desc = req->pbssDescription;
+
+	wlan_get_parsed_bss_description_ies(mac_ctx, bss_desc, &ie_struct);
+	self_dot11_mode = lim_get_self_dot11_mode(mac_ctx, QDF_STA_MODE);
+	bss_dot11_mode = lim_get_bss_dot11_mode(bss_desc, ie_struct);
+
+	status = lim_get_intersected_dot11_mode_sta_ap(mac_ctx, self_dot11_mode,
+						       bss_dot11_mode,
+						       &intersected_mode,
+						       ie_struct, bss_desc);
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
+
+	req->dot11mode = intersected_mode;
+	pe_debug("self dot11mode %d bss_dot11 mode %d intersected_mode %d",
+		 self_dot11_mode, bss_dot11_mode, intersected_mode);
+
+	qdf_mem_free(ie_struct);
+	return status;
+}
+
+static QDF_STATUS lim_cm_handle_preauth_req(struct wlan_preauth_req *req)
+{
+	struct mac_context *mac_ctx;
+	struct wlan_objmgr_vdev *vdev;
+	struct scan_cache_entry *scan_entry;
+	struct bss_description *bss_desc = NULL;
+	uint32_t ie_len, bss_len;
+	uint8_t vdev_id;
+	struct mlme_legacy_priv *mlme_priv;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	tpSirFTPreAuthReq preauth_req = NULL;
+	bool buf_consumed = true;
+
+	if (!req)
+		return QDF_STATUS_E_INVAL;
+
+	mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
+	if (!mac_ctx)
+		return QDF_STATUS_E_INVAL;
+
+	ie_len = util_scan_entry_ie_len(req->entry);
+	bss_len = (uint16_t)(offsetof(struct bss_description,
+			   ieFields[0]) + ie_len);
+
+	bss_desc = qdf_mem_malloc(sizeof(*bss_desc) + bss_len);
+	if (!bss_desc) {
+		status = QDF_STATUS_E_NOMEM;
+		goto end;
+	}
+
+	scan_entry = req->entry;
+	status = wlan_fill_bss_desc_from_scan_entry(mac_ctx, bss_desc,
+						    scan_entry);
+	if (QDF_IS_STATUS_ERROR(status))
+		goto end;
+
+	preauth_req = qdf_mem_malloc(sizeof(tSirFTPreAuthReq));
+	if (!preauth_req) {
+		status = QDF_STATUS_E_NOMEM;
+		goto end;
+	}
+
+	preauth_req->pbssDescription = bss_desc;
+	status = lim_fill_preauth_req_dot11_mode(mac_ctx, preauth_req);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("dot11mode doesn't get proper filling");
+		goto end;
+	}
+
+	vdev_id = req->vdev_id;
+	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev, vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev) {
+		status = QDF_STATUS_E_FAILURE;
+		goto end;
+	}
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		status =  QDF_STATUS_E_FAILURE;
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+		goto end;
+	}
+	qdf_mem_copy(preauth_req->ft_ies,
+		     mlme_priv->connect_info.ft_info.auth_ft_ie,
+		     mlme_priv->connect_info.ft_info.auth_ie_len);
+	preauth_req->ft_ies_length =
+			mlme_priv->connect_info.ft_info.auth_ie_len;
+	preauth_req->pre_auth_channel_freq = scan_entry->channel.chan_freq;
+	wlan_mlme_get_bssid_vdev_id(
+			mac_ctx->pdev, vdev_id,
+			(struct qdf_mac_addr *)&preauth_req->currbssId);
+	qdf_mem_copy(&preauth_req->preAuthbssId,
+		     scan_entry->bssid.bytes, QDF_MAC_ADDR_SIZE);
+
+	wlan_vdev_obj_lock(vdev);
+	qdf_mem_copy(&preauth_req->self_mac_addr,
+		     wlan_vdev_mlme_get_macaddr(vdev), QDF_MAC_ADDR_SIZE);
+	wlan_vdev_obj_unlock(vdev);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+
+	buf_consumed = lim_process_ft_pre_auth_req(mac_ctx, preauth_req);
+
+end:
+	if (buf_consumed) {
+		if (bss_desc)
+			qdf_mem_free(bss_desc);
+		if (preauth_req)
+			qdf_mem_free(preauth_req);
+	}
+
+	return status;
+}
+
+QDF_STATUS cm_process_preauth_req(struct scheduler_msg *msg)
+{
+	struct wlan_preauth_req *req;
+	QDF_STATUS status;
+
+	if (!msg || !msg->bodyptr) {
+		mlme_err("msg or msg->bodyptr is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	req = msg->bodyptr;
+
+	status = lim_cm_handle_preauth_req(req);
+
+	cm_free_preauth_req(req);
+	return status;
+}
 #endif
+
 #else
 
 /**
@@ -7877,7 +8020,8 @@ bool lim_process_sme_req_messages(struct mac_context *mac,
 
 #ifndef FEATURE_CM_ENABLE
 	case eWNI_SME_FT_PRE_AUTH_REQ:
-		bufConsumed = (bool) lim_process_ft_pre_auth_req(mac, pMsg);
+		bufConsumed = lim_process_ft_pre_auth_req(
+					mac, (tpSirFTPreAuthReq)pMsg->bodyptr);
 		break;
 #else
 	/* handle new command */

+ 40 - 0
core/sme/src/csr/csr_api_roam.c

@@ -1624,6 +1624,18 @@ QDF_STATUS csr_get_tsm_stats(struct mac_context *mac,
 }
 
 #ifndef FEATURE_CM_ENABLE
+
+/*  Update the TSF with the difference in system time */
+static void update_cckmtsf(uint32_t *timestamp0, uint32_t *timestamp1,
+			   uint64_t *incr)
+{
+	uint64_t timestamp64 = ((uint64_t)*timestamp1 << 32) | (*timestamp0);
+
+	timestamp64 = (uint64_t)(timestamp64 + (*incr));
+	*timestamp0 = (uint32_t)(timestamp64 & 0xffffffff);
+	*timestamp1 = (uint32_t)((timestamp64 >> 32) & 0xffffffff);
+}
+
 /**
  * csr_roam_read_tsf() - read TSF
  * @mac: Global MAC context
@@ -12877,6 +12889,34 @@ cm_csr_diconnect_done_ind(struct wlan_objmgr_vdev *vdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef WLAN_FEATURE_HOST_ROAM
+void cm_csr_preauth_done(struct wlan_objmgr_vdev *vdev)
+{
+	struct mac_context *mac_ctx;
+	uint8_t vdev_id = wlan_vdev_get_id(vdev);
+	struct cm_roam_values_copy config;
+	bool is_11r;
+
+	/*
+	 * This API is to update legacy struct and should be removed once
+	 * CSR is cleaned up fully. No new params should be added to CSR, use
+	 * vdev/pdev/psoc instead
+	 */
+	mac_ctx = cds_get_context(QDF_MODULE_ID_SME);
+	if (!mac_ctx) {
+		sme_err("mac_ctx is NULL");
+		return;
+	}
+
+	wlan_cm_roam_cfg_get_value(mac_ctx->psoc, vdev_id, IS_11R_CONNECTION,
+				   &config);
+	is_11r = config.bool_value;
+	if (is_11r || wlan_cm_get_ese_assoc(mac_ctx->pdev, vdev_id))
+		sme_qos_csr_event_ind(mac_ctx, vdev_id,
+				      SME_QOS_CSR_PREAUTH_SUCCESS_IND, NULL);
+}
+#endif
+
 #else /* FEATURE_CM_ENABLE */
 
 #ifdef WLAN_FEATURE_FILS_SK

+ 0 - 15
core/sme/src/csr/csr_api_scan.c

@@ -1460,22 +1460,7 @@ free_mem:
 
 	return status;
 }
-#endif
-
-#ifdef FEATURE_WLAN_ESE
-/*  Update the TSF with the difference in system time */
-void update_cckmtsf(uint32_t *timeStamp0, uint32_t *timeStamp1,
-		    uint64_t *incr)
-{
-	uint64_t timeStamp64 = ((uint64_t) *timeStamp1 << 32) | (*timeStamp0);
 
-	timeStamp64 = (uint64_t)(timeStamp64 + (*incr));
-	*timeStamp0 = (uint32_t) (timeStamp64 & 0xffffffff);
-	*timeStamp1 = (uint32_t) ((timeStamp64 >> 32) & 0xffffffff);
-}
-#endif
-
-#ifndef FEATURE_CM_ENABLE
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
 QDF_STATUS
 csr_rso_save_ap_to_scan_cache(struct mac_context *mac,

+ 0 - 2
core/sme/src/csr/csr_inside_api.h

@@ -795,8 +795,6 @@ void csr_roam_ft_pre_auth_rsp_processor(struct mac_context *mac_ctx,
 #endif
 
 #ifdef FEATURE_WLAN_ESE
-void update_cckmtsf(uint32_t *timeStamp0, uint32_t *timeStamp1,
-		    uint64_t *incr);
 void csr_update_prev_ap_info(struct csr_roam_session *session,
 			     struct wlan_objmgr_vdev *vdev);