瀏覽代碼

qcacmn: Support roaming request to connection manager

Add change to support roaming request to connection manager.

Change-Id: I7f580e042522a245fc6a263d0e8f8b32b2f693f7
CRs-Fixed: 2845076
Santosh Anbu 4 年之前
父節點
當前提交
45a300ce7b

+ 3 - 1
os_if/linux/mlme/inc/osif_cm_req.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015, 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015,2020-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
@@ -44,12 +44,14 @@
  *           0 = hunting-and-pecking loop only
  *           1 = hash-to-element only
  *           2 = both hunting-and-pecking loop and hash-to-element enabled
+ * @prev_bssid: Previous bssid in case of roam scenario
  */
 struct osif_connect_params {
 	struct element_info scan_ie;
 	bool force_rsne_override;
 	enum dot11_mode_filter dot11mode_filter;
 	uint8_t sae_pwe;
+	struct qdf_mac_addr prev_bssid;
 };
 
 /**

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

@@ -183,6 +183,22 @@ typedef QDF_STATUS (*osif_cm_set_hlp_data_cb)(struct net_device *dev,
 					      struct wlan_cm_connect_resp *rsp);
 #endif
 
+/**
+ * typedef osif_cm_reassoc_comp_cb  - Reassoc complete callback
+ * @vdev: vdev pointer
+ * @rsp: Reassoc response
+ * @type: indicates update type
+ *
+ * This callback indicates reassoc complete to the legacy module
+ *
+ * Context: Any context.
+ * Return: QDF_STATUS
+ */
+typedef QDF_STATUS
+	(*osif_cm_reassoc_comp_cb)(struct wlan_objmgr_vdev *vdev,
+				   struct wlan_cm_roam_resp *rsp,
+				   enum osif_cb_type type);
+
 /**
  * typedef  osif_cm_disconnect_comp_cb: Disonnect complete callback
  * @vdev: vdev pointer
@@ -249,12 +265,15 @@ void osif_cm_unlink_bss(struct wlan_objmgr_vdev *vdev,
  * modules
  *  osif_cm_disconnect_comp_cb: callback for disconnect complete to
  * legacy modules
+ * osif_cm_reassoc_comp_cb: callback for reassoc complete to legacy
+ * modules
  * osif_cm_netif_queue_ctrl_cb: callback to legacy module to take
  * actions on netif queue
  */
 struct osif_cm_ops {
 	osif_cm_connect_comp_cb connect_complete_cb;
 	osif_cm_disconnect_comp_cb disconnect_complete_cb;
+	osif_cm_reassoc_comp_cb reassoc_complete_cb;
 #ifdef CONN_MGR_ADV_FEATURE
 	osif_cm_netif_queue_ctrl_cb netif_queue_control_cb;
 #endif
@@ -280,6 +299,22 @@ QDF_STATUS osif_cm_connect_comp_ind(struct wlan_objmgr_vdev *vdev,
 				    struct wlan_cm_connect_resp *rsp,
 				    enum osif_cb_type type);
 
+/**
+ * osif_cm_reassoc_comp_ind() - Function to indicate reassoc
+ * complete to legacy module
+ * @vdev: vdev pointer
+ * @rsp: Roam response
+ * @type: indicates update type
+ *
+ * This function indicates connect complete to the legacy module
+ *
+ * Context: Any context.
+ * Return: QDF_STATUS
+ */
+QDF_STATUS osif_cm_reassoc_comp_ind(struct wlan_objmgr_vdev *vdev,
+				    struct wlan_cm_roam_resp *rsp,
+				    enum osif_cb_type type);
+
 /**
  * osif_cm_disconnect_comp_ind() - Function to indicate disconnect
  * complete to legacy module

+ 5 - 1
os_if/linux/mlme/src/osif_cm_req.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015, 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015,2020-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
@@ -350,6 +350,10 @@ osif_cm_fill_connect_params(struct wlan_cm_connect_req *req,
 	req->dot11mode_filter = params->dot11mode_filter;
 	req->force_rsne_override = params->force_rsne_override;
 	req->sae_pwe = params->sae_pwe;
+
+	if (!qdf_is_macaddr_zero((struct qdf_mac_addr *)&params->prev_bssid))
+		qdf_copy_macaddr(&req->prev_bssid,
+				 (struct qdf_mac_addr *)&params->prev_bssid);
 }
 
 static void osif_cm_free_connect_req(struct wlan_cm_connect_req *connect_req)

+ 75 - 1
os_if/linux/mlme/src/osif_cm_roam_rsp.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015, 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015,2020-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
@@ -19,3 +19,77 @@
  *
  * This file maintains definitaions of roam response apis.
  */
+
+#include <linux/version.h>
+#include <linux/nl80211.h>
+#include <net/cfg80211.h>
+#include <wlan_osif_priv.h>
+#include "osif_cm_rsp.h"
+#include <osif_cm_util.h>
+#include <wlan_cfg80211.h>
+#include <wlan_cfg80211_scan.h>
+
+static QDF_STATUS
+osif_validate_reassoc_and_reset_src_id(struct vdev_osif_priv *osif_priv,
+				       wlan_cm_id cm_id)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	qdf_spinlock_acquire(&osif_priv->cm_info.cmd_id_lock);
+	if (cm_id != osif_priv->cm_info.last_id) {
+		osif_debug("Ignore as cm_id(%d) didn't match stored cm_id(%d)",
+			   cm_id, osif_priv->cm_info.last_id);
+		status = QDF_STATUS_E_INVAL;
+		goto rel_lock;
+	}
+	osif_cm_reset_id_and_src_no_lock(osif_priv);
+
+rel_lock:
+	qdf_spinlock_release(&osif_priv->cm_info.cmd_id_lock);
+
+	return status;
+}
+
+#ifdef CONN_MGR_ADV_FEATURE
+static void osif_indicate_reassoc_results(struct wlan_objmgr_vdev *vdev,
+					  struct vdev_osif_priv *osif_priv,
+					  struct wlan_cm_roam_resp *rsp)
+{
+	/*
+	 * To notify kernel on connection completion
+	 */
+}
+#else
+static void osif_indicate_reassoc_results(struct wlan_objmgr_vdev *vdev,
+					  struct vdev_osif_priv *osif_priv,
+					  struct wlan_cm_roam_resp *rsp)
+{}
+#endif
+
+QDF_STATUS osif_reassoc_handler(struct wlan_objmgr_vdev *vdev,
+				struct wlan_cm_roam_resp *rsp)
+{
+	struct vdev_osif_priv *osif_priv  = wlan_vdev_get_ospriv(vdev);
+	QDF_STATUS status;
+	enum wlan_cm_source source;
+
+	osif_nofl_info("%s(vdevid-%d): " QDF_MAC_ADDR_FMT " Roam with " QDF_MAC_ADDR_FMT " SSID \"%.*s\" is %s cm_id %d cm_reason %d status_code %d",
+		       osif_priv->wdev->netdev->name, rsp->vdev_id,
+		       QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)),
+		       QDF_MAC_ADDR_REF(rsp->bssid.bytes),
+		       rsp->ssid.length, rsp->ssid.ssid,
+		       rsp->reassoc_status ? "FAILURE" : "SUCCESS", rsp->cm_id,
+		       rsp->reason, rsp->status_code);
+	source = osif_priv->cm_info.last_source;
+	status = osif_validate_reassoc_and_reset_src_id(osif_priv, rsp->cm_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		osif_cm_reassoc_comp_ind(vdev, rsp, OSIF_NOT_HANDLED);
+		return status;
+	}
+
+	osif_cm_reassoc_comp_ind(vdev, rsp, OSIF_PRE_USERSPACE_UPDATE);
+	osif_indicate_reassoc_results(vdev, osif_priv, rsp);
+	osif_cm_reassoc_comp_ind(vdev, rsp, OSIF_POST_USERSPACE_UPDATE);
+
+	return QDF_STATUS_SUCCESS;
+}

