Преглед на файлове

qcacld-3.0: Copy link beacon from sync frame event to roam_sync_ind

When firmware attempts roaming to an MLO AP, it tries to find
the complete ML info(all links info) either through ML probe
response or beacons from all the links. It forwards all link
beacons(or ML probe response) to host as part of roam sync
indication through roam sync frame event.
Add support to fetch both link beacons and add them to scan db.
If firmware sends ML probe response, generate link probe response
as well and add it to the scan db.
The link scan result can be used in link connect in case of
hybrid roaming like OWE, 1x,..

Change-Id: Ic8457a5630441d6fd3faeb4791c79422db787f94
CRs-Fixed: 3335225
Srinivas Dasari преди 2 години
родител
ревизия
7324535b01

+ 5 - 0
components/target_if/connection_mgr/src/target_if_cm_roam_event.c

@@ -181,6 +181,11 @@ target_if_free_roam_synch_frame_ind(struct roam_synch_frame_ind *frame_ind)
 		frame_ind->bcn_probe_rsp_len = 0;
 		frame_ind->bcn_probe_rsp = NULL;
 	}
+	if (frame_ind->link_bcn_probe_rsp) {
+		qdf_mem_free(frame_ind->link_bcn_probe_rsp);
+		frame_ind->link_bcn_probe_rsp_len = 0;
+		frame_ind->link_bcn_probe_rsp = NULL;
+	}
 	if (frame_ind->reassoc_req) {
 		qdf_mem_free(frame_ind->reassoc_req);
 		frame_ind->reassoc_req_len = 0;

+ 56 - 7
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c

@@ -298,6 +298,22 @@ cm_populate_connect_ies(struct roam_offload_synch_ind *roam_synch_data,
 			     connect_ies->bcn_probe_rsp.len);
 	}
 
+	/* Beacon/Probe Rsp frame */
+	if (roam_synch_data->link_beacon_probe_resp_length) {
+		connect_ies->link_bcn_probe_rsp.len =
+			roam_synch_data->link_beacon_probe_resp_length;
+		bcn_probe_rsp_ptr = (uint8_t *)roam_synch_data +
+				roam_synch_data->link_beacon_probe_resp_offset;
+
+		connect_ies->link_bcn_probe_rsp.ptr =
+			qdf_mem_malloc(connect_ies->link_bcn_probe_rsp.len);
+		if (!connect_ies->link_bcn_probe_rsp.ptr)
+			return QDF_STATUS_E_NOMEM;
+		qdf_mem_copy(connect_ies->link_bcn_probe_rsp.ptr,
+			     bcn_probe_rsp_ptr,
+			     connect_ies->link_bcn_probe_rsp.len);
+	}
+
 	/* ReAssoc Rsp IE data */
 	if (roam_synch_data->reassocRespLength >
 	    sizeof(struct wlan_frame_hdr)) {
@@ -792,21 +808,49 @@ end:
 static void
 cm_update_scan_db_on_roam_success(struct wlan_objmgr_vdev *vdev,
 				  struct wlan_cm_connect_resp *resp,
-				  struct roam_offload_synch_ind *roam_synch_data,
+				  struct roam_offload_synch_ind *roam_synch_ind,
 				  wlan_cm_id cm_id)
 {
 	struct cnx_mgr *cm_ctx;
+	qdf_freq_t link_freq;
+	struct wlan_connect_rsp_ies *ies = &resp->connect_ies;
 
 	cm_ctx = cm_get_cm_ctx(vdev);
 	if (!cm_ctx)
 		return;
 
-	cm_inform_bcn_probe(cm_ctx,
-			    resp->connect_ies.bcn_probe_rsp.ptr,
-			    resp->connect_ies.bcn_probe_rsp.len,
-			    resp->freq,
-			    roam_synch_data->rssi,
-			    cm_id);
+	link_freq = mlo_roam_get_chan_freq(wlan_vdev_get_id(vdev),
+					   roam_synch_ind);
+	if (roam_synch_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) {
+		if (ies->link_bcn_probe_rsp.len)
+			cm_inform_bcn_probe(cm_ctx,
+					    ies->link_bcn_probe_rsp.ptr,
+					    ies->link_bcn_probe_rsp.len,
+					    link_freq,
+					    roam_synch_ind->rssi,
+					    cm_id);
+		cm_inform_bcn_probe(cm_ctx,
+				    ies->bcn_probe_rsp.ptr,
+				    ies->bcn_probe_rsp.len,
+				    resp->freq,
+				    roam_synch_ind->rssi,
+				    cm_id);
+	} else if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) {
+		if (ies->link_bcn_probe_rsp.len)
+			cm_inform_bcn_probe(cm_ctx,
+					    ies->link_bcn_probe_rsp.ptr,
+					    ies->link_bcn_probe_rsp.len,
+					    link_freq,
+					    roam_synch_ind->rssi,
+					    cm_id);
+	} else {
+		cm_inform_bcn_probe(cm_ctx,
+				    ies->bcn_probe_rsp.ptr,
+				    ies->bcn_probe_rsp.len,
+				    resp->freq,
+				    roam_synch_ind->rssi,
+				    cm_id);
+	}
 
 	cm_update_scan_mlme_on_roam(vdev, &resp->bssid,
 				    SCAN_ENTRY_CON_STATE_ASSOC);
@@ -1306,6 +1350,11 @@ QDF_STATUS wlan_cm_free_roam_synch_frame_ind(struct rso_config *rso_cfg)
 		frame_ind->bcn_probe_rsp_len = 0;
 		frame_ind->bcn_probe_rsp = NULL;
 	}
