Browse Source

qcacld-3.0: Extract all link probe rsps from ML probe rsp

Firmware sends beacon/probe response of the roam candidate to host
through roam_frame_event when it chooses a candidate which needs
SAE authentication to be performed. This is needed as the host
checks if corresponding scan entry is present in the scan db
before starting SAE authentication trigger.
But in MLO roaming case, firmware might send ML probe response
and the scan entry corresponds to re-assoc link might be present
in the per STA profile of the ML probe response.
So, extract all per-STA profiles and add them to scan db.

Also, use this API to extract and add the link specific
ML probe responses for the ML probe response received
in roam sync indication if extraction via roam info fails due
to some reason(currently it may fail if fw roams to a link but
got ML probe rsp from other link as link_info is not
present roam info).

Change-Id: I6c67927732a54568dfe618bdecaca8f37515e203
CRs-Fixed: 3454834
Srinivas Dasari 2 years ago
parent
commit
a87a7cde2a

+ 15 - 6
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c

@@ -890,12 +890,21 @@ cm_update_scan_db_on_roam_success(struct wlan_objmgr_vdev *vdev,
 				roam_synch_ind,
 				wlan_mlme_get_src_addr_from_frame(
 				&ies->bcn_probe_rsp));
-	cm_inform_bcn_probe(cm_ctx,
-			    ies->bcn_probe_rsp.ptr,
-			    ies->bcn_probe_rsp.len,
-			    frame_freq,
-			    roam_synch_ind->rssi,
-			    cm_id);
+	/*
+	 * Firmware might have roamed to a link but got ML probe
+	 * response from the other link. Then the link freq is not
+	 * present in roam link info and it returns 0. No need to add
+	 * the original probe rsp in such cases as roam sync indication
+	 * handling would add it to scan db. Add the entry to scan
+	 * db only if valid link freq is found.
+	 */
+	if (frame_freq)
+		cm_inform_bcn_probe(cm_ctx,
+				    ies->bcn_probe_rsp.ptr,
+				    ies->bcn_probe_rsp.len,
+				    frame_freq,
+				    roam_synch_ind->rssi,
+				    cm_id);
 
 	cm_update_scan_mlme_on_roam(vdev, &resp->bssid,
 				    SCAN_ENTRY_CON_STATE_ASSOC);

+ 0 - 121
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c

@@ -591,124 +591,3 @@ QDF_STATUS cm_roam_sync_event_handler_cb(struct wlan_objmgr_vdev *vdev,
 err:
 	return status;
 }