+ 14 - 1
os_if/linux/mlme/src/osif_cm_rsp.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015, 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015,2020-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
@@ -56,6 +56,19 @@ QDF_STATUS osif_disconnect_handler(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS osif_connect_handler(struct wlan_objmgr_vdev *vdev,
 				struct wlan_cm_connect_resp *rsp);
 
+/**
+ * osif_reassoc_handler() - API to send reassoc response to kernel
+ * @vdev: vdev pointer
+ * @rsp: Connection manager reassoc response
+ *
+ * The API is used to send reassoc response to kernel
+ *
+ * Context: Any context.
+ * Return: QDF_STATUS
+ */
+QDF_STATUS osif_reassoc_handler(struct wlan_objmgr_vdev *vdev,
+				struct wlan_cm_roam_resp *rsp);
+
 /**
  * osif_failed_candidate_handler() - API to indicate individual candidate
  * connect failure resp

+ 30 - 0
os_if/linux/mlme/src/osif_cm_util.c

@@ -198,6 +198,20 @@ osif_cm_connect_complete_cb(struct wlan_objmgr_vdev *vdev,
 	return osif_connect_handler(vdev, rsp);
 }
 
+/**
+ * osif_cm_reassoc_complete_cb() - Reassoc complete callback
+ * @vdev: vdev pointer
+ * @rsp: Reassoc response
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+osif_cm_reassoc_complete_cb(struct wlan_objmgr_vdev *vdev,
+			    struct wlan_cm_roam_resp *rsp)
+{
+	return osif_reassoc_handler(vdev, rsp);
+}
+
 /**
  * osif_cm_failed_candidate_cb() - Callback to indicate failed candidate
  * @vdev: vdev pointer
@@ -315,6 +329,7 @@ static struct mlme_cm_ops cm_ops = {
 	.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,
+	.mlme_cm_reassoc_complete_cb = osif_cm_reassoc_complete_cb,
 };
 
 /**
@@ -384,6 +399,21 @@ QDF_STATUS osif_cm_connect_comp_ind(struct wlan_objmgr_vdev *vdev,
 	return ret;
 }
 
+QDF_STATUS osif_cm_reassoc_comp_ind(struct wlan_objmgr_vdev *vdev,
+				    struct wlan_cm_roam_resp *rsp,
+				    enum osif_cb_type type)
+{
+	osif_cm_reassoc_comp_cb cb = NULL;
+	QDF_STATUS ret = QDF_STATUS_SUCCESS;
+
+	if (osif_cm_legacy_ops)
+		cb = osif_cm_legacy_ops->reassoc_complete_cb;
+	if (cb)
+		ret = cb(vdev, rsp, type);
+
+	return ret;
+}
+
 QDF_STATUS osif_cm_disconnect_comp_ind(struct wlan_objmgr_vdev *vdev,
 				       struct wlan_cm_discon_rsp *rsp,
 				       enum osif_cb_type type)

+ 3 - 1
umac/cmn_services/serialization/inc/wlan_serialization_api.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-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
@@ -196,6 +196,7 @@ typedef QDF_STATUS (*wlan_ser_umac_cmd_cb)(void *umac_cmd);
  * @WLAN_SER_CMD_PDEV_RESTART: Cmd to restart all VDEVs of a PDEV
  * @WLAN_SER_CMD_PDEV_CSA_RESTART: Cmd to CSA restart all AP VDEVs of a PDEV
  * @WLAN_SER_CMD_GET_DISCONNECT_STATS: Cmd to get peer stats on disconnection
+ * @WLAN_SER_CMD_VDEV_REASSOC: Cmd to roam a STA VDEV
  */
 enum wlan_serialization_cmd_type {
 	/* all scan command before non-scan */
@@ -234,6 +235,7 @@ enum wlan_serialization_cmd_type {
 	WLAN_SER_CMD_PDEV_RESTART,
 	WLAN_SER_CMD_PDEV_CSA_RESTART,
 	WLAN_SER_CMD_GET_DISCONNECT_STATS,
+	WLAN_SER_CMD_VDEV_REASSOC,
 	WLAN_SER_CMD_MAX
 };
 

+ 1 - 47
umac/mlme/connection_mgr/core/src/wlan_cm_connect.c

@@ -19,7 +19,6 @@
  */
 
 #include "wlan_cm_main_api.h"
-#include "wlan_cm_bss_score_param.h"
 #include "wlan_scan_api.h"
 #include "wlan_cm_sm.h"
 #ifdef WLAN_POLICY_MGR_ENABLE
@@ -412,47 +411,7 @@ static QDF_STATUS cm_check_for_hw_mode_change(struct wlan_objmgr_psoc *psoc,
 						     connect_id);
 }
 
-static void
-cm_get_pcl_chan_weigtage_for_sta(struct wlan_objmgr_pdev *pdev,
-				 struct pcl_freq_weight_list *pcl_lst)
-{
-	enum QDF_OPMODE opmode = QDF_STA_MODE;
-	enum policy_mgr_con_mode pm_mode;
-	uint32_t num_entries = 0;
-	QDF_STATUS status;
-
-	if (!pcl_lst)
-		return;
-
-	if (policy_mgr_map_concurrency_mode(&opmode, &pm_mode)) {
-		status = policy_mgr_get_pcl(wlan_pdev_get_psoc(pdev), pm_mode,
-					    pcl_lst->pcl_freq_list,
-					    &num_entries,
-					    pcl_lst->pcl_weight_list,
-					    NUM_CHANNELS);
-		if (QDF_IS_STATUS_ERROR(status))
-			return;
-		pcl_lst->num_of_pcl_channels = num_entries;
-	}
-}
 
-static void cm_calculate_scores(struct wlan_objmgr_pdev *pdev,
-				struct scan_filter *filter, qdf_list_t *list)
-{
-	struct pcl_freq_weight_list *pcl_lst = NULL;
-
-	if (!filter->num_of_bssid) {
-		pcl_lst = qdf_mem_malloc(sizeof(*pcl_lst));
-		cm_get_pcl_chan_weigtage_for_sta(pdev, pcl_lst);
-		if (pcl_lst && !pcl_lst->num_of_pcl_channels) {
-			qdf_mem_free(pcl_lst);
-			pcl_lst = NULL;
-		}
-	}
-	wlan_cm_calculate_bss_score(pdev, pcl_lst, list, &filter->bssid_hint);
-	if (pcl_lst)
-		qdf_mem_free(pcl_lst);
-}
 #else
 
 static inline
@@ -463,12 +422,6 @@ QDF_STATUS cm_check_for_hw_mode_change(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_E_ALREADY;
 }
 
-static inline
-void cm_calculate_scores(struct wlan_objmgr_pdev *pdev,
-			 struct scan_filter *filter, qdf_list_t *list)
-{
-	wlan_cm_calculate_bss_score(pdev, NULL, list, &filter->bssid_hint);
-}
 #endif /* WLAN_POLICY_MGR_ENABLE */
 
 static inline void cm_delete_pmksa_for_bssid(struct cnx_mgr *cm_ctx,
@@ -808,6 +761,7 @@ static void cm_update_security_filter(struct scan_filter *filter,
 	filter->mgmtcipherset = req->crypto.mgmt_ciphers;
 	cm_set_pmf_caps(req, filter);
 }
+
 static inline void cm_set_fils_wep_key(struct cnx_mgr *cm_ctx,
 				       struct wlan_cm_connect_resp *resp)
 {}

+ 2 - 2
umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015, 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015,2020-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
@@ -355,7 +355,7 @@ QDF_STATUS cm_disconnect_start(struct cnx_mgr *cm_ctx,
 	return QDF_STATUS_SUCCESS;
 }
 
-static void
+void
 cm_update_scan_mlme_on_disconnect(struct wlan_objmgr_vdev *vdev,
 				  struct cm_disconnect_req *req)
 {

+ 17 - 1
umac/mlme/connection_mgr/core/src/wlan_cm_main.h

@@ -117,6 +117,20 @@ struct cm_connect_req {
 	uint8_t connect_attempts;
 };
 
+/**
+ * struct cm_roam_req - roam req stored in connect manager
+ * @cm_id: Connect manager id
+ * @req: roam req from osif
+ * @candidate_list: candidate list
+ * @cur_candidate: current candidate
+ */
+struct cm_roam_req {
+	wlan_cm_id cm_id;
+	struct wlan_cm_roam_req req;
+	qdf_list_t *candidate_list;
+	struct scan_cache_node *cur_candidate;
+};
+
 /**
  * struct cm_disconnect_req - disconnect req
  * @cm_id: Connect manager id
@@ -135,7 +149,8 @@ struct cm_disconnect_req {
  * with a commands pending before it, ie this is the latest command which failed
  * but still some operation(req) is pending.
  * @connect_req: connect req
- * @disconnect_req: disconnect req
+ * @discon_req: disconnect req
+ * @roam_req: roam req
  */
 struct cm_req {
 	qdf_list_node_t node;
@@ -144,6 +159,7 @@ struct cm_req {
 	union {
 		struct cm_connect_req connect_req;
 		struct cm_disconnect_req discon_req;
+		struct cm_roam_req roam_req;
 	};
 };
 

+ 41 - 0
umac/mlme/connection_mgr/core/src/wlan_cm_main_api.h

@@ -33,6 +33,8 @@
 
 #define CONNECT_REQ_PREFIX          0x00C00000
 #define DISCONNECT_REQ_PREFIX       0x00D00000
+#define ROAM_REQ_PREFIX             0x00F00000
+
 #define CM_ID_MASK                  0x0000FFFF
 
 #define CM_ID_GET_PREFIX(cm_id)     cm_id & 0xFFFF0000
@@ -922,4 +924,43 @@ struct cm_req *cm_get_req_by_scan_id(struct cnx_mgr *cm_ctx,
 wlan_cm_id cm_get_cm_id_by_scan_id(struct cnx_mgr *cm_ctx,
 				   wlan_scan_id scan_id);
 
+/**
+ * cm_update_scan_mlme_on_disconnect() - update the scan mlme info
+ * on disconnect completion
+ * @vdev: Object manager vdev
+ * @req: Disconnect request
+ *
+ * Return: void
+ */
+void
+cm_update_scan_mlme_on_disconnect(struct wlan_objmgr_vdev *vdev,
+				  struct cm_disconnect_req *req);
+
+/**
+ * cm_calculate_scores() - Score the candidates obtained from scan
+ * manager after filtering
+ * @pdev: Object manager pdev
+ * @filter: Scan filter params
+ * @list: List of candidates to be scored
+ *
+ * Return: void
+ */
+void cm_calculate_scores(struct wlan_objmgr_pdev *pdev,
+			 struct scan_filter *filter, qdf_list_t *list);
+
+/**
+ * cm_req_lock_acquire() - Acquire connection manager request lock
+ * @cm_ctx: Connection manager context
+ *
+ * Return: void
+ */
+void cm_req_lock_acquire(struct cnx_mgr *cm_ctx);
+
+/**
+ * cm_req_lock_release() - Release connection manager request lock
+ * @cm_ctx: Connection manager context
+ *
+ * Return: void
+ */
+void cm_req_lock_release(struct cnx_mgr *cm_ctx);
 #endif /* __WLAN_CM_MAIN_API_H__ */

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

@@ -89,7 +89,9 @@ QDF_STATUS cm_reassoc_complete(struct cnx_mgr *cm_ctx,
 #else
 static inline QDF_STATUS cm_reassoc_complete(struct cnx_mgr *cm_ctx,
 					     struct wlan_cm_roam_resp *resp)
-{}
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif
 
 /**

+ 135 - 31
umac/mlme/connection_mgr/core/src/wlan_cm_roam_sm.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015, 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015,2020-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
@@ -21,6 +21,8 @@
 #include "wlan_cm_main.h"
 #include "wlan_cm_roam_sm.h"
 #include "wlan_cm_sm.h"
+#include "wlan_cm_main_api.h"
+#include "wlan_cm_roam.h"
 
 void cm_state_roaming_entry(void *ctx)
 {
@@ -33,19 +35,30 @@ void cm_state_roaming_exit(void *ctx)
 {
 }
 
-bool cm_state_roaming_event(void *ctx, uint16_t event, uint16_t data_len,
-			    void *data)
+bool cm_state_roaming_event(void *ctx, uint16_t event,
+			    uint16_t data_len, void *data)
 {
-//	struct cnx_mgr *cm_ctx = ctx;
-	bool status;
+	struct cnx_mgr *cm_ctx = ctx;
+	bool event_handled = true;
 
 	switch (event) {
+	case WLAN_CM_SM_EV_ROAM_REQ:
+		cm_start_roam_req(cm_ctx, data);
+		break;
+	case WLAN_CM_SM_EV_ROAM_INVOKE:
+		cm_add_connect_req_to_list(cm_ctx, data);
+		cm_start_roam_invoke(cm_ctx);
+		break;
+	case WLAN_CM_SM_EV_ROAM_START:
+		cm_add_connect_req_to_list(cm_ctx, data);
+		cm_fw_roam_start(cm_ctx);
+		break;
 	default:
-		status = false;
+		event_handled = false;
 		break;
 	}
 
-	return status;
+	return event_handled;
 }
 
 #ifdef WLAN_FEATURE_HOST_ROAM
@@ -64,19 +77,70 @@ void cm_subst_preauth_exit(void *ctx)
 {
 }
 
-bool cm_subst_preauth_event(void *ctx, uint16_t event, uint16_t data_len,
-			    void *data)
+bool cm_subst_preauth_event(void *ctx, uint16_t event,
+			    uint16_t data_len, void *data)
+{
+	bool event_handled;
+
+	switch (event) {
+	default:
+		event_handled = false;
+		break;
+	}
+
+	return event_handled;
+}
+
+#else
+void cm_subst_preauth_entry(void *ctx)
+{
+	struct cnx_mgr *cm_ctx = ctx;
+
+	if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING)
+		QDF_BUG(0);
+
+	cm_set_substate(cm_ctx, WLAN_CM_SS_PREAUTH);
+}
+
+void cm_subst_preauth_exit(void *ctx)
+{
+}
+
+bool cm_subst_preauth_event(void *ctx, uint16_t event,
+			    uint16_t data_len, void *data)
 {
-//	struct cnx_mgr *cm_ctx = ctx;
-	bool status;
+	struct cnx_mgr *cm_ctx = ctx;
+	bool event_handled = true;
+	QDF_STATUS status;
 
 	switch (event) {
+	case WLAN_CM_SM_EV_ROAM_START:
+		cm_host_roam_start_req(cm_ctx, data);
+		break;
+	case WLAN_CM_SM_EV_START_REASSOC:
+		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_REASSOC);
+		cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_START_REASSOC,
+					 data_len, data);
+		break;
+	case WLAN_CM_SM_EV_DISCONNECT_REQ:
+		status = cm_add_disconnect_req_to_list(cm_ctx, data);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			event_handled = false;
+			break;
+		}
+		cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING);
+		cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_DISCONNECT_START,
+					 data_len, data);
+		break;
+	case WLAN_CM_SM_EV_REASSOC_FAILURE:
+		cm_reassoc_complete(cm_ctx, data);
+		break;
 	default:
-		status = false;
+		event_handled = false;
 		break;
 	}
 
-	return status;
+	return event_handled;
 }
 
 #endif /* WLAN_FEATURE_PREAUTH_ENABLE */
@@ -95,19 +159,61 @@ void cm_subst_reassoc_exit(void *ctx)
 {
 }
 
-bool cm_subst_reassoc_event(void *ctx, uint16_t event, uint16_t data_len,
-			    void *data)
+bool cm_subst_reassoc_event(void *ctx, uint16_t event,
+			    uint16_t data_len, void *data)
 {
-//	struct cnx_mgr *cm_ctx = ctx;
-	bool status;
+	struct cnx_mgr *cm_ctx = ctx;
+	bool event_handled = true;
+	QDF_STATUS status;
 
 	switch (event) {
+	case WLAN_CM_SM_EV_START_REASSOC:
+		cm_reassoc_start(cm_ctx, data);
+		break;
+	case WLAN_CM_SM_EV_REASSOC_ACTIVE:
+		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
+			event_handled = false;
+			break;
+		}
+		cm_reassoc_active(cm_ctx, data);
+		break;
+	case WLAN_CM_SM_EV_DISCONNECT_DONE:
+		cm_reassoc_disconnect_complete(cm_ctx, data);
+		break;
+	case WLAN_CM_SM_EV_BSS_CREATE_PEER_SUCCESS:
+		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
+			event_handled = false;
+			break;
+		}
+		cm_resume_reassoc_after_peer_create(cm_ctx, data);
+		break;
+	case WLAN_CM_SM_EV_REASSOC_DONE:
+		if (!cm_roam_resp_cmid_match_list_head(cm_ctx, data)) {
+			event_handled = false;
+			break;
+		}
+		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
+		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
+		break;
+	case WLAN_CM_SM_EV_DISCONNECT_REQ:
+		status = cm_add_disconnect_req_to_list(cm_ctx, data);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			event_handled = false;
+			break;
+		}
+		cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING);
+		cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_DISCONNECT_START,
+					 data_len, data);
+		break;
+	case WLAN_CM_SM_EV_REASSOC_FAILURE:
+		cm_reassoc_complete(cm_ctx, data);
+		break;
 	default:
-		status = false;
+		event_handled = false;
 		break;
 	}
 
-	return status;
+	return event_handled;
 }
 
 #endif /* WLAN_FEATURE_HOST_ROAM */
@@ -127,19 +233,18 @@ void cm_subst_roam_start_exit(void *ctx)
 {
 }
 
-bool cm_subst_roam_start_event(void *ctx, uint16_t event, uint16_t data_len,
-			       void *data)
+bool cm_subst_roam_start_event(void *ctx, uint16_t event,
+			       uint16_t data_len, void *data)
 {
-//	struct cnx_mgr *cm_ctx = ctx;
-	bool status;
+	bool event_handled;
 
 	switch (event) {
 	default:
-		status = false;
+		event_handled = false;
 		break;
 	}
 
-	return status;
+	return event_handled;
 }
 
 void cm_subst_roam_sync_entry(void *ctx)
@@ -156,18 +261,17 @@ void cm_subst_roam_sync_exit(void *ctx)
 {
 }
 
-bool cm_subst_roam_sync_event(void *ctx, uint16_t event, uint16_t data_len,
-			      void *data)
+bool cm_subst_roam_sync_event(void *ctx, uint16_t event,
+			      uint16_t data_len, void *data)
 {
-//	struct cnx_mgr *cm_ctx = ctx;
-	bool status;
+	bool event_handled;
 
 	switch (event) {
 	default:
-		status = false;
+		event_handled = false;
 		break;
 	}
 
-	return status;
+	return event_handled;
 }
 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */

+ 5 - 4
umac/mlme/connection_mgr/core/src/wlan_cm_roam_sm.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015, 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015,2020-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
@@ -23,6 +23,8 @@
 #ifndef __WLAN_CM_ROAM_SM_H__
 #define __WLAN_CM_ROAM_SM_H__
 
+#include "wlan_cm_roam.h"
+
 /**
  * cm_state_roaming_entry() - Entry API for roaming state for
  * connection mgr
@@ -59,7 +61,7 @@ void cm_state_roaming_exit(void *ctx);
 bool cm_state_roaming_event(void *ctx, uint16_t event, uint16_t data_len,
 			    void *data);
 
-#if defined(WLAN_FEATURE_HOST_ROAM) && defined(WLAN_FEATURE_PREAUTH_ENABLE)
+#if defined(WLAN_FEATURE_HOST_ROAM)
 /**
  * cm_subst_preauth_entry() - Entry API for preauth sub-state for
  * connection mgr
@@ -150,6 +152,7 @@ bool cm_subst_reassoc_event(void *ctx, uint16_t event, uint16_t data_len,
 
 static inline void cm_subst_reassoc_entry(void *ctx) {}
 static inline void cm_subst_reassoc_exit(void *ctx) {}
+
 static inline
 bool cm_subst_reassoc_event(void *ctx, uint16_t event, uint16_t data_len,
 			    void *data)
@@ -257,7 +260,5 @@ bool cm_subst_roam_sync_event(void *ctx, uint16_t event, uint16_t data_len,
 {
 	return true;
 }
-
 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
-
 #endif /* __WLAN_CM_ROAM_SM_H__ */

+ 33 - 1
umac/mlme/connection_mgr/core/src/wlan_cm_sm.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015, 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015,2020-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
@@ -240,9 +240,34 @@ static bool cm_state_connected_event(void *ctx, uint16_t event,
 	struct cnx_mgr *cm_ctx = ctx;
 	bool event_handled;
 	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);
+		event_handled = true;
+		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,
+					 WLAN_CM_SM_EV_ROAM_REQ,
+					 data_len, data);
+		event_handled = true;
+		break;
 	case WLAN_CM_SM_EV_CONNECT_REQ:
+		status = cm_check_and_prepare_roam_req(cm_ctx, data,
+						       &roam_cm_req);
+		if (QDF_IS_STATUS_SUCCESS(status)) {
+			cm_sm_deliver_event_sync(cm_ctx,
+						 WLAN_CM_SM_EV_ROAM_REQ,
+						 sizeof(*roam_cm_req),
+						 roam_cm_req);
+			event_handled = true;
+			break;
+		}
 		status = cm_handle_connect_req_in_non_init_state(cm_ctx, data,
 							WLAN_CM_S_CONNECTED);
 		if (QDF_IS_STATUS_ERROR(status)) {
@@ -275,6 +300,10 @@ static bool cm_state_connected_event(void *ctx, uint16_t event,
 					 data_len, data);
 		event_handled = true;
 		break;
+	case WLAN_CM_SM_EV_REASSOC_DONE:
+		cm_reassoc_complete(cm_ctx, data);
+		event_handled = true;
+		break;
 	default:
 		event_handled = false;
 		break;
@@ -958,9 +987,12 @@ static const char *cm_sm_event_names[] = {
 	"EV_GET_NEXT_PREAUTH_AP",
 	"EV_PREAUTH_FAIL",
 	"EV_START_REASSOC",
+	"EV_REASSOC_ACTIVE",
 	"EV_REASSOC_DONE",
 	"EV_REASSOC_FAILURE",
 	"EV_ROAM_COMPLETE",
+	"EV_ROAM_REQ",
+	"EV_ROAM_INVOKE",
 };
 
 enum wlan_cm_sm_state cm_get_state(struct cnx_mgr *cm_ctx)

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

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015, 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015,2020-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
@@ -46,17 +46,21 @@
  * @WLAN_CM_SM_EV_DISCONNECT_START:       Start disconnect sequence
  * @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
- * @WLAN_CM_SM_EV_ROAM_SYNC:              Roam sync 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_INVOKE_FAIL:       Roam invoke fail event
  * @WLAN_CM_SM_EV_ROAM_HO_FAIL:           Hand 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
  * @WLAN_CM_SM_EV_START_REASSOC:          Start reassoc after preauth done
+ * @WLAN_CM_SM_EV_REASSOC_ACTIVE:         Reassoc request activated
  * @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
+ *                                        LFR2/Host roam - Roam req from host/FW
+ * @WLAN_CM_SM_EV_ROAM_INVOKE:            Host initiated LFR3/FW roam req
  * @WLAN_CM_SM_EV_MAX:                    Max event
  */
 enum wlan_cm_sm_evt {
@@ -85,9 +89,12 @@ enum wlan_cm_sm_evt {
 	WLAN_CM_SM_EV_GET_NEXT_PREAUTH_AP = 22,
 	WLAN_CM_SM_EV_PREAUTH_FAIL = 23,
 	WLAN_CM_SM_EV_START_REASSOC = 24,
-	WLAN_CM_SM_EV_REASSOC_DONE = 25,
-	WLAN_CM_SM_EV_REASSOC_FAILURE = 26,
-	WLAN_CM_SM_EV_ROAM_COMPLETE = 27,
+	WLAN_CM_SM_EV_REASSOC_ACTIVE = 25,
+	WLAN_CM_SM_EV_REASSOC_DONE = 26,
+	WLAN_CM_SM_EV_REASSOC_FAILURE = 27,
+	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_MAX,
 };
 

+ 72 - 6
umac/mlme/connection_mgr/core/src/wlan_cm_util.c

@@ -22,13 +22,16 @@
 #include "wlan_scan_api.h"
 #include "wlan_cm_public_struct.h"
 #include "wlan_serialization_api.h"
+#include "wlan_cm_bss_score_param.h"
 
 static uint32_t cm_get_prefix_for_cm_id(enum wlan_cm_source source) {
 	switch (source) {
 	case CM_OSIF_CONNECT:
-	case CM_ROAMING:
 	case CM_OSIF_CFG_CONNECT:
 		return CONNECT_REQ_PREFIX;
+	case CM_ROAMING_HOST:
+	case CM_ROAMING_FW:
+		return ROAM_REQ_PREFIX;
 	default:
 		return DISCONNECT_REQ_PREFIX;
 	}
@@ -104,7 +107,7 @@ void cm_reset_active_cm_id(struct wlan_objmgr_vdev *vdev, wlan_cm_id cm_id)
  *
  * return: void
  */
-static inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx)
+inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx)
 {
 	qdf_spinlock_acquire(&cm_ctx->cm_req_lock);
 }
@@ -117,17 +120,17 @@ static inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx)
  *
  * return: void
  */