+	if (frame_ind->link_bcn_probe_rsp) {
+		qdf_mem_free(frame_ind->link_bcn_probe_rsp);
+		frame_ind->link_bcn_probe_rsp_len = 0;
+		frame_ind->link_bcn_probe_rsp = NULL;
+	}
 	if (frame_ind->reassoc_req) {
 		qdf_mem_free(frame_ind->reassoc_req);
 		frame_ind->reassoc_req_len = 0;

+ 23 - 1
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c

@@ -422,6 +422,17 @@ cm_roam_sync_frame_event_handler(struct wlan_objmgr_psoc *psoc,
 			sync_frame_ind->bcn_probe_rsp;
 	}
 
+	if (sync_frame_ind->link_bcn_probe_rsp_len) {
+		roam_synch_frame_ind->link_bcn_probe_rsp_len =
+			sync_frame_ind->link_bcn_probe_rsp_len;
+		roam_synch_frame_ind->is_link_beacon =
+			sync_frame_ind->is_link_beacon;
+		if (roam_synch_frame_ind->link_bcn_probe_rsp)
+			qdf_mem_free(roam_synch_frame_ind->link_bcn_probe_rsp);
+		roam_synch_frame_ind->link_bcn_probe_rsp =
+			sync_frame_ind->link_bcn_probe_rsp;
+	}
+
 	if (sync_frame_ind->reassoc_req_len) {
 		roam_synch_frame_ind->reassoc_req_len =
 				sync_frame_ind->reassoc_req_len;
@@ -504,7 +515,18 @@ QDF_STATUS cm_roam_sync_event_handler_cb(struct wlan_objmgr_vdev *vdev,
 	}
 
 	/* 24 byte MAC header and 12 byte to ssid IE */
-	if (sync_ind->beaconProbeRespLength >
+	if (wlan_vdev_mlme_is_mlo_link_vdev(vdev) &&
+	    sync_ind->link_beacon_probe_resp_length) {
+		if (sync_ind->link_beacon_probe_resp_length >
+		    (QDF_IEEE80211_3ADDR_HDR_LEN + MAC_B_PR_SSID_OFFSET)) {
+			ie_len = sync_ind->link_beacon_probe_resp_length -
+					(QDF_IEEE80211_3ADDR_HDR_LEN +
+					 MAC_B_PR_SSID_OFFSET);
+		} else {
+			mlme_err("LFR3: MLO: Invalid link Beacon Length");
+			goto err;
+		}
+	} else if (sync_ind->beaconProbeRespLength >
 			(QDF_IEEE80211_3ADDR_HDR_LEN + MAC_B_PR_SSID_OFFSET)) {
 		ie_len = sync_ind->beaconProbeRespLength -
 			(QDF_IEEE80211_3ADDR_HDR_LEN + MAC_B_PR_SSID_OFFSET);

+ 1 - 0
components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c

@@ -1671,6 +1671,7 @@ void wlan_cm_free_connect_rsp(struct cm_vdev_join_rsp *rsp)
 
 	qdf_mem_free(connect_ie->assoc_req.ptr);
 	qdf_mem_free(connect_ie->bcn_probe_rsp.ptr);
+	qdf_mem_free(connect_ie->link_bcn_probe_rsp.ptr);
 	qdf_mem_free(connect_ie->assoc_rsp.ptr);
 	cm_free_fils_ie(connect_ie);
 	cm_free_tspec_ie(rsp);

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

@@ -440,6 +440,9 @@ struct roam_synch_frame_ind {
 	uint32_t bcn_probe_rsp_len;
 	uint8_t *bcn_probe_rsp;
 	uint8_t is_beacon;
+	uint32_t link_bcn_probe_rsp_len;
+	uint8_t *link_bcn_probe_rsp;
+	uint8_t is_link_beacon;
 	uint32_t reassoc_req_len;
 	uint8_t *reassoc_req;
 	uint32_t reassoc_rsp_len;
@@ -2588,6 +2591,9 @@ struct roam_offload_synch_ind {
 	uint8_t is_assoc;
 	enum wlan_phymode phy_mode; /*phy mode sent by fw */
 	wmi_channel chan;
+	uint16_t link_beacon_probe_resp_offset;
+	uint16_t link_beacon_probe_resp_length;
+	uint8_t is_link_beacon;
 #ifdef WLAN_FEATURE_11BE_MLO
 	uint8_t num_setup_links;
 	struct ml_setup_link_param ml_link[WLAN_UMAC_MLO_MAX_VDEVS];

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

@@ -91,6 +91,20 @@ uint32_t
 mlo_roam_get_chan_freq(uint8_t vdev_id,
 		       struct roam_offload_synch_ind *sync_ind);
 
+/**
+ * mlo_roam_get_link_freq - get given link frequency
+ *
+ * @vdev_id: vdev id
+ * @sync_ind: roam sync ind pointer
+ *
+ * This api will be called to get the link frequency.
+ *
+ * Return: channel frequency
+ */
+uint32_t
+mlo_roam_get_link_freq(uint8_t vdev_id,
+		       struct roam_offload_synch_ind *sync_ind);
+
 /**
  * mlo_roam_get_link_id - get link id
  *

+ 18 - 1
components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c

@@ -396,6 +396,23 @@ bool is_multi_link_roam(struct roam_offload_synch_ind *sync_ind)
 	return false;
 }
 
+uint32_t
+mlo_roam_get_link_freq(uint8_t vdev_id,
+		       struct roam_offload_synch_ind *sync_ind)
+{
+	uint8_t i;
+
+	if (!sync_ind || !sync_ind->num_setup_links)
+		return 0;
+
+	for (i = 0; i < sync_ind->num_setup_links; i++) {
+		if (sync_ind->ml_link[i].vdev_id != vdev_id)
+			return sync_ind->ml_link[i].channel.mhz;
+	}
+
+	return 0;
+}
+
 QDF_STATUS mlo_enable_rso(struct wlan_objmgr_pdev *pdev,
 			  struct wlan_objmgr_vdev *vdev,
 			  struct wlan_cm_connect_resp *rsp)
@@ -440,7 +457,7 @@ mlo_roam_copy_partner_info(struct wlan_cm_connect_resp *connect_rsp,
 	for (i = 0; i < sync_ind->num_setup_links; i++) {
 		partner_info->partner_link_info[i].link_id =
 			sync_ind->ml_link[i].link_id;
-	       partner_info->partner_link_info[i].vdev_id =
+		partner_info->partner_link_info[i].vdev_id =
 			sync_ind->ml_link[i].vdev_id;
 
 		qdf_copy_macaddr(

+ 115 - 70
components/wmi/src/wmi_unified_roam_tlv.c

@@ -2102,7 +2102,7 @@ static void
 wmi_fill_data_synch_frame_event(struct rso_config *rso_cfg,
 				struct roam_offload_synch_ind *roam_sync_ind)
 {
-	uint8_t *bcn_probersp_ptr;
+	uint8_t *bcn_probersp_ptr, *link_bcn_probersp_ptr;
 	uint8_t *reassoc_rsp_ptr;
 	uint8_t *reassoc_req_ptr;
 
@@ -2119,10 +2119,29 @@ wmi_fill_data_synch_frame_event(struct rso_config *rso_cfg,
 	qdf_mem_free(rso_cfg->roam_sync_frame_ind.bcn_probe_rsp);
 	rso_cfg->roam_sync_frame_ind.bcn_probe_rsp = NULL;
 
+	/* Link beacon/probe rsp data */
+	if (rso_cfg->roam_sync_frame_ind.link_bcn_probe_rsp) {
+		roam_sync_ind->link_beacon_probe_resp_offset =
+			sizeof(struct roam_offload_synch_ind) +
+			roam_sync_ind->beaconProbeRespLength;
+		roam_sync_ind->link_beacon_probe_resp_length =
+			rso_cfg->roam_sync_frame_ind.link_bcn_probe_rsp_len;
+		roam_sync_ind->is_link_beacon =
+			rso_cfg->roam_sync_frame_ind.is_link_beacon;
+		link_bcn_probersp_ptr = (uint8_t *)roam_sync_ind +
+				  roam_sync_ind->link_beacon_probe_resp_offset;
+		qdf_mem_copy(link_bcn_probersp_ptr,
+			     rso_cfg->roam_sync_frame_ind.link_bcn_probe_rsp,
+			     roam_sync_ind->link_beacon_probe_resp_length);
+		qdf_mem_free(rso_cfg->roam_sync_frame_ind.link_bcn_probe_rsp);
+		rso_cfg->roam_sync_frame_ind.link_bcn_probe_rsp = NULL;
+	}
+
 	/* ReAssoc Rsp data */
 	roam_sync_ind->reassocRespOffset =
 		sizeof(struct roam_offload_synch_ind) +
-		roam_sync_ind->beaconProbeRespLength;
+		roam_sync_ind->beaconProbeRespLength +
+		roam_sync_ind->link_beacon_probe_resp_length;
 	roam_sync_ind->reassocRespLength =
 		rso_cfg->roam_sync_frame_ind.reassoc_rsp_len;
 	reassoc_rsp_ptr = (uint8_t *)roam_sync_ind +
@@ -2137,6 +2156,7 @@ wmi_fill_data_synch_frame_event(struct rso_config *rso_cfg,
 	roam_sync_ind->reassoc_req_offset =
 		sizeof(struct roam_offload_synch_ind) +
 		roam_sync_ind->beaconProbeRespLength +
+		roam_sync_ind->link_beacon_probe_resp_length +
 		roam_sync_ind->reassocRespLength;
 	roam_sync_ind->reassoc_req_length =
 		rso_cfg->roam_sync_frame_ind.reassoc_req_len;
@@ -2183,6 +2203,10 @@ wmi_fill_data_synch_event(struct roam_offload_synch_ind *roam_sync_ind,
 		synch_event->bcn_probe_rsp_len;
 	qdf_mem_copy(bcn_probersp_ptr, param_buf->bcn_probe_rsp_frame,
 		     roam_sync_ind->beaconProbeRespLength);
+	/*
+	 * Firmware doesn't support link beacon/Probe Rsp data in roam sync
+	 * event. It's always sent in sync_frame event
+	 */
 	/* ReAssoc Rsp data */
 	roam_sync_ind->reassocRespOffset =
 		sizeof(struct roam_offload_synch_ind) +
@@ -2208,7 +2232,8 @@ wmi_fill_data_synch_event(struct roam_offload_synch_ind *roam_sync_ind,
 
 #ifdef WLAN_FEATURE_11BE_MLO
 static QDF_STATUS
-wmi_fill_roam_mlo_info(WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf,
+wmi_fill_roam_mlo_info(wmi_unified_t wmi_handle,
+		       WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf,
 		       struct roam_offload_synch_ind *roam_sync_ind)
 {
 	uint8_t i;
@@ -2262,7 +2287,8 @@ wmi_fill_roam_mlo_info(WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf,
 }
 #else
 static QDF_STATUS
-wmi_fill_roam_mlo_info(WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf,
+wmi_fill_roam_mlo_info(wmi_unified_t wmi_handle,
+		       WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf,
 		       struct roam_offload_synch_ind *roam_sync_ind)
 {
 	return QDF_STATUS_SUCCESS;
@@ -2270,7 +2296,8 @@ wmi_fill_roam_mlo_info(WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf,
 #endif
 
 static QDF_STATUS
-wmi_fill_roam_sync_buffer(struct wlan_objmgr_vdev *vdev,
+wmi_fill_roam_sync_buffer(wmi_unified_t wmi_handle,
+			  struct wlan_objmgr_vdev *vdev,
 			  struct rso_config *rso_cfg,
 			  struct roam_offload_synch_ind *roam_sync_ind,
 			  WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf)
@@ -2318,6 +2345,7 @@ wmi_fill_roam_sync_buffer(struct wlan_objmgr_vdev *vdev,
 			wlan_cm_free_roam_synch_frame_ind(rso_cfg);
 			return status;
 		}
+
 		if (!rso_cfg->roam_sync_frame_ind.reassoc_rsp) {
 			wmi_err("LFR3: reassoc_rsp is NULL");
 			QDF_ASSERT(rso_cfg->roam_sync_frame_ind.reassoc_rsp);
@@ -2439,7 +2467,7 @@ wmi_fill_roam_sync_buffer(struct wlan_objmgr_vdev *vdev,
 			     pmk_cache_info->pmkid, PMKID_LEN);
 	}
 
-	status = wmi_fill_roam_mlo_info(param_buf, roam_sync_ind);
+	status = wmi_fill_roam_mlo_info(wmi_handle, param_buf, roam_sync_ind);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		wmi_err("Failed to fill roam mlo info");
 		return status;
@@ -2469,7 +2497,7 @@ extract_roam_sync_event_tlv(wmi_unified_t wmi_handle, void *evt_buf,
 	struct wlan_objmgr_psoc *psoc = NULL;
 	struct rso_config *rso_cfg;
 	uint32_t roam_synch_data_len;
-	uint32_t bcn_probe_rsp_len;
+	uint32_t bcn_probe_rsp_len, link_bcn_probe_rsp_len;
 	uint32_t reassoc_rsp_len;
 	uint32_t reassoc_req_len;
 	wmi_pdev_hw_mode_transition_event_fixed_param *hw_mode_trans_param;
@@ -2554,15 +2582,21 @@ extract_roam_sync_event_tlv(wmi_unified_t wmi_handle, void *evt_buf,
 	if ((!synch_event->bcn_probe_rsp_len) &&
 	    (!synch_event->reassoc_req_len) &&
 	    (!synch_event->reassoc_rsp_len)) {
-		bcn_probe_rsp_len = rso_cfg->roam_sync_frame_ind.bcn_probe_rsp_len;
+		bcn_probe_rsp_len =
+			rso_cfg->roam_sync_frame_ind.bcn_probe_rsp_len;
+		link_bcn_probe_rsp_len =
+			rso_cfg->roam_sync_frame_ind.link_bcn_probe_rsp_len;
 		reassoc_req_len = rso_cfg->roam_sync_frame_ind.reassoc_req_len;
 		reassoc_rsp_len = rso_cfg->roam_sync_frame_ind.reassoc_rsp_len;
 
-		roam_synch_data_len = bcn_probe_rsp_len + reassoc_rsp_len +
-			reassoc_req_len + sizeof(struct roam_offload_synch_ind);
+		roam_synch_data_len =
+			bcn_probe_rsp_len + link_bcn_probe_rsp_len +
+			reassoc_rsp_len + reassoc_req_len +
+			sizeof(struct roam_offload_synch_ind);
 
-		wmi_debug("Updated synch payload: LEN bcn:%d, req:%d, rsp:%d",
+		wmi_debug("Updated synch payload: LEN bcn:%d, link bcn: %d req:%d, rsp:%d",
 			  bcn_probe_rsp_len,
+			  link_bcn_probe_rsp_len,
 			  reassoc_req_len,
 			  reassoc_rsp_len);
 	} else {
@@ -2609,7 +2643,7 @@ extract_roam_sync_event_tlv(wmi_unified_t wmi_handle, void *evt_buf,
 	}
 
 	*roam_sync_ind = roam_sync;
-	status = wmi_fill_roam_sync_buffer(vdev, rso_cfg,
+	status = wmi_fill_roam_sync_buffer(wmi_handle, vdev, rso_cfg,
 					   roam_sync, param_buf);
 
 end:
@@ -2638,8 +2672,8 @@ extract_roam_sync_frame_event_tlv(wmi_unified_t wmi_handle, void *event,
 				  struct roam_synch_frame_ind *frame_ptr)
 {
 	WMI_ROAM_SYNCH_FRAME_EVENTID_param_tlvs *param_buf = NULL;
-	struct roam_synch_frame_ind *roam_sync_frame_ind;
-	wmi_roam_synch_frame_event_fixed_param *synch_frame_event;
+	struct roam_synch_frame_ind *frame_ind;
+	wmi_roam_synch_frame_event_fixed_param *frame_evt;
 
 	if (!event) {
 		wmi_err("Event param null");
@@ -2652,16 +2686,14 @@ extract_roam_sync_frame_event_tlv(wmi_unified_t wmi_handle, void *event,
 		return QDF_STATUS_E_NULL_VALUE;
 	}
 
-	synch_frame_event = param_buf->fixed_param;
-
-	if (!synch_frame_event) {
+	frame_evt = param_buf->fixed_param;
+	if (!frame_evt) {
 		wmi_err("received null event data from target");
 		return QDF_STATUS_E_NULL_VALUE;
 	}
 
-	if (synch_frame_event->vdev_id >= WLAN_MAX_VDEVS) {
-		wmi_err("received invalid vdev_id %d",
-			synch_frame_event->vdev_id);
+	if (frame_evt->vdev_id >= WLAN_MAX_VDEVS) {
+		wmi_err("received invalid vdev_id %d", frame_evt->vdev_id);
 		return QDF_STATUS_E_FAILURE;
 	}
 
@@ -2670,82 +2702,95 @@ extract_roam_sync_frame_event_tlv(wmi_unified_t wmi_handle, void *event,
 	 * driver. So Bcn_prb_rsp_len/reassoc_req_len/reassoc_rsp_len can be 0
 	 * in some of the events.
 	 */
-	if (synch_frame_event->bcn_probe_rsp_len >
-	    param_buf->num_bcn_probe_rsp_frame ||
-	    synch_frame_event->reassoc_req_len >
-	    param_buf->num_reassoc_req_frame ||
-	    synch_frame_event->reassoc_rsp_len >
-	    param_buf->num_reassoc_rsp_frame ||
-	    (synch_frame_event->bcn_probe_rsp_len &&
-	    synch_frame_event->bcn_probe_rsp_len < sizeof(struct wlan_frame_hdr)) ||
-	    (synch_frame_event->reassoc_req_len &&
-	    synch_frame_event->reassoc_req_len < sizeof(struct wlan_frame_hdr)) ||
-	    (synch_frame_event->reassoc_rsp_len &&
-	    synch_frame_event->reassoc_rsp_len < sizeof(struct wlan_frame_hdr))) {
+	if (frame_evt->bcn_probe_rsp_len > param_buf->num_bcn_probe_rsp_frame ||
+	    frame_evt->reassoc_req_len > param_buf->num_reassoc_req_frame ||
+	    frame_evt->reassoc_rsp_len > param_buf->num_reassoc_rsp_frame ||
+	    (frame_evt->bcn_probe_rsp_len &&
+	     frame_evt->bcn_probe_rsp_len < sizeof(struct wlan_frame_hdr)) ||
+	    (frame_evt->reassoc_req_len &&
+	     frame_evt->reassoc_req_len < sizeof(struct wlan_frame_hdr)) ||
+	    (frame_evt->reassoc_rsp_len &&
+	     frame_evt->reassoc_rsp_len < sizeof(struct wlan_frame_hdr))) {
 		wmi_err("fixed/actual len err: bcn:%d/%d req:%d/%d rsp:%d/%d",
-			synch_frame_event->bcn_probe_rsp_len,
+			frame_evt->bcn_probe_rsp_len,
 			param_buf->num_bcn_probe_rsp_frame,
-			synch_frame_event->reassoc_req_len,
+			frame_evt->reassoc_req_len,
 			param_buf->num_reassoc_req_frame,
-			synch_frame_event->reassoc_rsp_len,
+			frame_evt->reassoc_rsp_len,
 			param_buf->num_reassoc_rsp_frame);
 		return QDF_STATUS_E_FAILURE;
 	}
 
-	roam_sync_frame_ind = frame_ptr;
-	roam_sync_frame_ind->vdev_id = synch_frame_event->vdev_id;
+	frame_ind = frame_ptr;
+	frame_ind->vdev_id = frame_evt->vdev_id;
+
+	wmi_debug("synch frame payload: LEN %s bcn:%d, req:%d, rsp:%d",
+		  frame_evt->reassoc_rsp_len ? "Assoc" : "Link",
+		  frame_evt->bcn_probe_rsp_len,
+		  frame_evt->reassoc_req_len,
+		  frame_evt->reassoc_rsp_len);
+
+	if (frame_evt->bcn_probe_rsp_len &&
+	    frame_evt->reassoc_rsp_len) {
+		frame_ind->bcn_probe_rsp_len = frame_evt->bcn_probe_rsp_len;
 
-	wmi_debug("synch frame payload: LEN bcn:%d, req:%d, rsp:%d",
-		  synch_frame_event->bcn_probe_rsp_len,
-		  synch_frame_event->reassoc_req_len,
-		  synch_frame_event->reassoc_rsp_len);
+		frame_ind->is_beacon = frame_evt->is_beacon;
+
+		frame_ind->bcn_probe_rsp =
+			qdf_mem_malloc(frame_ind->bcn_probe_rsp_len);
+		if (!frame_ind->bcn_probe_rsp) {
+			QDF_ASSERT(frame_ind->bcn_probe_rsp);
+			return QDF_STATUS_E_NOMEM;
+		}
+		qdf_mem_copy(frame_ind->bcn_probe_rsp,
+			     param_buf->bcn_probe_rsp_frame,
+			     frame_ind->bcn_probe_rsp_len);
+	} else if (frame_evt->bcn_probe_rsp_len) {
+		frame_ind->link_bcn_probe_rsp_len =
+			frame_evt->bcn_probe_rsp_len;
 
-	if (synch_frame_event->bcn_probe_rsp_len) {
-		roam_sync_frame_ind->bcn_probe_rsp_len =
-			synch_frame_event->bcn_probe_rsp_len;
+		frame_ind->is_link_beacon = frame_evt->is_beacon;
 
-		roam_sync_frame_ind->is_beacon =
-			synch_frame_event->is_beacon;
+		if (frame_ind->link_bcn_probe_rsp)
+			qdf_mem_free(frame_ind->bcn_probe_rsp);
 
-		roam_sync_frame_ind->bcn_probe_rsp =
-			qdf_mem_malloc(roam_sync_frame_ind->bcn_probe_rsp_len);
-		if (!roam_sync_frame_ind->bcn_probe_rsp) {
-			QDF_ASSERT(roam_sync_frame_ind->bcn_probe_rsp);
+		frame_ind->link_bcn_probe_rsp =
+			qdf_mem_malloc(frame_ind->link_bcn_probe_rsp_len);
+		if (!frame_ind->link_bcn_probe_rsp) {
+			QDF_ASSERT(frame_ind->link_bcn_probe_rsp);
 			return QDF_STATUS_E_NOMEM;
 		}
-		qdf_mem_copy(roam_sync_frame_ind->bcn_probe_rsp,
+		qdf_mem_copy(frame_ind->link_bcn_probe_rsp,
 			     param_buf->bcn_probe_rsp_frame,
-			     roam_sync_frame_ind->bcn_probe_rsp_len);
+			     frame_ind->link_bcn_probe_rsp_len);
 	}
 
-	if (synch_frame_event->reassoc_req_len) {
-		roam_sync_frame_ind->reassoc_req_len =
-				synch_frame_event->reassoc_req_len;
+	if (frame_evt->reassoc_req_len) {
+		frame_ind->reassoc_req_len = frame_evt->reassoc_req_len;
 
-		roam_sync_frame_ind->reassoc_req =
-			qdf_mem_malloc(roam_sync_frame_ind->reassoc_req_len);
-		if (!roam_sync_frame_ind->reassoc_req) {
-			QDF_ASSERT(roam_sync_frame_ind->reassoc_req);
+		frame_ind->reassoc_req =
+			qdf_mem_malloc(frame_ind->reassoc_req_len);
+		if (!frame_ind->reassoc_req) {
+			QDF_ASSERT(frame_ind->reassoc_req);
 			return QDF_STATUS_E_NOMEM;
 		}
-		qdf_mem_copy(roam_sync_frame_ind->reassoc_req,
+		qdf_mem_copy(frame_ind->reassoc_req,
 			     param_buf->reassoc_req_frame,
-			     roam_sync_frame_ind->reassoc_req_len);
+			     frame_ind->reassoc_req_len);
 	}
 
-	if (synch_frame_event->reassoc_rsp_len) {
-		roam_sync_frame_ind->reassoc_rsp_len =
-				synch_frame_event->reassoc_rsp_len;
+	if (frame_evt->reassoc_rsp_len) {
+		frame_ind->reassoc_rsp_len = frame_evt->reassoc_rsp_len;
 
-		roam_sync_frame_ind->reassoc_rsp =
-			qdf_mem_malloc(roam_sync_frame_ind->reassoc_rsp_len);
-		if (!roam_sync_frame_ind->reassoc_rsp) {
-			QDF_ASSERT(roam_sync_frame_ind->reassoc_rsp);
+		frame_ind->reassoc_rsp =
+			qdf_mem_malloc(frame_ind->reassoc_rsp_len);
+		if (!frame_ind->reassoc_rsp) {
+			QDF_ASSERT(frame_ind->reassoc_rsp);
 			return QDF_STATUS_E_NOMEM;
 		}
-		qdf_mem_copy(roam_sync_frame_ind->reassoc_rsp,
+		qdf_mem_copy(frame_ind->reassoc_rsp,
 			     param_buf->reassoc_rsp_frame,
-			     roam_sync_frame_ind->reassoc_rsp_len);
+			     frame_ind->reassoc_rsp_len);
 	}
 
 	return QDF_STATUS_SUCCESS;

+ 21 - 0
core/mac/src/pe/include/lim_api.h

@@ -595,6 +595,19 @@ lim_gen_link_specific_probe_rsp(struct mac_context *mac_ctx,
  * Return qdf status
  */
 QDF_STATUS lim_check_for_ml_probe_req(struct pe_session *session);
+
+/**
+ * lim_gen_link_probe_rsp_roam() - Generate link prb rsp from assoc link prb rsp
+ * @mac_ctx: Pointer to mac context
+ * @session_entry: pe session
+ * @roam_sync_ind_ptr: Roam synch parameters
+ *
+ * Return qdf status
+ */
+QDF_STATUS
+lim_gen_link_probe_rsp_roam(struct mac_context *mac_ctx,
+			    struct pe_session *session_entry,
+			    struct roam_offload_synch_ind *roam_sync_ind);
 #else
 static inline QDF_STATUS
 lim_gen_link_specific_probe_rsp(struct mac_context *mac_ctx,
@@ -612,6 +625,14 @@ lim_check_for_ml_probe_req(struct pe_session *session)
 {
 	return QDF_STATUS_E_NOSUPPORT;
 }
+
+static inline QDF_STATUS
+lim_gen_link_probe_rsp_roam(struct mac_context *mac_ctx,
+			    struct pe_session *session_entry,
+			    struct roam_offload_synch_ind *roam_sync_ind)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
 #endif
 
 #ifdef WLAN_FEATURE_SR

+ 180 - 42
core/mac/src/pe/lim/lim_api.c

@@ -2073,18 +2073,18 @@ error:
 
 static QDF_STATUS
 lim_roam_gen_beacon_descr(struct mac_context *mac,
+			  uint8_t *bcn_prb_ptr,
+			  uint16_t bcn_prb_len, bool is_mlo_link,
 			  struct roam_offload_synch_ind *roam_ind,
 			  tpSirProbeRespBeacon parsed_frm,
 			  uint8_t **ie, uint32_t *ie_len,
 			  struct qdf_mac_addr *bssid)
 {
 	QDF_STATUS status;
-	uint8_t *bcn_prb_ptr;
 	tpSirMacMgmtHdr mac_hdr;
 	uint8_t ie_offset;
+	bool is_beacon;
 
-	bcn_prb_ptr = (uint8_t *)roam_ind +
-		roam_ind->beaconProbeRespOffset;
 	mac_hdr = (tpSirMacMgmtHdr)bcn_prb_ptr;
 	ie_offset = SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET;
 
@@ -2096,6 +2096,8 @@ lim_roam_gen_beacon_descr(struct mac_context *mac,
 			     sizeof(tSirMacAddr));
 	}
 
+	is_beacon = is_mlo_link ? roam_ind->is_link_beacon : roam_ind->isBeacon;
+
 	if ((!is_multi_link_roam(roam_ind)) &&
 	    (qdf_mem_cmp(bssid->bytes,
 			 &mac_hdr->bssId, QDF_MAC_ADDR_SIZE) != 0)) {
@@ -2116,32 +2118,32 @@ lim_roam_gen_beacon_descr(struct mac_context *mac,
 			return QDF_STATUS_E_FAILURE;
 		}
 	} else {
-		if (roam_ind->isBeacon) {
+		if (is_beacon) {
 			if (sir_parse_beacon_ie(mac, parsed_frm,
 				&bcn_prb_ptr[SIR_MAC_HDR_LEN_3A +
 				SIR_MAC_B_PR_SSID_OFFSET],
-				roam_ind->beaconProbeRespLength -
-				SIR_MAC_HDR_LEN_3A) != QDF_STATUS_SUCCESS ||
-				!parsed_frm->ssidPresent) {
+				bcn_prb_len - SIR_MAC_HDR_LEN_3A) !=
+						QDF_STATUS_SUCCESS ||
+			    !parsed_frm->ssidPresent) {
 				pe_err("Parse error Beacon, length: %d",
-				       roam_ind->beaconProbeRespLength);
+				       bcn_prb_len);
 				return QDF_STATUS_E_FAILURE;
 			}
 		} else {
 			if (sir_convert_probe_frame2_struct(mac,
 				&bcn_prb_ptr[SIR_MAC_HDR_LEN_3A],
-				roam_ind->beaconProbeRespLength -
+				bcn_prb_len -
 				SIR_MAC_HDR_LEN_3A, parsed_frm) !=
 				QDF_STATUS_SUCCESS ||
 				!parsed_frm->ssidPresent) {
 				pe_err("Parse error ProbeResponse, length: %d",
-				       roam_ind->beaconProbeRespLength);
+				       bcn_prb_len);
 				return QDF_STATUS_E_FAILURE;
 			}
 		}
 		/* 24 byte MAC header and 12 byte to ssid IE */
-		if (roam_ind->beaconProbeRespLength > ie_offset) {
-			*ie_len = roam_ind->beaconProbeRespLength - ie_offset;
+		if (bcn_prb_len > ie_offset) {
+			*ie_len = bcn_prb_len - ie_offset;
 			*ie = qdf_mem_malloc(*ie_len);
 			if (!*ie)
 				return QDF_STATUS_E_NOMEM;
@@ -2153,7 +2155,7 @@ lim_roam_gen_beacon_descr(struct mac_context *mac,
 	 * For probe response, unpack core parses beacon interval, capabilities,
 	 * timestamp. For beacon IEs, these fields are not parsed.
 	 */
-	if (roam_ind->isBeacon)
+	if (is_beacon)
 		sir_parse_bcn_fixed_fields(mac, parsed_frm,
 			&bcn_prb_ptr[SIR_MAC_HDR_LEN_3A]);
 
@@ -2164,29 +2166,70 @@ static QDF_STATUS
 lim_roam_fill_bss_descr(struct mac_context *mac,
 			struct roam_offload_synch_ind *roam_synch_ind_ptr,
 			struct bss_description *bss_desc_ptr,
-			uint8_t vdev_id)
+			struct pe_session *session)
 {
 	uint32_t ie_len = 0;
-	tpSirProbeRespBeacon parsed_frm_ptr;
+	tpSirProbeRespBeacon parsed_frm_ptr = NULL;
 	tpSirMacMgmtHdr mac_hdr;
-	uint8_t *bcn_proberesp_ptr;
-	QDF_STATUS status;
+	uint8_t *bcn_proberesp_ptr = NULL;
+	uint16_t bcn_proberesp_len = 0;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	uint8_t *ie = NULL;
 	struct qdf_mac_addr bssid;
+	bool is_mlo_link = false;
+	uint8_t vdev_id = session->vdev_id;
+	struct element_info frame;
+
+	frame.ptr = NULL;
+	frame.len = 0;
+	if (is_multi_link_roam(roam_synch_ind_ptr) &&
+	    wlan_vdev_mlme_get_is_mlo_link(mac->psoc, vdev_id)) {
+		if (roam_synch_ind_ptr->link_beacon_probe_resp_length) {
+			bcn_proberesp_ptr = (uint8_t *)roam_synch_ind_ptr +
+			roam_synch_ind_ptr->link_beacon_probe_resp_offset;
+			bcn_proberesp_len =
+			roam_synch_ind_ptr->link_beacon_probe_resp_length;
+		} else {
+			/*
+			 * This indicates that firmware hasn't sent link beacon,
+			 * which means assoc probe rsp is an ML probe rsp.
+			 * Extract the link probe rsp also from that.
+			 */
+			status = lim_gen_link_probe_rsp_roam(mac,
+						session, roam_synch_ind_ptr);
+			if (QDF_IS_STATUS_ERROR(status))
+				return status;
+			mlo_get_sta_link_mac_addr(vdev_id, roam_synch_ind_ptr,
+						  &bssid);
+			status = wlan_scan_get_entry_by_mac_addr(mac->pdev,
+								 &bssid, &frame);
+			if (QDF_IS_STATUS_ERROR(status) && !frame.len) {
+				pe_err("Failed to get scan entry for " QDF_MAC_ADDR_FMT,
+				       QDF_MAC_ADDR_REF(bssid.bytes));
+				return status;
+			}
+			bcn_proberesp_ptr = frame.ptr;
+			bcn_proberesp_len = frame.len;
+		}
+		is_mlo_link = true;
+	} else {
+		bcn_proberesp_ptr = (uint8_t *)roam_synch_ind_ptr +
+			roam_synch_ind_ptr->beaconProbeRespOffset;
+		bcn_proberesp_len = roam_synch_ind_ptr->beaconProbeRespLength;
+	}
 
-	bcn_proberesp_ptr = (uint8_t *)roam_synch_ind_ptr +
-		roam_synch_ind_ptr->beaconProbeRespOffset;
 	mac_hdr = (tpSirMacMgmtHdr)bcn_proberesp_ptr;
 	parsed_frm_ptr = qdf_mem_malloc(sizeof(tSirProbeRespBeacon));
-	if (!parsed_frm_ptr)
-		return QDF_STATUS_E_NOMEM;
+	if (!parsed_frm_ptr) {
+		status = QDF_STATUS_E_NOMEM;
+		goto done;
+	}
 
-	if (roam_synch_ind_ptr->beaconProbeRespLength <=
-			SIR_MAC_HDR_LEN_3A) {
-		pe_err("very few bytes in synchInd beacon / probe resp frame! length: %d",
-		       roam_synch_ind_ptr->beaconProbeRespLength);
-		qdf_mem_free(parsed_frm_ptr);
-		return QDF_STATUS_E_FAILURE;
+	if (bcn_proberesp_len <= SIR_MAC_HDR_LEN_3A) {
+		pe_err("very few bytes in synchInd %s beacon / probe resp frame! length: %d",
+		       is_mlo_link ? "link" : "", bcn_proberesp_len);
+		status = QDF_STATUS_E_FAILURE;
+		goto done;
 	}
 
 	if (is_multi_link_roam(roam_synch_ind_ptr))
@@ -2196,23 +2239,24 @@ lim_roam_fill_bss_descr(struct mac_context *mac,
 
 	pe_debug("LFR3:Beacon/Prb Rsp: %d bssid " QDF_MAC_ADDR_FMT
 		 " beacon " QDF_MAC_ADDR_FMT,
-		 roam_synch_ind_ptr->isBeacon,
+		 is_mlo_link ? roam_synch_ind_ptr->is_link_beacon :
+			roam_synch_ind_ptr->isBeacon,
 		 QDF_MAC_ADDR_REF(bssid.bytes),
 		 QDF_MAC_ADDR_REF(mac_hdr->bssId));
 
 	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
 			   bcn_proberesp_ptr,
-			   roam_synch_ind_ptr->beaconProbeRespLength);
+			   bcn_proberesp_len);
 
-	status = lim_roam_gen_beacon_descr(mac,
-					   roam_synch_ind_ptr,
-					   parsed_frm_ptr,
+	status = lim_roam_gen_beacon_descr(mac, bcn_proberesp_ptr,
+					   bcn_proberesp_len, is_mlo_link,
+					   roam_synch_ind_ptr, parsed_frm_ptr,
 					   &ie, &ie_len,
 					   &bssid);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		pe_err("Failed to parse beacon");
-		qdf_mem_free(parsed_frm_ptr);
-		return QDF_STATUS_E_FAILURE;
+		status = QDF_STATUS_E_FAILURE;
+		goto done;
 	}
 
 	/*
@@ -2231,7 +2275,9 @@ lim_roam_fill_bss_descr(struct mac_context *mac,
 					   ieFields[0]) -
 				sizeof(bss_desc_ptr->length) + ie_len);
 
-	bss_desc_ptr->fProbeRsp = !roam_synch_ind_ptr->isBeacon;
+	bss_desc_ptr->fProbeRsp = !(is_mlo_link ?
+					roam_synch_ind_ptr->is_link_beacon :
+					roam_synch_ind_ptr->isBeacon);
 	bss_desc_ptr->rssi = roam_synch_ind_ptr->rssi;
 	/* Copy Timestamp */
 	bss_desc_ptr->scansystimensec = qdf_get_monotonic_boottime_ns();
@@ -2290,16 +2336,19 @@ lim_roam_fill_bss_descr(struct mac_context *mac,
 		 bss_desc_ptr->chan_freq,
 		 bss_desc_ptr->rssi, ie_len);
 
-	qdf_mem_free(parsed_frm_ptr);
 	if (ie_len) {
 		qdf_mem_copy(&bss_desc_ptr->ieFields,
 			     ie, ie_len);
 		qdf_mem_free(ie);
 	} else {
 		pe_err("Beacon/Probe rsp doesn't have any IEs");
-		return QDF_STATUS_E_FAILURE;
+		status = QDF_STATUS_E_FAILURE;
+		goto done;
 	}
-	return QDF_STATUS_SUCCESS;
+done:
+	qdf_mem_free(frame.ptr);
+	qdf_mem_free(parsed_frm_ptr);
+	return status;
 }
 
 #if defined(WLAN_FEATURE_FILS_SK)
@@ -2741,7 +2790,7 @@ pe_roam_synch_callback(struct mac_context *mac_ctx,
 	}
 
 	status = lim_roam_fill_bss_descr(mac_ctx, roam_sync_ind_ptr,
-					 bss_desc, vdev_id);
+					 bss_desc, session_ptr);
 	if (!QDF_IS_STATUS_SUCCESS(status)) {
 		pe_err("LFR3:Failed to fill Bss Descr");
 		qdf_mem_free(bss_desc);
@@ -3313,8 +3362,8 @@ lim_cm_fill_link_session(struct mac_context *mac_ctx,
 
 	sir_copy_mac_addr(pe_session->bssId, sync_ind->bssid.bytes);
 
-	pe_session->lim_join_req = qdf_mem_malloc(sizeof(*pe_session->lim_join_req) +
-						  bss_len);
+	pe_session->lim_join_req =
+		qdf_mem_malloc(sizeof(*pe_session->lim_join_req) + bss_len);
 	if (!pe_session->lim_join_req)
 		return QDF_STATUS_E_NOMEM;
 
@@ -3328,7 +3377,8 @@ lim_cm_fill_link_session(struct mac_context *mac_ctx,
 		goto end;
 	}
 
-	status = lim_roam_fill_bss_descr(mac_ctx, sync_ind, bss_desc, vdev_id);
+	status = lim_roam_fill_bss_descr(mac_ctx, sync_ind, bss_desc,
+					 pe_session);
 	if (!QDF_IS_STATUS_SUCCESS(status)) {
 		pe_err("LFR3:Failed to fill Bss Descr");
 		qdf_mem_free(bss_desc);
@@ -3781,6 +3831,94 @@ end:
 	link_probe_rsp.len = 0;
 	return status;
 }
+
+QDF_STATUS
+lim_gen_link_probe_rsp_roam(struct mac_context *mac_ctx,
+			    struct pe_session *session,
+			    struct roam_offload_synch_ind *roam_sync_ind)
+{
+	struct element_info link_probe_rsp;
+	struct qdf_mac_addr sta_link_addr;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	tSirProbeRespBeacon *probe_rsp;
+	uint8_t *frame;
+	uint32_t frame_len;
+	struct wlan_frame_hdr *hdr;
+
+	if (!session || !roam_sync_ind)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	if (!roam_sync_ind->num_setup_links)
+		return status;
+
+	if (roam_sync_ind->link_beacon_probe_resp_length) {
+		pe_debug("Firmware sent link beacon also. No need to generate a new one from assoc bcn/prb rsp");
+		return QDF_STATUS_SUCCESS;
+	}
+	frame_len = roam_sync_ind->beaconProbeRespLength;
+	frame = (uint8_t *)roam_sync_ind +
+			roam_sync_ind->beaconProbeRespOffset;
+
+	frame = (uint8_t *)(frame + sizeof(*hdr));
+	frame_len -= sizeof(*hdr);
+	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
+			   frame, frame_len);
+
+	probe_rsp = qdf_mem_malloc(sizeof(tSirProbeRespBeacon));
+	if (!probe_rsp)
+		return QDF_STATUS_E_NOMEM;
+
+	probe_rsp->ssId.length = 0;
+	probe_rsp->wpa.length = 0;
+	/* Enforce Mandatory IEs */
+	if ((sir_convert_probe_frame2_struct(mac_ctx,
+		frame, frame_len, probe_rsp) == QDF_STATUS_E_FAILURE) ||
+	    !probe_rsp->ssidPresent) {
+		pe_err("Parse error ProbeResponse, length=%d", frame_len);
+		qdf_mem_free(probe_rsp);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (probe_rsp->mlo_ie.mlo_ie_present) {
+		link_probe_rsp.ptr = qdf_mem_malloc(frame_len);
+		if (!link_probe_rsp.ptr)
+			return QDF_STATUS_E_NOMEM;
+
+		/*
+		 * 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);
+
+		link_probe_rsp.len = frame_len;
+		status = util_gen_link_probe_rsp(frame, frame_len,
+				sta_link_addr, link_probe_rsp.ptr,
+				frame_len, (qdf_size_t *)&link_probe_rsp.len);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			pe_err("MLO: Link probe response generation failed %d",
+			       status);
+			status = QDF_STATUS_E_FAILURE;
+			goto end;
+		}
+
+		lim_add_bcn_probe(session->vdev, link_probe_rsp.ptr,
+				  link_probe_rsp.len,
+				  mlo_roam_get_link_freq(session->vdev_id,
+							 roam_sync_ind),
+				  roam_sync_ind->rssi);
+	} else {
+		qdf_mem_free(probe_rsp);
+		return status;
+	}
+end:
+	if (link_probe_rsp.ptr)
+		qdf_mem_free(link_probe_rsp.ptr);
+	link_probe_rsp.len = 0;
+	qdf_mem_free(probe_rsp);
+	return status;
+}
 #endif
 
 #ifdef WLAN_FEATURE_SR

+ 9 - 3
core/wma/src/wma_scan_roam.c

@@ -560,11 +560,17 @@ wma_roam_update_vdev(tp_wma_handle wma,
 
 	vdev_id = roamed_vdev_id;
 	wma->interfaces[vdev_id].nss = roam_synch_ind_ptr->nss;
-	/* update freq and channel width */
-	wma->interfaces[vdev_id].ch_freq =
-		roam_synch_ind_ptr->chan_freq;
+
+	/* update channel width */
 	wma->interfaces[vdev_id].chan_width =
 		roam_synch_ind_ptr->chan_width;
+	/* Fill link freq from roam_synch_ind */
+	if (is_multi_link_roam(roam_synch_ind_ptr))
+		wma->interfaces[vdev_id].ch_freq =
+			mlo_roam_get_chan_freq(vdev_id, roam_synch_ind_ptr);
+	else
+		wma->interfaces[vdev_id].ch_freq =
+			roam_synch_ind_ptr->chan_freq;
 
 	del_sta_params = qdf_mem_malloc(sizeof(*del_sta_params));
 	if (!del_sta_params) {