-
-QDF_STATUS
-cm_roam_candidate_event_handler(struct wlan_objmgr_psoc *psoc,
-				struct roam_scan_candidate_frame *candidate)
-{
-	struct wlan_objmgr_vdev *vdev;
-	struct wlan_objmgr_pdev *pdev;
-	struct cnx_mgr *cm_ctx;
-	uint32_t ie_offset, ie_len;
-	uint8_t *ie_ptr = NULL;
-	uint8_t *extracted_ie = NULL;
-	uint8_t primary_channel, band;
-	qdf_freq_t op_freq;
-	struct wlan_frame_hdr *wh;
-	struct qdf_mac_addr bssid;
-
-	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, candidate->vdev_id,
-						    WLAN_MLME_CM_ID);
-	if (!vdev) {
-		mlme_err("vdev object is NULL");
-		return QDF_STATUS_E_NULL_VALUE;
-	}
-
-	pdev = wlan_vdev_get_pdev(vdev);
-	if (!pdev) {
-		mlme_err("pdev object is NULL");
-		goto err;
-	}
-
-	cm_ctx = cm_get_cm_ctx(vdev);
-	if (!cm_ctx) {
-		mlme_err("cm ctx is NULL");
-		goto err;
-	}
-
-	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLME, QDF_TRACE_LEVEL_DEBUG,
-			   candidate->frame, candidate->frame_length);
-	/* Fixed parameters offset */
-	ie_offset = sizeof(struct wlan_frame_hdr) + MAC_B_PR_SSID_OFFSET;
-
-	if (candidate->frame_length <= ie_offset) {
-		mlme_err("Invalid frame length");
-		goto err;
-	}
-
-	ie_ptr = candidate->frame + ie_offset;
-	ie_len = candidate->frame_length - ie_offset;
-
-	extracted_ie = (uint8_t *)wlan_get_ie_ptr_from_eid(WLAN_ELEMID_SSID,
-							   ie_ptr, ie_len);
-	if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_SSID &&
-	    extracted_ie[1] > MIN_IE_LEN) {
-		wh = (struct wlan_frame_hdr *)candidate->frame;
-		WLAN_ADDR_COPY(&bssid.bytes[0], wh->i_addr2);
-
-		mlme_debug("SSID of the candidate is " QDF_SSID_FMT,
-			   QDF_SSID_REF(extracted_ie[1], &extracted_ie[2]));
-		wlan_cm_set_roam_offload_ssid(vdev, &extracted_ie[2],
-					      extracted_ie[1]);
-		wlan_cm_set_roam_offload_bssid(vdev, &bssid);
-	}
-
-	/* For 2.4GHz,5GHz get channel from DS IE */
-	extracted_ie = (uint8_t *)wlan_get_ie_ptr_from_eid(WLAN_ELEMID_DSPARMS,
-							   ie_ptr, ie_len);
-	if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_DSPARMS &&
-	    extracted_ie[1] == WLAN_DS_PARAM_IE_MAX_LEN) {
-		band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G);
-		primary_channel = *(extracted_ie + 2);
-		mlme_debug("Extracted primary channel from DS : %d",
-			   primary_channel);
-		goto update_beacon;
-	}
-
-	/* For HT, VHT and non-6GHz HE, get channel from HTINFO IE */
-	extracted_ie = (uint8_t *)
-			wlan_get_ie_ptr_from_eid(WLAN_ELEMID_HTINFO_ANA,
-						 ie_ptr, ie_len);
-	if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_HTINFO_ANA &&
-	    extracted_ie[1] == sizeof(struct wlan_ie_htinfo_cmn)) {
-		band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G);
-		primary_channel =
-			((struct wlan_ie_htinfo *)extracted_ie)->
-						hi_ie.hi_ctrlchannel;
-		mlme_debug("Extracted primary channel from HT INFO : %d",
-			   primary_channel);
-		goto update_beacon;
-	}
-	/* For 6GHz, get channel from HE OP IE */
-	extracted_ie = (uint8_t *)
-			wlan_get_ext_ie_ptr_from_ext_id(WLAN_HEOP_OUI_TYPE,
-							(uint8_t)
-							WLAN_HEOP_OUI_SIZE,
-							ie_ptr, ie_len);
-	if (extracted_ie && !qdf_mem_cmp(&extracted_ie[2], WLAN_HEOP_OUI_TYPE,
-					 WLAN_HEOP_OUI_SIZE) &&
-	    extracted_ie[1] <= WLAN_MAX_HEOP_IE_LEN) {
-		band = BIT(REG_BAND_6G);
-		primary_channel = util_scan_get_6g_oper_channel(extracted_ie);
-		mlme_debug("Extracted primary channel from HE OP : %d",
-			   primary_channel);
-		if (primary_channel)
-			goto update_beacon;
-	}
-
-	mlme_err("Ignore beacon, Primary channel was not found in the candidate frame");
-	goto err;
-
-update_beacon:
-	op_freq = wlan_reg_chan_band_to_freq(pdev, primary_channel, band);
-	cm_inform_bcn_probe(cm_ctx, candidate->frame, candidate->frame_length,
-			    op_freq,
-			    0, /* Real RSSI will be updated by Roam synch ind */
-			    cm_ctx->active_cm_id);
-
-	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
-	return QDF_STATUS_SUCCESS;
-err:
-	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
-	return QDF_STATUS_E_FAILURE;
-}

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