-static inline void cm_req_lock_release(struct cnx_mgr *cm_ctx)
+inline void cm_req_lock_release(struct cnx_mgr *cm_ctx)
 {
 	qdf_spinlock_release(&cm_ctx->cm_req_lock);
 }
 #else
-static inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx)
+inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx)
 {
 	qdf_mutex_acquire(&cm_ctx->cm_req_lock);
 }
 
-static inline void cm_req_lock_release(struct cnx_mgr *cm_ctx)
+inline void cm_req_lock_release(struct cnx_mgr *cm_ctx)
 {
 	qdf_mutex_release(&cm_ctx->cm_req_lock);
 }
@@ -459,6 +462,8 @@ static void cm_remove_cmd_from_serialization(struct cnx_mgr *cm_ctx,
 
 	if (prefix == CONNECT_REQ_PREFIX)
 		cmd_info.cmd_type = WLAN_SER_CMD_VDEV_CONNECT;
+	else if (prefix == ROAM_REQ_PREFIX)
+		cmd_info.cmd_type = WLAN_SER_CMD_VDEV_REASSOC;
 	else
 		cmd_info.cmd_type = WLAN_SER_CMD_VDEV_DISCONNECT;
 
@@ -613,8 +618,9 @@ QDF_STATUS cm_add_req_to_list_and_indicate_osif(struct cnx_mgr *cm_ctx,
 	qdf_list_insert_front(&cm_ctx->req_list, &cm_req->node);
 	if (prefix == CONNECT_REQ_PREFIX)
 		cm_ctx->connect_count++;
-	else
+	else if (prefix == DISCONNECT_REQ_PREFIX)
 		cm_ctx->disconnect_count++;
+
 	cm_req_lock_release(cm_ctx);
 	mlme_debug(CM_PREFIX_FMT,
 		   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
@@ -654,6 +660,12 @@ void cm_free_connect_req_mem(struct cm_connect_req *connect_req)
 	qdf_mem_zero(connect_req, sizeof(*connect_req));
 }
 
+void cm_free_roam_req_mem(struct cm_roam_req *roam_req)
+{
+	if (roam_req->candidate_list)
+		wlan_scan_purge_results(roam_req->candidate_list);
+}
+
 QDF_STATUS
 cm_delete_req_from_list(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
 {
@@ -686,6 +698,8 @@ cm_delete_req_from_list(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
 	if (prefix == CONNECT_REQ_PREFIX) {
 		cm_ctx->connect_count--;
 		cm_free_connect_req_mem(&cm_req->connect_req);
+	} else if (prefix == ROAM_REQ_PREFIX) {
+		cm_free_roam_req_mem(&cm_req->roam_req);
 	} else {
 		cm_ctx->disconnect_count--;
 	}
@@ -1048,6 +1062,8 @@ cm_get_active_req_type(struct wlan_objmgr_vdev *vdev)
 		return CM_CONNECT_ACTIVE;
 	else if (active_req_prefix == DISCONNECT_REQ_PREFIX)
 		return CM_DISCONNECT_ACTIVE;
+	else if (active_req_prefix == ROAM_REQ_PREFIX)
+		return CM_ROAM_ACTIVE;
 	else
 		return CM_NONE;
 }
@@ -1179,3 +1195,53 @@ wlan_cm_id cm_get_cm_id_by_scan_id(struct cnx_mgr *cm_ctx,
 	return CM_ID_INVALID;
 }
 
+#ifdef WLAN_POLICY_MGR_ENABLE
+static void
+cm_get_pcl_chan_weigtage_for_sta(struct wlan_objmgr_pdev *pdev,
+				 struct pcl_freq_weight_list *pcl_lst)
+{
+	enum QDF_OPMODE opmode = QDF_STA_MODE;
+	enum policy_mgr_con_mode pm_mode;
+	uint32_t num_entries = 0;
+	QDF_STATUS status;
+
+	if (!pcl_lst)
+		return;
+
+	if (policy_mgr_map_concurrency_mode(&opmode, &pm_mode)) {
+		status = policy_mgr_get_pcl(wlan_pdev_get_psoc(pdev), pm_mode,
+					    pcl_lst->pcl_freq_list,
+					    &num_entries,
+					    pcl_lst->pcl_weight_list,
+					    NUM_CHANNELS);
+		if (QDF_IS_STATUS_ERROR(status))
+			return;
+		pcl_lst->num_of_pcl_channels = num_entries;
+	}
+}
+
+void cm_calculate_scores(struct wlan_objmgr_pdev *pdev,
+			 struct scan_filter *filter, qdf_list_t *list)
+{
+	struct pcl_freq_weight_list *pcl_lst = NULL;
+
+	if (!filter->num_of_bssid) {
+		pcl_lst = qdf_mem_malloc(sizeof(*pcl_lst));
+		cm_get_pcl_chan_weigtage_for_sta(pdev, pcl_lst);
+		if (pcl_lst && !pcl_lst->num_of_pcl_channels) {
+			qdf_mem_free(pcl_lst);
+			pcl_lst = NULL;
+		}
+	}
+	wlan_cm_calculate_bss_score(pdev, pcl_lst, list, &filter->bssid_hint);
+	if (pcl_lst)
+		qdf_mem_free(pcl_lst);
+}
+#else
+inline
+void cm_calculate_scores(struct wlan_objmgr_pdev *pdev,
+			 struct scan_filter *filter, qdf_list_t *list)
+{
+	wlan_cm_calculate_bss_score(pdev, NULL, list, &filter->bssid_hint);
+}
+#endif

+ 41 - 0
umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_api.h

@@ -280,6 +280,28 @@ bool wlan_cm_is_vdev_roam_reassoc_state(struct wlan_objmgr_vdev *vdev)
 bool wlan_cm_get_active_connect_req(struct wlan_objmgr_vdev *vdev,
 				    struct wlan_cm_vdev_connect_req *req);
 
+#ifdef WLAN_FEATURE_HOST_ROAM
+/**
+ * wlan_cm_get_active_reassoc_req() - Get copy of active reassoc request
+ * @vdev: vdev pointer
+ * @req: pointer to the copy of the active reassoc request
+ * *
+ * Context: Should be called only in the conext of the
+ * cm request activation
+ *
+ * Return: true and reassoc req if any request is active
+ */
+bool wlan_cm_get_active_reassoc_req(struct wlan_objmgr_vdev *vdev,
+				    struct wlan_cm_vdev_reassoc_req *req);
+#else
+static inline
+bool wlan_cm_get_active_reassoc_req(struct wlan_objmgr_vdev *vdev,
+				    struct wlan_cm_vdev_reassoc_req *req)
+{
+	return false;
+}
+#endif
+
 /**
  * wlan_cm_get_active_disconnect_req() - Get copy of active disconnect request
  * @vdev: vdev pointer
@@ -315,6 +337,25 @@ const char *wlan_cm_reason_code_to_str(enum wlan_reason_code reason);
 enum wlan_cm_active_request_type
 wlan_cm_get_active_req_type(struct wlan_objmgr_vdev *vdev);
 
+#ifdef WLAN_FEATURE_HOST_ROAM
+/**
+ * wlan_cm_reassoc_rsp() - Connection manager reassoc response
+ * @vdev: vdev pointer
+ * @resp: Reassoc response
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_cm_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
+			       struct wlan_cm_roam_resp *resp);
+#else
+static inline
+QDF_STATUS wlan_cm_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
+			       struct wlan_cm_roam_resp *resp)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
  * wlan_cm_hw_mode_change_resp() - HW mode change response
  * @pdev: pdev pointer

+ 61 - 3
umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_public_struct.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015, 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015,2020-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
@@ -108,7 +108,8 @@ struct wlan_fils_con_info {
 /**
  * enum wlan_cm_source - connection manager req source
  * @CM_OSIF_CONNECT: Connect req initiated by OSIF or north bound
- * @CM_ROAMING: Roaming request
+ * @CM_ROAMING_HOST: Roaming request initiated by host
+ * @CM_ROAMING_FW: Roam req initiated by FW
  * @CM_OSIF_DISCONNECT: Disconnect req initiated by OSIF or north bound
  * @CM_PEER_DISCONNECT: Disconnect req initiated by peer sending deauth/disassoc
  * only for this localy generated will be false while indicating to kernel
@@ -126,7 +127,8 @@ struct wlan_fils_con_info {
  */
 enum wlan_cm_source {
 	CM_OSIF_CONNECT,
-	CM_ROAMING,
+	CM_ROAMING_HOST,
+	CM_ROAMING_FW,
 	CM_OSIF_DISCONNECT,
 	CM_PEER_DISCONNECT,
 	CM_SB_DISCONNECT,
@@ -225,6 +227,36 @@ struct wlan_cm_vdev_connect_req {
 #endif
 };
 
+/**
+ * struct wlan_cm_roam_req - roam req from requester
+ * @vdev_id: vdev id
+ * @source: source of the req
+ * @bssid: bssid given
+ * @prev_bssid: prev AP bssid, given in case supplican want to roam to new BSSID
+ * @chan_freq: channel of the AP
+ */
+struct wlan_cm_roam_req {
+	uint8_t vdev_id;
+	enum wlan_cm_source source;
+	struct qdf_mac_addr bssid;
+	struct qdf_mac_addr prev_bssid;
+	uint32_t chan_freq;
+};
+
+/**
+ * struct wlan_cm_vdev_reassoc_req - Reassoc req from connection manager to
+ * vdev mgr
+ * @vdev_id: vdev id
+ * @cm_id: Connect manager id
+ * @bss: scan entry for the candidate
+ */
+struct wlan_cm_vdev_reassoc_req {
+	uint8_t vdev_id;
+	wlan_cm_id cm_id;
+	struct qdf_mac_addr prev_bssid;
+	struct scan_cache_node *bss;
+};
+
 /**
  * struct wlan_cm_disconnect_req - disconnect req from requester
  * @vdev_id: vdev id
@@ -379,6 +411,30 @@ struct wlan_cm_connect_resp {
 #endif
 };
 
+/**
+ * struct wlan_cm_roam_rsp - Roam resp from VDEV mgr and will be sent to
+ * OSIF
+ * @vdev_id: vdev id
+ * @cm_id: Connection manager id
+ * @bssid: BSSID of the ap
+ * @ssid: SSID of the connection
+ * @freq: Channel frequency
+ * @reassoc_status: Reassoc status success or failure
+ * @reason: connect fail reason, valid only in case of failure
+ * @status_code: protocol status code received in auth/assoc resp
+ * @connect_ies: connect related IE required by osif to send to kernel
+ */
+struct wlan_cm_roam_resp {
+	uint8_t vdev_id;
+	wlan_cm_id cm_id;
+	struct qdf_mac_addr bssid;
+	struct wlan_ssid ssid;
+	qdf_freq_t freq;
+	QDF_STATUS reassoc_status;
+	enum wlan_cm_connect_fail_reason reason;
+	enum wlan_status_code status_code;
+	struct wlan_connect_rsp_ies connect_ies;
+};
 
 /**
  * struct wlan_cm_discon_rsp - disconnect resp from VDEV mgr and will be sent to
@@ -396,11 +452,13 @@ struct wlan_cm_discon_rsp {
  * @CM_NONE: No active serialisation command
  * @CM_CONNECT_ACTIVE: Connect active in serialisation
  * @CM_DISCONNECT_ACTIVE: DicConnect active in serialisation
+ * @CM_ROAM_ACTIVE: Roam active in serialisation
  */
 enum wlan_cm_active_request_type {
 	CM_NONE,
 	CM_CONNECT_ACTIVE,
 	CM_DISCONNECT_ACTIVE,
+	CM_ROAM_ACTIVE,
 };
 
 #endif /* FEATURE_CM_ENABLE */

+ 39 - 2
umac/mlme/connection_mgr/dispatcher/src/wlan_cm_api.c

@@ -22,6 +22,7 @@
 
 #include <wlan_cm_api.h>
 #include "connection_mgr/core/src/wlan_cm_main_api.h"
+#include "connection_mgr/core/src/wlan_cm_roam.h"
 
 QDF_STATUS wlan_cm_start_connect(struct wlan_objmgr_vdev *vdev,
 				 struct wlan_cm_connect_req *req)
@@ -68,7 +69,17 @@ QDF_STATUS wlan_cm_bss_peer_create_rsp(struct wlan_objmgr_vdev *vdev,
 				       QDF_STATUS status,
 				       struct qdf_mac_addr *peer_mac)
 {
-	return cm_bss_peer_create_rsp(vdev, status, peer_mac);
+	uint32_t prefix;
+	struct cnx_mgr *cm_ctx = cm_get_cm_ctx(vdev);
+
+	if (!cm_ctx)
+		return QDF_STATUS_E_INVAL;
+
+	prefix = CM_ID_GET_PREFIX(cm_ctx->active_cm_id);
+	if (prefix == ROAM_REQ_PREFIX)
+		return cm_roam_bss_peer_create_rsp(vdev, status, peer_mac);
+	else
+		return cm_bss_peer_create_rsp(vdev, status, peer_mac);
 }
 
 QDF_STATUS wlan_cm_connect_rsp(struct wlan_objmgr_vdev *vdev,
@@ -92,8 +103,26 @@ QDF_STATUS wlan_cm_bss_peer_delete_rsp(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS wlan_cm_disconnect_rsp(struct wlan_objmgr_vdev *vdev,
 				  struct wlan_cm_discon_rsp *resp)
 {
-	return cm_disconnect_rsp(vdev, resp);
+	uint32_t prefix;
+	struct cnx_mgr *cm_ctx = cm_get_cm_ctx(vdev);
+
+	if (!cm_ctx)
+		return QDF_STATUS_E_INVAL;
+
+	prefix = CM_ID_GET_PREFIX(cm_ctx->active_cm_id);
+	if (prefix == ROAM_REQ_PREFIX)
+		return cm_roam_disconnect_rsp(vdev, resp);
+	else
+		return cm_disconnect_rsp(vdev, resp);
+}
+
+#ifdef WLAN_FEATURE_HOST_ROAM
+QDF_STATUS wlan_cm_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
+			       struct wlan_cm_roam_resp *resp)
+{
+	return cm_reassoc_rsp(vdev, resp);
 }
+#endif
 
 void wlan_cm_set_max_connect_attempts(struct wlan_objmgr_vdev *vdev,
 				      uint8_t max_connect_attempts)
@@ -173,6 +202,14 @@ bool wlan_cm_get_active_connect_req(struct wlan_objmgr_vdev *vdev,
 	return cm_get_active_connect_req(vdev, req);
 }
 
+#ifdef WLAN_FEATURE_HOST_ROAM
+bool wlan_cm_get_active_reassoc_req(struct wlan_objmgr_vdev *vdev,
+				    struct wlan_cm_vdev_reassoc_req *req)
+{
+	return cm_get_active_reassoc_req(vdev, req);
+}
+#endif
+
 bool wlan_cm_get_active_disconnect_req(struct wlan_objmgr_vdev *vdev,
 				       struct wlan_cm_vdev_discon_req *req)
 {

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

@@ -51,6 +51,10 @@
  *
  * @mlme_cm_disconnect_start_cb: Disconnect start callback
  * @vdev: vdev pointer
+ *
+ * @mlme_cm_reassoc_complete_cb: Reassoc done callback
+ * @vdev: vdev pointer
+ * @rsp: Roam response
  */
 struct mlme_cm_ops {
 	QDF_STATUS (*mlme_cm_connect_complete_cb)(
@@ -68,6 +72,9 @@ struct mlme_cm_ops {
 					struct wlan_cm_discon_rsp *rsp);
 	QDF_STATUS (*mlme_cm_disconnect_start_cb)(
 					struct wlan_objmgr_vdev *vdev);
+	QDF_STATUS (*mlme_cm_reassoc_complete_cb)(
+					struct wlan_objmgr_vdev *vdev,
+					struct wlan_cm_roam_resp *rsp);
 };
 #endif
 
@@ -116,6 +123,11 @@ struct mlme_cm_ops {
  * @mlme_cm_ext_disconnect_complete_ind_cb: callback to indicate disconnect
  *                                          complete
  * @mlme_cm_ext_vdev_down_req_cb:           callback to send vdev down to FW
+ * @mlme_cm_ext_roam_start_ind_cb:          callback to indicate roam start
+ * @mlme_cm_ext_reassoc_req_cb:             callback for reassoc request to
+ *                                          VDEV/PEER SM
+ * @mlme_cm_ext_reassoc_complete_ind_cb:    callback to indicate reassoc
+ *                                          complete
  */
 struct mlme_ext_ops {
 	QDF_STATUS (*mlme_psoc_ext_hdl_create)(
@@ -177,6 +189,15 @@ struct mlme_ext_ops {
 				struct wlan_cm_discon_rsp *rsp);
 	QDF_STATUS (*mlme_cm_ext_vdev_down_req_cb)(
 				struct wlan_objmgr_vdev *vdev);
+	QDF_STATUS (*mlme_cm_ext_roam_start_ind_cb)(
+				struct wlan_objmgr_vdev *vdev,
+				struct wlan_cm_roam_req *req);
+	QDF_STATUS (*mlme_cm_ext_reassoc_req_cb)(
+				struct wlan_objmgr_vdev *vdev,
+				struct wlan_cm_vdev_reassoc_req *req);
+	QDF_STATUS (*mlme_cm_ext_reassoc_complete_ind_cb)(
+				struct wlan_objmgr_vdev *vdev,
+				struct wlan_cm_roam_resp *rsp);
 #endif
 };
 
@@ -452,6 +473,40 @@ QDF_STATUS mlme_cm_connect_req(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS mlme_cm_connect_complete_ind(struct wlan_objmgr_vdev *vdev,
 					struct wlan_cm_connect_resp *rsp);
 
+/**
+ * mlme_cm_roam_start_ind() - Connection manager ext Connect start indication
+ * @vdev: VDEV object
+ * @req: Connection manager roam request
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS mlme_cm_roam_start_ind(struct wlan_objmgr_vdev *vdev,
+				  struct wlan_cm_roam_req *req);
+
+/**
+ * mlme_cm_reassoc_req() - Connection manager ext reassoc request
+ * @vdev: VDEV object
+ * @req: Vdev reassoc request
+ *
+ * Context: The req is on stack, so the API need to make a copy, if it want to
+ * use the req after return.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS mlme_cm_reassoc_req(struct wlan_objmgr_vdev *vdev,
+			       struct wlan_cm_vdev_reassoc_req *req);
+
+/**
+ * mlme_cm_reassoc_complete_ind() - Connection manager ext reassoc complete
+ * indication
+ * @vdev: VDEV object
+ * @rsp: Connection manager roam response
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS mlme_cm_reassoc_complete_ind(struct wlan_objmgr_vdev *vdev,
+					struct wlan_cm_roam_resp *rsp);
+
 /**
  * mlme_cm_disconnect_start_ind() - Connection manager ext disconnect start
  * indication
@@ -513,6 +568,16 @@ QDF_STATUS mlme_cm_vdev_down_req(struct wlan_objmgr_vdev *vdev);
 QDF_STATUS mlme_cm_osif_connect_complete(struct wlan_objmgr_vdev *vdev,
 					 struct wlan_cm_connect_resp *rsp);
 
+/**
+ * mlme_cm_osif_reassoc_complete() - Reassoc complete resp to osif
+ * @vdev: vdev pointer
+ * @rsp: Roam response
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS mlme_cm_osif_reassoc_complete(struct wlan_objmgr_vdev *vdev,
+					 struct wlan_cm_roam_resp *rsp);
+
 /**
  * mlme_cm_osif_failed_candidate_ind() - Failed Candidate indication to osif
  * @vdev: vdev pointer

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

@@ -312,6 +312,28 @@ QDF_STATUS mlme_cm_connect_req(struct wlan_objmgr_vdev *vdev,
 	return ret;
 }
 
+QDF_STATUS mlme_cm_roam_start_ind(struct wlan_objmgr_vdev *vdev,
+				  struct wlan_cm_roam_req *req)
+{
+	QDF_STATUS ret = QDF_STATUS_SUCCESS;
+
+	if ((glbl_ops) && glbl_ops->mlme_cm_ext_roam_start_ind_cb)
+		ret = glbl_ops->mlme_cm_ext_roam_start_ind_cb(vdev, req);
+
+	return ret;
+}
+
+QDF_STATUS mlme_cm_reassoc_req(struct wlan_objmgr_vdev *vdev,
+			       struct wlan_cm_vdev_reassoc_req *req)
+{
+	QDF_STATUS ret = QDF_STATUS_SUCCESS;
+
+	if ((glbl_ops) && glbl_ops->mlme_cm_ext_reassoc_req_cb)
+		ret = glbl_ops->mlme_cm_ext_reassoc_req_cb(vdev, req);
+
+	return ret;
+}
+
 QDF_STATUS mlme_cm_connect_complete_ind(struct wlan_objmgr_vdev *vdev,
 					struct wlan_cm_connect_resp *rsp)
 {
@@ -323,6 +345,17 @@ QDF_STATUS mlme_cm_connect_complete_ind(struct wlan_objmgr_vdev *vdev,
 	return ret;
 }
 
+QDF_STATUS mlme_cm_reassoc_complete_ind(struct wlan_objmgr_vdev *vdev,
+					struct wlan_cm_roam_resp *rsp)
+{
+	QDF_STATUS ret = QDF_STATUS_SUCCESS;
+
+	if ((glbl_ops) && glbl_ops->mlme_cm_ext_reassoc_complete_ind_cb)
+		ret = glbl_ops->mlme_cm_ext_reassoc_complete_ind_cb(vdev, rsp);
+
+	return ret;
+}
+
 QDF_STATUS mlme_cm_disconnect_start_ind(struct wlan_objmgr_vdev *vdev,
 					struct wlan_cm_disconnect_req *req)
 {
@@ -387,6 +420,17 @@ QDF_STATUS mlme_cm_osif_connect_complete(struct wlan_objmgr_vdev *vdev,
 	return ret;
 }
 
+QDF_STATUS mlme_cm_osif_reassoc_complete(struct wlan_objmgr_vdev *vdev,
+					 struct wlan_cm_roam_resp *rsp)
+{
+	QDF_STATUS ret = QDF_STATUS_SUCCESS;
+
+	if (glbl_cm_ops && glbl_cm_ops->mlme_cm_reassoc_complete_cb)
+		ret = glbl_cm_ops->mlme_cm_reassoc_complete_cb(vdev, rsp);
+
+	return ret;
+}
+
 QDF_STATUS
 mlme_cm_osif_failed_candidate_ind(struct wlan_objmgr_vdev *vdev,
 				  struct wlan_cm_connect_resp *rsp)