@@ -1300,6 +1300,20 @@ QDF_STATUS
 wlan_cm_update_offload_ssid_from_candidate(struct wlan_objmgr_pdev *pdev,
 					   uint8_t vdev_id,
 					   struct qdf_mac_addr *ap_bssid);
+
+/**
+ * wlan_cm_add_frame_to_scan_db() - Add the frame to scan db
+ *
+ * @psoc: PSOC pointer
+ * @frame: frame to be added to scan db
+ *
+ * Fetch the channel from frame and add the frame to scan db
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_cm_add_frame_to_scan_db(struct wlan_objmgr_psoc *psoc,
+			     struct roam_scan_candidate_frame *frame);
 #else
 static inline
 void wlan_cm_roam_activate_pcl_per_vdev(struct wlan_objmgr_psoc *psoc,
@@ -1549,6 +1563,12 @@ wlan_cm_update_offload_ssid_from_candidate(struct wlan_objmgr_pdev *pdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+static inline QDF_STATUS
+wlan_cm_add_frame_to_scan_db(struct wlan_objmgr_psoc *psoc,
+			     struct roam_scan_candidate_frame *frame)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
 
 #ifdef WLAN_FEATURE_FIPS

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

@@ -2859,11 +2859,13 @@ struct roam_offload_synch_ind {
  * @vdev_id : vdev id
  * @frame_length : Length of the beacon/probe rsp frame
  * @frame : Pointer to the frame
+ * @rssi: RSSI of the received frame, 0 if not available
  */
 struct roam_scan_candidate_frame {
 	uint8_t vdev_id;
 	uint32_t frame_length;
 	uint8_t *frame;
+	int32_t rssi;
 };
 
 /**

+ 135 - 1
components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c

@@ -36,6 +36,7 @@
 #include "wlan_reg_ucfg_api.h"
 #include "wlan_connectivity_logging.h"
 #include "target_if.h"
+#include "wlan_mlo_mgr_roam.h"
 
 /* Support for "Fast roaming" (i.e., ESE, LFR, or 802.11r.) */
 #define BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN 15
@@ -4678,6 +4679,125 @@ end:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
 	return status;
 }
+
+QDF_STATUS
+wlan_cm_add_frame_to_scan_db(struct wlan_objmgr_psoc *psoc,
+			     struct roam_scan_candidate_frame *frame)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_pdev *pdev;
+	struct cnx_mgr *cm_ctx;
+	uint32_t ie_offset, ie_len;
+	uint8_t *ie_ptr = NULL;
+	uint8_t *extracted_ie = NULL;
+	uint8_t primary_channel, band;
+	qdf_freq_t op_freq;
+	struct wlan_frame_hdr *wh;
+	struct qdf_mac_addr bssid;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, frame->vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev) {
+		mlme_err("vdev object is NULL");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		mlme_err("pdev object is NULL");
+		goto err;
+	}
+
+	cm_ctx = cm_get_cm_ctx(vdev);
+	if (!cm_ctx) {
+		mlme_err("cm ctx is NULL");
+		goto err;
+	}
+
+	/* Fixed parameters offset */
+	ie_offset = sizeof(struct wlan_frame_hdr) + MAC_B_PR_SSID_OFFSET;
+
+	if (frame->frame_length <= ie_offset) {
+		mlme_err("Invalid frame length");
+		goto err;
+	}
+
+	ie_ptr = frame->frame + ie_offset;
+	ie_len = frame->frame_length - ie_offset;
+
+	extracted_ie = (uint8_t *)wlan_get_ie_ptr_from_eid(WLAN_ELEMID_SSID,
+							   ie_ptr, ie_len);
+	if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_SSID &&
+	    extracted_ie[1] > MIN_IE_LEN) {
+		wh = (struct wlan_frame_hdr *)frame->frame;
+		WLAN_ADDR_COPY(&bssid.bytes[0], wh->i_addr2);
+
+		mlme_debug("SSID of the candidate is " QDF_SSID_FMT,
+			   QDF_SSID_REF(extracted_ie[1], &extracted_ie[2]));
+		wlan_cm_set_roam_offload_ssid(vdev, &extracted_ie[2],
+					      extracted_ie[1]);
+		wlan_cm_set_roam_offload_bssid(vdev, &bssid);
+	}
+
+	/* For 2.4GHz,5GHz get channel from DS IE */
+	extracted_ie = (uint8_t *)wlan_get_ie_ptr_from_eid(WLAN_ELEMID_DSPARMS,
+							   ie_ptr, ie_len);
+	if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_DSPARMS &&
+	    extracted_ie[1] == WLAN_DS_PARAM_IE_MAX_LEN) {
+		band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G);
+		primary_channel = *(extracted_ie + 2);
+		mlme_debug("Extracted primary channel from DS : %d",
+			   primary_channel);
+		goto update_beacon;
+	}
+
+	/* For HT, VHT and non-6GHz HE, get channel from HTINFO IE */
+	extracted_ie = (uint8_t *)
+			wlan_get_ie_ptr_from_eid(WLAN_ELEMID_HTINFO_ANA,
+						 ie_ptr, ie_len);
+	if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_HTINFO_ANA &&
+	    extracted_ie[1] == sizeof(struct wlan_ie_htinfo_cmn)) {
+		band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G);
+		primary_channel =
+			((struct wlan_ie_htinfo *)extracted_ie)->
+						hi_ie.hi_ctrlchannel;
+		mlme_debug("Extracted primary channel from HT INFO : %d",
+			   primary_channel);
+		goto update_beacon;
+	}
+	/* For 6GHz, get channel from HE OP IE */
+	extracted_ie = (uint8_t *)
+			wlan_get_ext_ie_ptr_from_ext_id(WLAN_HEOP_OUI_TYPE,
+							(uint8_t)
+							WLAN_HEOP_OUI_SIZE,
+							ie_ptr, ie_len);
+	if (extracted_ie && !qdf_mem_cmp(&extracted_ie[2], WLAN_HEOP_OUI_TYPE,
+					 WLAN_HEOP_OUI_SIZE) &&
+	    extracted_ie[1] <= WLAN_MAX_HEOP_IE_LEN) {
+		band = BIT(REG_BAND_6G);
+		primary_channel = util_scan_get_6g_oper_channel(extracted_ie);
+		mlme_debug("Extracted primary channel from HE OP : %d",
+			   primary_channel);
+		if (primary_channel)
+			goto update_beacon;
+	}
+
+	mlme_err("Ignore beacon, Primary channel was not found in the candidate frame");
+	goto err;
+
+update_beacon:
+	op_freq = wlan_reg_chan_band_to_freq(pdev, primary_channel, band);
+	cm_inform_bcn_probe(cm_ctx, frame->frame, frame->frame_length,
+			    op_freq,
+			    frame->rssi,
+			    cm_ctx->active_cm_id);
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+	return QDF_STATUS_SUCCESS;
+err:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+	return QDF_STATUS_E_FAILURE;
+}
 #endif
 
 #ifdef WLAN_FEATURE_11BE_MLO
@@ -4812,4 +4932,18 @@ bool wlan_cm_roam_is_mlo_ap(struct wlan_objmgr_vdev *vdev)
 
 	return rso_config->sae_roam_auth.is_mlo_ap;
 }
-#endif /* WLAN_FEATURE_ROAM_OFFLOAD && WLAN_FEATURE_11BE_MLO */
+
+QDF_STATUS
+cm_roam_candidate_event_handler(struct wlan_objmgr_psoc *psoc,
+				struct roam_scan_candidate_frame *candidate)
+{
+	return mlo_add_all_link_probe_rsp_to_scan_db(psoc, candidate);
+}
+#elif defined(WLAN_FEATURE_ROAM_OFFLOAD) /* end WLAN_FEATURE_11BE_MLO */
+QDF_STATUS
+cm_roam_candidate_event_handler(struct wlan_objmgr_psoc *psoc,
+				struct roam_scan_candidate_frame *candidate)
+{
+	return wlan_cm_add_frame_to_scan_db(psoc, candidate);
+}
+#endif /* WLAN_FEATURE_ROAM_OFFLOAD */

+ 15 - 0
components/umac/mlme/mlo_mgr/inc/wlan_mlo_mgr_roam.h

@@ -408,6 +408,21 @@ mlo_roam_set_link_id(struct wlan_objmgr_vdev *vdev,
 bool
 mlo_is_roaming_in_progress(struct wlan_objmgr_psoc *psoc,
 			   uint8_t vdev_id);
+
+/**
+ * mlo_add_all_link_probe_rsp_to_scan_db - Extract and add all ML link probe
+ * rsps to scan db
+ * @psoc: psoc pointer
+ * @rcvd_frame: Received frame from firmware
+ *
+ * This api will be called to generate ML probe responses corresponds to each
+ * link from the received probe response and add them to scan db
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+mlo_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc,
+			      struct roam_scan_candidate_frame *rcvd_frame);
 #else /* WLAN_FEATURE_11BE_MLO */
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
 static inline

+ 89 - 0
components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c

@@ -30,6 +30,7 @@
 #include "wlan_mlme_vdev_mgr_interface.h"
 #include <include/wlan_mlme_cmn.h>
 #include <wlan_cm_api.h>
+#include <utils_mlo.h>
 
 #ifdef WLAN_FEATURE_11BE_MLO
 static bool
@@ -1364,3 +1365,91 @@ end:
 	return is_roaming_in_progress;
 }
 
+QDF_STATUS
+mlo_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc,
+			struct roam_scan_candidate_frame *rcvd_frame)
+{
+	uint8_t *ml_ie, link_id, idx, ies_offset;
+	qdf_size_t ml_ie_total_len, gen_frame_len;
+	QDF_STATUS status;
+	struct mlo_partner_info ml_partner_info = {0};
+	struct element_info rcvd_probe_rsp, gen_probe_rsp = {0, NULL};
+	struct roam_scan_candidate_frame entry = {0};
+	struct qdf_mac_addr self_link_addr;
+	struct wlan_objmgr_vdev *vdev;
+
+	/* Add the received scan entry as it is */
+	wlan_cm_add_frame_to_scan_db(psoc, rcvd_frame);
+
+	ies_offset = WLAN_MAC_HDR_LEN_3A + WLAN_PROBE_RESP_IES_OFFSET;
+	if (rcvd_frame->frame_length < ies_offset) {
+		mlme_err("No IEs in probe rsp");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = util_find_mlie(rcvd_frame->frame + ies_offset,
+				rcvd_frame->frame_length - ies_offset,
+				&ml_ie, &ml_ie_total_len);
+	if (QDF_IS_STATUS_ERROR(status))
+		return QDF_STATUS_SUCCESS;
+
+	status = util_get_bvmlie_persta_partner_info(ml_ie,
+						     ml_ie_total_len,
+						     &ml_partner_info);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlme_err("Per STA profile parsing failed");
+		return status;
+	}
+
+	gen_frame_len = MAX_MGMT_MPDU_LEN;
+
+	gen_probe_rsp.ptr = qdf_mem_malloc(gen_frame_len);
+	if (!gen_probe_rsp.ptr)
+		return QDF_STATUS_E_NOMEM;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rcvd_frame->vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev) {
+		mlme_err("vdev object is NULL");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto done;
+	}
+	qdf_mem_copy(self_link_addr.bytes,
+		     wlan_vdev_mlme_get_macaddr(vdev),
+		     QDF_MAC_ADDR_SIZE);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+
+	rcvd_probe_rsp.ptr = rcvd_frame->frame + WLAN_MAC_HDR_LEN_3A;
+	rcvd_probe_rsp.len = rcvd_frame->frame_length - WLAN_MAC_HDR_LEN_3A;
+
+	for (idx = 0; idx < ml_partner_info.num_partner_links; idx++) {
+		link_id = ml_partner_info.partner_link_info[idx].link_id;
+		status = util_gen_link_probe_rsp(rcvd_probe_rsp.ptr,
+				rcvd_probe_rsp.len,
+				link_id,
+				self_link_addr,
+				gen_probe_rsp.ptr,
+				gen_frame_len,
+				(qdf_size_t *)&gen_probe_rsp.len);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			mlme_err("MLO: Link %d probe resp gen failed %d",
+				 link_id, status);
+			status = QDF_STATUS_E_FAILURE;
+			goto done;
+		}
+
+		mlme_debug("MLO: link probe rsp size:%u orig probe rsp :%u",
+			   gen_probe_rsp.len, rcvd_probe_rsp.len);
+
+		entry.vdev_id = rcvd_frame->vdev_id;
+		entry.frame = gen_probe_rsp.ptr;
+		entry.frame_length = gen_probe_rsp.len;
+		entry.rssi = rcvd_frame->rssi;
+
+		wlan_cm_add_frame_to_scan_db(psoc, &entry);
+	}
+done:
+	qdf_mem_free(gen_probe_rsp.ptr);
+
+	return status;
+}

+ 2 - 0
components/wmi/src/wmi_unified_roam_tlv.c

@@ -3457,6 +3457,8 @@ extract_roam_candidate_frame_tlv(wmi_unified_t wmi_handle, uint8_t *event,
 	data->vdev_id = frame_params->vdev_id;
 	data->frame_length = frame_params->frame_length;
 	data->frame = (uint8_t *)param_buf->frame;
+	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG,
+			   data->frame, data->frame_length);
 
 	return QDF_STATUS_SUCCESS;
 }

+ 101 - 75
core/mac/src/pe/lim/lim_api.c

@@ -4192,6 +4192,8 @@ lim_gen_link_probe_rsp_roam(struct mac_context *mac_ctx,
 	struct wlan_frame_hdr *hdr;
 	uint16_t gen_frame_len;
 	uint32_t idx, link_id, ml_probe_link_id;
+	struct roam_scan_candidate_frame rcvd_frame;
+	qdf_freq_t freq;
 
 	if (!session || !roam_sync_ind)
 		return QDF_STATUS_E_NULL_VALUE;
@@ -4233,97 +4235,121 @@ lim_gen_link_probe_rsp_roam(struct mac_context *mac_ctx,
 		return QDF_STATUS_E_INVAL;
 	}
 
-	if (probe_rsp->mlo_ie.mlo_ie_present) {
-		/* Add received ml bcn/probe rsp to scan db */
-		src_addr = wlan_mlme_get_src_addr_from_frame(&frame);
-		if (!src_addr) {
-			pe_err("MLO: Failed to fetch src address");
-			status = QDF_STATUS_E_FAILURE;
-			goto done;
-		}
-		lim_add_bcn_probe(session->vdev, frame.ptr, frame.len,
-				  mlo_roam_get_link_freq_from_mac_addr(
-					       roam_sync_ind, src_addr),
-				  roam_sync_ind->rssi);
-		/*
-		 * When STA roams to an MLO AP, non-assoc link might be superior
-		 * in features compared to  assoc link and the per-STA profile
-		 * info may carry corresponding IEs. These IEs are extracted
-		 * and added to IE list of link probe response while generating
-		 * it. So, the link probe response generated from assoc link
-		 * probe response might be of more size than assoc link probe
-		 * rsp. Allocate buffer for the bss descriptor to accommodate
-		 * all of the IEs got generated as part of link probe rsp
-		 * generation. Allocate MAX_MGMT_MPDU_LEN bytes for IEs as the
-		 * max frame size that can be received from AP is
-		 * MAX_MGMT_MPDU_LEN bytes.
-		 */
-		gen_frame_len = MAX_MGMT_MPDU_LEN;
+	if (!probe_rsp->mlo_ie.mlo_ie_present)
+		goto done;
 
-		gen_probe_rsp.ptr = qdf_mem_malloc(gen_frame_len);
-		if (!gen_probe_rsp.ptr) {
-			qdf_mem_free(probe_rsp);
-			return QDF_STATUS_E_NOMEM;
-		}
+	/* Add received ml bcn/probe rsp to scan db */
+	src_addr = wlan_mlme_get_src_addr_from_frame(&frame);
+	if (!src_addr) {
+		pe_err("MLO: Failed to fetch src address");
+		status = QDF_STATUS_E_FAILURE;
+		goto done;
+	}
+	freq = mlo_roam_get_link_freq_from_mac_addr(roam_sync_ind,
+						    src_addr);
+	/*
+	 * Frequency corresponds to a link mac address might not be
+	 * present in the ml roam info if firmware hadn't roamed to
+	 * the link where ML probe response is received. It might have
+	 * roamed to other links. This happens frequently when roamed
+	 * to a 3-link(2+5+6) AP. As STA can do only 2-link association,
+	 * it chooses best two links(5+6) due to scoring but it might
+	 * have got ML probe response from 2ghz link.
+	 */
+	if (!freq) {
+		pe_debug("MLO: Failed to fetch freq");
+		status = QDF_STATUS_E_FAILURE;
+		goto done;
+	}
+	lim_add_bcn_probe(session->vdev, frame.ptr, frame.len,
+			  freq, roam_sync_ind->rssi);
+	/*
+	 * When STA roams to an MLO AP, non-assoc link might be superior
+	 * in features compared to  assoc link and the per-STA profile
+	 * info may carry corresponding IEs. These IEs are extracted
+	 * and added to IE list of link probe response while generating
+	 * it. So, the link probe response generated from assoc link
+	 * probe response might be of more size than assoc link probe
+	 * rsp. Allocate buffer for the bss descriptor to accommodate
+	 * all of the IEs got generated as part of link probe rsp
+	 * generation. Allocate MAX_MGMT_MPDU_LEN bytes for IEs as the
+	 * max frame size that can be received from AP is
+	 * MAX_MGMT_MPDU_LEN bytes.
+	 */
+	gen_frame_len = MAX_MGMT_MPDU_LEN;
 
-		/*
-		 * It's ok to keep assoc vdev mac address as DA as link vdev
-		 * is just cleanedup and it may not be an ML vdev till the
-		 * flags are set again
-		 */
-		qdf_mem_copy(&sta_link_addr, session->self_mac_addr,
-			     QDF_MAC_ADDR_SIZE);
+	gen_probe_rsp.ptr = qdf_mem_malloc(gen_frame_len);
+	if (!gen_probe_rsp.ptr) {
+		qdf_mem_free(probe_rsp);
+		status = QDF_STATUS_E_NOMEM;
+		goto done;
+	}
 
-		gen_probe_rsp.len = gen_frame_len;
-		src_addr = wlan_mlme_get_src_addr_from_frame(&frame);
-		status = mlo_roam_get_link_id_from_mac_addr(roam_sync_ind,
-							    src_addr,
-							    &ml_probe_link_id);
-		if (QDF_IS_STATUS_ERROR(status)) {
-			pe_debug("Invalid link id for mac_addr: " QDF_MAC_ADDR_FMT,
-				 src_addr);
-			goto done;
-		}
-		for (idx = 0; idx < roam_sync_ind->num_setup_links; idx++) {
-			link_id =  roam_sync_ind->ml_link[idx].link_id;
-			if (link_id == ml_probe_link_id)
-				continue;
-			status = util_gen_link_probe_rsp(rcvd_probe_rsp.ptr,
+	/*
+	 * It's ok to keep assoc vdev mac address as DA as link vdev
+	 * is just cleanedup and it may not be an ML vdev till the
+	 * flags are set again
+	 */
+	qdf_mem_copy(&sta_link_addr, session->self_mac_addr,
+		     QDF_MAC_ADDR_SIZE);
+
+	gen_probe_rsp.len = gen_frame_len;
+	src_addr = wlan_mlme_get_src_addr_from_frame(&frame);
+	status = mlo_roam_get_link_id_from_mac_addr(roam_sync_ind,
+						    src_addr,
+						    &ml_probe_link_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_debug("Invalid link id for mac_addr: " QDF_MAC_ADDR_FMT,
+			 src_addr);
+		goto done;
+	}
+	for (idx = 0; idx < roam_sync_ind->num_setup_links; idx++) {
+		link_id =  roam_sync_ind->ml_link[idx].link_id;
+		if (link_id == ml_probe_link_id)
+			continue;
+		status = util_gen_link_probe_rsp(rcvd_probe_rsp.ptr,
 					rcvd_probe_rsp.len,
 					link_id,
 					sta_link_addr,
 					gen_probe_rsp.ptr,
 					gen_frame_len,
 					(qdf_size_t *)&gen_probe_rsp.len);
-			if (QDF_IS_STATUS_ERROR(status)) {
-				pe_err("MLO: Link %d probe resp gen failed %d",
-				       link_id, status);
-				status = QDF_STATUS_E_FAILURE;
-				goto done;
-			}
+		if (QDF_IS_STATUS_ERROR(status)) {
+			pe_err("MLO: Link %d probe resp gen failed %d",
+			       link_id, status);
+			status = QDF_STATUS_E_FAILURE;
+			goto done;
+		}
 
-			pe_debug("MLO: link probe rsp size:%u orig probe rsp :%u",
-				 gen_probe_rsp.len, rcvd_probe_rsp.len);
+		pe_debug("MLO: link probe rsp size:%u orig probe rsp :%u",
+			 gen_probe_rsp.len, rcvd_probe_rsp.len);
 
-			src_addr = wlan_mlme_get_src_addr_from_frame(
-							&gen_probe_rsp);
-			if (!src_addr) {
-				pe_err("MLO: Failed to fetch src address");
-				status = QDF_STATUS_E_FAILURE;
-				goto done;
-			}
-			lim_add_bcn_probe(session->vdev, gen_probe_rsp.ptr,
-					  gen_probe_rsp.len,
-					  mlo_roam_get_link_freq_from_mac_addr(
-						       roam_sync_ind, src_addr),
-					  roam_sync_ind->rssi);
+		src_addr = wlan_mlme_get_src_addr_from_frame(
+						&gen_probe_rsp);
+		if (!src_addr) {
+			pe_err("MLO: Failed to fetch src address");
+			status = QDF_STATUS_E_FAILURE;
+			goto done;
 		}
+		lim_add_bcn_probe(session->vdev, gen_probe_rsp.ptr,
+				  gen_probe_rsp.len,
+				  mlo_roam_get_link_freq_from_mac_addr(
+					       roam_sync_ind, src_addr),
+				  roam_sync_ind->rssi);
 	}
 
 done:
-	if (gen_probe_rsp.ptr)
-		qdf_mem_free(gen_probe_rsp.ptr);
+	qdf_mem_free(gen_probe_rsp.ptr);
 	qdf_mem_free(probe_rsp);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		rcvd_frame.vdev_id = roam_sync_ind->roamed_vdev_id;
+		rcvd_frame.frame = frame.ptr;
+		rcvd_frame.frame_length = frame.len;
+		rcvd_frame.rssi = roam_sync_ind->rssi;
+		status = mlo_add_all_link_probe_rsp_to_scan_db(mac_ctx->psoc,
+							       &rcvd_frame);
+	}
 	return status;
 }