Selaa lähdekoodia

qcacld-3.0: 2-link MLO Sap Simulation

Current SAP is unable to bringup 2 vdevs and connect 2-link MLO.
To unblock validation we simulate 2link connection on SAP.

Changes are as Follows:
- Add MLD caps to Beacon Frame
- Add RNR IE to Beacon/Probe Rsp Frame
- Add Per-Sta Profile to Probe Rsp Frame
- Add Per-Sta Profile to Assoc Rsp Frame

Change-Id: Ice2d3557e00426ead044ec6b4b507746db4148d4
CRs-Fixed: 3591637
David Oladunjoye 1 vuosi sitten
vanhempi
sitoutus
a00091f1b5

+ 1 - 0
Kbuild

@@ -4204,6 +4204,7 @@ ccflags-$(CONFIG_DP_RX_UDP_OVER_PEER_ROAM) += -DDP_RX_UDP_OVER_PEER_ROAM
 cppflags-$(CONFIG_WLAN_BOOST_CPU_FREQ_IN_ROAM) += -DWLAN_BOOST_CPU_FREQ_IN_ROAM
 
 ccflags-$(CONFIG_QCA_WIFI_EMULATION) += -DQCA_WIFI_EMULATION
+ccflags-$(CONFIG_SAP_MULTI_LINK_EMULATION) += -DSAP_MULTI_LINK_EMULATION
 ccflags-$(CONFIG_SHADOW_V2) += -DCONFIG_SHADOW_V2
 ccflags-$(CONFIG_SHADOW_V3) += -DCONFIG_SHADOW_V3
 ccflags-$(CONFIG_QCA6290_HEADERS_DEF) += -DQCA6290_HEADERS_DEF

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

@@ -1139,8 +1139,29 @@ QDF_STATUS cm_flush_join_req(struct scheduler_msg *msg)
 
 	return QDF_STATUS_SUCCESS;
 }
-
 #ifdef WLAN_FEATURE_11BE_MLO
+#if defined (SAP_MULTI_LINK_EMULATION)
+static void
+set_partner_info_for_2link_sap(struct scan_cache_entry *scan_entry,
+			       struct mlo_partner_info *partner_info)
+{
+	partner_info->partner_link_info[0].link_addr =
+		scan_entry->ml_info.link_info[0].link_addr;
+	partner_info->partner_link_info[0].link_id =
+		scan_entry->ml_info.link_info[0].link_id;
+	partner_info->partner_link_info[0].chan_freq =
+		scan_entry->ml_info.link_info[0].freq;
+	partner_info->num_partner_links = 1;
+
+}
+#else
+static void
+set_partner_info_for_2link_sap(struct scan_cache_entry *scan_entry,
+			       struct mlo_partner_info *partner_info)
+{
+}
+#endif
+
 QDF_STATUS
 cm_get_ml_partner_info(struct wlan_objmgr_pdev *pdev,
 		       struct scan_cache_entry *scan_entry,
@@ -1201,6 +1222,8 @@ cm_get_ml_partner_info(struct wlan_objmgr_pdev *pdev,
 	partner_info->num_partner_links = j;
 	mlme_debug("sta and ap intersect num of partner link: %d", j);
 
+	set_partner_info_for_2link_sap(scan_entry, partner_info);
+
 	return QDF_STATUS_SUCCESS;
 }
 

+ 4 - 0
configs/config_to_feature.h

@@ -1460,6 +1460,10 @@
 #define QCA_WIFI_EMULATION (1)
 #endif
 
+#ifdef CONFIG_SAP_MULTI_LINK_EMULATION
+#define SAP_MULTI_LINK_EMULATION (1)
+#endif
+
 #ifdef CONFIG_QCA6290_HEADERS_DEF
 #define QCA6290_HEADERS_DEF (1)
 #endif

+ 9 - 0
core/mac/src/pe/lim/lim_mlo.c

@@ -903,6 +903,14 @@ void lim_mlo_delete_link_peer(struct pe_session *pe_session,
 	wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID);
 }
 
+#if defined(SAP_MULTI_LINK_EMULATION)
+QDF_STATUS lim_mlo_assoc_ind_upper_layer(struct mac_context *mac,
+					 struct pe_session *pe_session,
+					 struct mlo_partner_info *mlo_info)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#else
 QDF_STATUS lim_mlo_assoc_ind_upper_layer(struct mac_context *mac,
 					 struct pe_session *pe_session,
 					 struct mlo_partner_info *mlo_info)
@@ -1007,6 +1015,7 @@ QDF_STATUS lim_mlo_assoc_ind_upper_layer(struct mac_context *mac,
 
 	return status;
 }
+#endif
 
 void lim_mlo_save_mlo_info(tpDphHashNode sta_ds,
 			   struct mlo_partner_info *mlo_info)

+ 19 - 1
core/mac/src/pe/sch/sch_beacon_gen.c

@@ -521,6 +521,22 @@ static uint16_t sch_get_tim_size(uint32_t max_aid)
 	return tim_size;
 }
 
+#ifdef SAP_MULTI_LINK_EMULATION
+static void omit_caps_for_2link_sap(tDot11fBeacon2 *bcn_2)
+{
+	qdf_mem_zero(&bcn_2->HTCaps, sizeof(bcn_2->HTCaps));
+	qdf_mem_zero(&bcn_2->EDCAParamSet, sizeof(bcn_2->EDCAParamSet));
+	qdf_mem_zero(&bcn_2->PowerConstraints, sizeof(bcn_2->PowerConstraints));
+	qdf_mem_zero(&bcn_2->TPCReport, sizeof(bcn_2->TPCReport));
+
+	pe_debug("Removed caps from beacon/probe rsp");
+}
+#else
+static inline void omit_caps_for_2link_sap(tDot11fBeacon2 *bcn_2)
+{
+}
+#endif
+
 /**
  * sch_set_fixed_beacon_fields() - sets the fixed params in beacon frame
  * @mac_ctx:       mac global context
@@ -912,7 +928,7 @@ sch_set_fixed_beacon_fields(struct mac_context *mac_ctx, struct pe_session *sess
 		}
 	}
 
-	if (session->vhtCapability && session->gLimOperatingMode.present) {
+	if (session->vhtCapability || session->gLimOperatingMode.present) {
 		populate_dot11f_operating_mode(mac_ctx, &bcn_2->OperatingMode,
 					       session);
 		lim_strip_ie(mac_ctx, addn_ie, &addn_ielen,
@@ -920,6 +936,8 @@ sch_set_fixed_beacon_fields(struct mac_context *mac_ctx, struct pe_session *sess
 			     NULL, SIR_MAC_VHT_OPMODE_SIZE - 2);
 	}
 
+	omit_caps_for_2link_sap(bcn_2);
+
 	n_status = dot11f_pack_beacon2(mac_ctx, bcn_2,
 				       session->pSchBeaconFrameEnd,
 				       SIR_MAX_BEACON_SIZE, &n_bytes);

+ 381 - 0
core/mac/src/sys/legacy/src/utils/src/parser_api.c

@@ -9873,6 +9873,343 @@ no_sta_prof:
 	return QDF_STATUS_SUCCESS;
 }
 
+#if defined(SAP_MULTI_LINK_EMULATION)
+QDF_STATUS populate_dot11f_assoc_rsp_mlo_ie(struct mac_context *mac_ctx,
+					    struct pe_session *session,
+					    tpDphHashNode sta,
+					    tDot11fAssocResponse *frm)
+{
+	struct wlan_mlo_ie *mlo_ie;
+	struct wlan_mlo_sta_profile *sta_pro;
+	tpSirAssocReq assoc_req;
+	uint8_t *sta_data;
+	uint32_t sta_len_left;
+	uint8_t common_info_len = 0;
+	uint8_t *p_ml_ie;
+	uint16_t len_remaining;
+	uint16_t presence_bitmap = 0;
+	uint16_t sta_prof_len;
+	uint8_t sta_prof_[] = {0x00, 0xff, 0xf1, 0x01, 0x13, 0x02, 0x03, 0x7f, 0x95, 0xaf, 0x62, 0x64, 0x00, 0x54, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x31, 0x04, 0x00, 0x00, 0x01, 0x08, 0x8c, 0x12, 0x98, 0x24, 0xb0,
+		0x48, 0x60, 0x6c, 0x07, 0x0a, 0x55, 0x53, 0x04, 0xc9, 0x83, 0x00, 0x01, 0x3b, 0x00, 0x00, 0x20,
+		0x01, 0x00, 0x23, 0x02, 0x0a, 0x00, 0x32, 0x01, 0xfb, 0x7f, 0x0b, 0x04, 0x00, 0x4f, 0x02, 0x00,
+		0x00, 0x00, 0x40, 0x00, 0x40, 0x19, 0xc3, 0x02, 0x58, 0x0a, 0xc3, 0x02, 0x18, 0xfe, 0xff, 0x23,
+		0x23, 0x0d, 0x01, 0x08, 0x1a, 0x40, 0x10, 0x00, 0x63, 0x40, 0x88, 0x1f, 0x43, 0x81, 0x1c, 0x11,
+		0x08, 0x00, 0xaa, 0xff, 0xaa, 0xff, 0x7b, 0x1c, 0xc7, 0x71, 0x1c, 0xc7, 0x71, 0x1c, 0xc7, 0x71,
+		0x1c, 0xc7, 0x71, 0xff, 0x0c, 0x24, 0xf4, 0x3f, 0x02, 0x28, 0xfc, 0xff, 0x25, 0x00, 0x25, 0x00,
+		0x01, 0xff, 0x0e, 0x26, 0x00, 0x03, 0xa4, 0xff, 0x27, 0xa4, 0xff, 0x42, 0x43, 0xff, 0x62, 0x32,
+		0xff, 0xff, 0x03, 0x3b, 0xb8, 0x36, 0xff, 0x0f, 0x6c, 0x17, 0x00, 0xe0, 0x03, 0x03, 0x00, 0x18,
+		0x76, 0xd8, 0x12, 0x00, 0x44, 0x44, 0x44, 0xff, 0x06, 0x6a, 0x04, 0x11, 0x00, 0x00, 0x00};
+	QDF_STATUS status;
+
+	if (!mac_ctx || !session || !frm)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	mlo_ie = &session->mlo_ie;
+
+	p_ml_ie = mlo_ie->data;
+	len_remaining = sizeof(mlo_ie->data);
+
+	*p_ml_ie++ = WLAN_ELEMID_EXTN_ELEM;
+	len_remaining--;
+	/* set length later */
+	*p_ml_ie++ = 0;
+	len_remaining--;
+	*p_ml_ie++ = WLAN_EXTN_ELEMID_MULTI_LINK;
+	len_remaining--;
+
+	mlo_ie->type = 0;
+	/* Common Info Length*/
+	common_info_len += WLAN_ML_BV_CINFO_LENGTH_SIZE;
+	qdf_mem_copy(mlo_ie->mld_mac_addr,
+		     session->vdev->mlo_dev_ctx->mld_addr.bytes,
+		     sizeof(mlo_ie->mld_mac_addr));
+	common_info_len += QDF_MAC_ADDR_SIZE;
+
+	mlo_ie->link_id_info_present = 1;
+	presence_bitmap |= WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P;
+	mlo_ie->link_id = wlan_vdev_get_link_id(session->vdev);
+	common_info_len += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
+
+	mlo_ie->bss_param_change_cnt_present = 1;
+	presence_bitmap |= WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P;
+	mlo_ie->bss_param_change_count =
+			session->mlo_link_info.link_ie.bss_param_change_cnt;
+	common_info_len += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
+
+	mlo_ie->mld_capab_and_op_present = 1;
+	mlo_ie->mld_id_present = 1;
+	mlo_ie->ext_mld_capab_and_op_present = 1;
+	common_info_len += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+	presence_bitmap |= WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P;
+
+	common_info_len += WLAN_ML_BV_CINFO_EMLCAP_SIZE;
+	presence_bitmap |= WLAN_ML_BV_CTRL_PBM_EMLCAP_P;
+
+	common_info_len += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+	presence_bitmap |= WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P;
+
+	mlo_ie->common_info_length = common_info_len;
+
+	QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_TYPE_IDX,
+		     WLAN_ML_CTRL_TYPE_BITS, mlo_ie->type);
+	QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_PBM_IDX,
+		     WLAN_ML_CTRL_PBM_BITS, presence_bitmap);
+	p_ml_ie += WLAN_ML_CTRL_SIZE;
+	len_remaining -= WLAN_ML_CTRL_SIZE;
+
+	*p_ml_ie++ = common_info_len;
+	len_remaining--;
+
+	qdf_mem_copy(p_ml_ie, mlo_ie->mld_mac_addr, QDF_MAC_ADDR_SIZE);
+	p_ml_ie += QDF_MAC_ADDR_SIZE;
+	len_remaining -= QDF_MAC_ADDR_SIZE;
+
+	QDF_SET_BITS(*p_ml_ie, WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_IDX,
+		     WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_BITS, mlo_ie->link_id);
+	p_ml_ie++;
+	len_remaining--;
+
+	*p_ml_ie++ = mlo_ie->bss_param_change_count;
+	len_remaining--;
+
+	p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+	p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+	len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+	len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+
+	if (mlo_ie->mld_capab_and_op_present) {
+		QDF_SET_BITS(*(uint16_t *)p_ml_ie,
+		     WLAN_ML_BV_CINFO_MLDCAPANDOP_MAXSIMULLINKS_IDX,
+		     WLAN_ML_BV_CINFO_MLDCAPANDOP_MAXSIMULLINKS_BITS,
+		     mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num);
+		QDF_SET_BITS(*(uint16_t *)p_ml_ie,
+		     WLAN_ML_BV_CINFO_MLDCAPANDOP_TIDTOLINKMAPNEGSUPPORT_IDX,
+		     WLAN_ML_BV_CINFO_MLDCAPANDOP_TIDTOLINKMAPNEGSUPPORT_BITS,
+		     mlo_ie->mld_capab_and_op_info.tid_link_map_supported);
+		p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+		len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+	}
+
+	mlo_ie->num_data = p_ml_ie - mlo_ie->data;
+
+	sta_prof_[5] = session->self_mac_addr[0];
+	sta_prof_[6] = session->self_mac_addr[1];
+	sta_prof_[7] = session->self_mac_addr[2];
+	sta_prof_[8] = session->self_mac_addr[3];
+
+	sta_prof_[9] = 0xaf;
+	sta_prof_[10] = 0x62;
+
+	sta_pro = &mlo_ie->sta_profile[0];
+	sta_data = sta_pro->data;
+	sta_len_left = sizeof(sta_pro->data);
+
+	sta_prof_len = ARRAY_SIZE(sta_prof_);
+	qdf_mem_copy(sta_data, sta_prof_, sta_prof_len);
+	sta_data += sta_prof_len;
+	sta_len_left -= sta_prof_len;
+
+	sta_pro->num_data = sta_data - sta_pro->data;
+	pe_debug("num data: %d, sta_prof_len: %d, sta_data len: %d",
+		 sta_pro->num_data, sta_prof_len, sizeof(sta_pro->data));
+	sta_pro->data[TAG_LEN_POS] = sta_pro->num_data - MIN_IE_LEN;
+
+	mlo_ie->num_sta_profile = 1;
+	mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num = 1;
+
+		if (sta_pro->num_data > WLAN_MAX_IE_LEN + MIN_IE_LEN) {
+			sta_pro->data[TAG_LEN_POS] = WLAN_MAX_IE_LEN;
+			status =
+			    lim_add_frag_ie_for_sta_profile(sta_pro->data,
+							    &sta_pro->num_data);
+			if (status != QDF_STATUS_SUCCESS) {
+				pe_debug("add frg ie for sta profile error.");
+				sta_pro->num_data =
+					WLAN_MAX_IE_LEN + MIN_IE_LEN;
+			}
+		} else {
+			sta_pro->data[TAG_LEN_POS] =
+					sta_pro->num_data - MIN_IE_LEN;
+		}
+	assoc_req = session->parsedAssocReq[sta->assocId];
+
+	pe_debug("num partner links: %d", assoc_req->mlo_info.num_partner_links);
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS populate_dot11f_bcn_mlo_ie(struct mac_context *mac_ctx,
+				      struct pe_session *session)
+{
+	struct wlan_mlo_ie *mlo_ie;
+	struct wlan_mlo_sta_profile *sta_pro;
+	uint16_t vdev_count;
+	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
+	uint16_t tmp_offset = 0;
+	struct ml_sch_partner_info *tmp_info;
+	struct mlo_sch_partner_links *sch_info;
+	uint8_t *sta_data;
+	uint8_t common_info_length = 0;
+	uint8_t *p_ml_ie;
+	uint16_t len_remaining;
+	uint16_t presence_bitmap = 0;
+	uint32_t sta_len_left;
+	QDF_STATUS status;
+	uint16_t sta_prof_len;
+	uint8_t sta_prof_[] = {0x00, 0xff, 0xf1, 0x01, 0x13, 0x02, 0x03, 0x7f, 0x95, 0xaf, 0x62, 0x64, 0x00, 0x54, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x05, 0x01, 0x08, 0x8c, 0x12, 0x98, 0x24, 0xb0,
+		0x48, 0x60, 0x6c, 0x07, 0x0a, 0x55, 0x53, 0x04, 0xc9, 0x83, 0x00, 0x01, 0x3b, 0x00, 0x00, 0x20,
+		0x01, 0x00, 0x23, 0x02, 0x0a, 0x00, 0x32, 0x01, 0xfb, 0x7f, 0x0b, 0x04, 0x00, 0x4f, 0x02, 0x00,
+		0x00, 0x00, 0x40, 0x00, 0x40, 0x19, 0xc3, 0x02, 0x58, 0x0a, 0xc3, 0x02, 0x18, 0xfe, 0xff, 0x23,
+		0x23, 0x0d, 0x01, 0x08, 0x1a, 0x40, 0x10, 0x00, 0x63, 0x40, 0x88, 0x1f, 0x43, 0x81, 0x1c, 0x11,
+		0x08, 0x00, 0xaa, 0xff, 0xaa, 0xff, 0x7b, 0x1c, 0xc7, 0x71, 0x1c, 0xc7, 0x71, 0x1c, 0xc7, 0x71,
+		0x1c, 0xc7, 0x71, 0xff, 0x0c, 0x24, 0xf4, 0x3f, 0x02, 0x28, 0xfc, 0xff, 0x25, 0x00, 0x25, 0x00,
+		0x01, 0xff, 0x0e, 0x26, 0x00, 0x03, 0xa4, 0xff, 0x27, 0xa4, 0xff, 0x42, 0x43, 0xff, 0x62, 0x32,
+		0xff, 0xff, 0x03, 0x3b, 0xb8, 0x36, 0xff, 0x0f, 0x6c, 0x17, 0x00, 0xe0, 0x03, 0x03, 0x00, 0x18,
+		0x76, 0xd8, 0x12, 0x00, 0x44, 0x44, 0x44, 0xff, 0x06, 0x6a, 0x04, 0x11, 0x00, 0x00, 0x00};
+	if (!mac_ctx || !session)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	mlo_ie = &session->mlo_ie;
+
+	/* Common Info Length */
+	common_info_length += WLAN_ML_BV_CINFO_LENGTH_SIZE;
+	qdf_mem_zero(&mac_ctx->sch.sch_mlo_partner,
+		     sizeof(mac_ctx->sch.sch_mlo_partner));
+	sch_info = &mac_ctx->sch.sch_mlo_partner;
+	mlo_ie->type = 0;
+	tmp_offset += 1; /* Element ID */
+	tmp_offset += 1; /* length */
+	tmp_offset += 1; /* Element ID extension */
+	tmp_offset += 2; /* Multi-link control */
+	qdf_mem_copy(mlo_ie->mld_mac_addr,
+		     session->vdev->mlo_dev_ctx->mld_addr.bytes,
+		     sizeof(mlo_ie->mld_mac_addr));
+	tmp_offset += 1; /* Common Info Length */
+	tmp_offset += 6; /* mld mac addr */
+	common_info_length += QDF_MAC_ADDR_SIZE;
+	mlo_ie->link_id_info_present = 1;
+	presence_bitmap |= WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P;
+	mlo_ie->link_id = wlan_vdev_get_link_id(session->vdev);
+	tmp_offset += 1; /* link id */
+	common_info_length += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
+	mlo_ie->bss_param_change_cnt_present = 1;
+	presence_bitmap |= WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P;
+	mlo_ie->bss_param_change_count =
+			session->mlo_link_info.link_ie.bss_param_change_cnt;
+	tmp_offset += 1; /* bss parameters change count */
+	common_info_length += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
+
+	tmp_offset += 2;/* MLD Parameters */
+	mlo_ie->mld_capab_and_op_present = 1;
+	mlo_ie->mld_id_present = 1;
+	mlo_ie->ext_mld_capab_and_op_present = 1;
+	sch_info->num_links = 1;
+	common_info_length += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+	presence_bitmap |= WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P;
+
+	tmp_offset += 2;
+	common_info_length += WLAN_ML_BV_CINFO_EMLCAP_SIZE;
+	presence_bitmap |= WLAN_ML_BV_CTRL_PBM_EMLCAP_P;
+
+	tmp_offset += 2;
+	common_info_length += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+	presence_bitmap |= WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P;
+
+	lim_get_mlo_vdev_list(session, &vdev_count, wlan_vdev_list);
+	mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num =
+							vdev_count;
+
+	mlo_ie->mld_capab_and_op_info.tid_link_map_supported = 1;
+
+	mlo_ie->common_info_length = common_info_length;
+	sch_info->mlo_ie_link_info_ofst = tmp_offset;
+
+	p_ml_ie = mlo_ie->data;
+	len_remaining = sizeof(mlo_ie->data);
+
+	*p_ml_ie++ = WLAN_ELEMID_EXTN_ELEM;
+	len_remaining--;
+	*p_ml_ie++ = 0;
+	len_remaining--;
+	*p_ml_ie++ = WLAN_EXTN_ELEMID_MULTI_LINK;
+	len_remaining--;
+
+	QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_TYPE_IDX,
+		     WLAN_ML_CTRL_TYPE_BITS, mlo_ie->type);
+	QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_PBM_IDX,
+		     WLAN_ML_CTRL_PBM_BITS, presence_bitmap);
+	p_ml_ie += WLAN_ML_CTRL_SIZE;
+	len_remaining -= WLAN_ML_CTRL_SIZE;
+
+	*p_ml_ie++ = common_info_length;
+	len_remaining--;
+
+	qdf_mem_copy(p_ml_ie, mlo_ie->mld_mac_addr, QDF_MAC_ADDR_SIZE);
+	p_ml_ie += QDF_MAC_ADDR_SIZE;
+	len_remaining -= QDF_MAC_ADDR_SIZE;
+
+	QDF_SET_BITS(*p_ml_ie, WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_IDX,
+		     WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_BITS,
+		     mlo_ie->link_id);
+	p_ml_ie++;
+	len_remaining--;
+
+	*p_ml_ie++ = mlo_ie->bss_param_change_count;
+	len_remaining--;
+
+	p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+	p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+	len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+	len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+
+	if (mlo_ie->mld_capab_and_op_present) {
+		QDF_SET_BITS(*(uint16_t *)p_ml_ie,
+		     WLAN_ML_BV_CINFO_MLDCAPANDOP_MAXSIMULLINKS_IDX,
+		     WLAN_ML_BV_CINFO_MLDCAPANDOP_MAXSIMULLINKS_BITS,
+		     mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num);
+		QDF_SET_BITS(*(uint16_t *)p_ml_ie,
+		     WLAN_ML_BV_CINFO_MLDCAPANDOP_TIDTOLINKMAPNEGSUPPORT_IDX,
+		     WLAN_ML_BV_CINFO_MLDCAPANDOP_TIDTOLINKMAPNEGSUPPORT_BITS,
+		     mlo_ie->mld_capab_and_op_info.tid_link_map_supported);
+		p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+		len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
+	}
+
+	mlo_ie->num_data = p_ml_ie - mlo_ie->data;
+
+	sta_prof_[5] = session->self_mac_addr[0];
+	sta_prof_[6] = session->self_mac_addr[1];
+	sta_prof_[7] = session->self_mac_addr[2];
+	sta_prof_[8] = session->self_mac_addr[3];
+
+	sta_prof_[9] = 0xaf;
+	sta_prof_[10] = 0x62;
+
+	sta_pro = &mlo_ie->sta_profile[0];
+	sta_data = sta_pro->data;
+	sta_len_left = sizeof(sta_pro->data);
+
+	sta_prof_len = ARRAY_SIZE(sta_prof_);
+	qdf_mem_copy(sta_data, sta_prof_, sta_prof_len);
+	sta_data += sta_prof_len;
+	sta_len_left -= sta_prof_len;
+	sch_info->num_links = 1;
+	mlo_ie->num_sta_profile = 1;
+
+	sta_pro->num_data = sta_data - sta_pro->data;
+	pe_debug("num data: %d, sta_prof_len: %d, sta_data len: %d",
+		 sta_pro->num_data, sta_prof_len, sizeof(sta_pro->data));
+	sta_pro->data[TAG_LEN_POS] =	sta_pro->num_data - MIN_IE_LEN;
+	tmp_info = &sch_info->partner_info[0];
+	tmp_info->link_info_sta_prof_ofst = sta_prof_len;
+
+	mlo_ie->num_sta_profile = 1;
+	status = QDF_STATUS_SUCCESS;
+
+	return status;
+}
+#else
 QDF_STATUS populate_dot11f_assoc_rsp_mlo_ie(struct mac_context *mac_ctx,
 					    struct pe_session *session,
 					    tpDphHashNode sta,
@@ -10727,6 +11064,7 @@ QDF_STATUS populate_dot11f_bcn_mlo_ie(struct mac_context *mac_ctx,
 
 	return QDF_STATUS_SUCCESS;
 }
+#endif
 
 QDF_STATUS populate_dot11f_tdls_mgmt_mlo_ie(struct mac_context *mac_ctx,
 					    struct pe_session *session)
@@ -10779,6 +11117,46 @@ QDF_STATUS populate_dot11f_tdls_mgmt_mlo_ie(struct mac_context *mac_ctx,
 	return QDF_STATUS_SUCCESS;
 }
 
+#if defined (SAP_MULTI_LINK_EMULATION)
+static void populate_2link_rnr_info(struct pe_session *session,
+				    tDot11fIEreduced_neighbor_report *dot11f)
+{
+	tSirMacAddr fake_mac_addr;
+
+	qdf_mem_copy(fake_mac_addr, session->self_mac_addr, sizeof(tSirMacAddr));
+
+	pe_debug(QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(fake_mac_addr));
+
+	dot11f->present = 1;
+	dot11f->op_class = 131;
+	dot11f->channel_num = 37;
+
+	dot11f->tbtt_info_count = 0;
+	dot11f->tbtt_info_len = 16;
+
+	fake_mac_addr[4] = 0xaf;
+	fake_mac_addr[5] = 0x62;
+	qdf_mem_copy(dot11f->tbtt_info.tbtt_info_16.bssid,
+		     fake_mac_addr, sizeof(tSirMacAddr));
+	dot11f->tbtt_info.tbtt_info_16.mld_id = 0;
+	dot11f->tbtt_info.tbtt_info_16.link_id = 1;
+
+	dot11f->tbtt_info.tbtt_info_16.bss_params = 0x4e;
+	dot11f->tbtt_info.tbtt_info_16.short_ssid = 0x558df58e;
+	dot11f->tbtt_info.tbtt_info_16.psd_20mhz = 0xfe;
+
+	dot11f->tbtt_info.tbtt_info_16.bss_param_change_cnt =
+		session->mlo_link_info.link_ie.bss_param_change_cnt;
+
+	pe_debug("Populated rnr IE...");
+}
+#else
+static inline void populate_2link_rnr_info(struct pe_session *session,
+					   tDot11fIEreduced_neighbor_report *dot11f)
+{
+}
+#endif
+
 void populate_dot11f_mlo_rnr(struct mac_context *mac_ctx,
 			     struct pe_session *session,
 			     tDot11fIEreduced_neighbor_report *dot11f)
@@ -10821,6 +11199,9 @@ void populate_dot11f_mlo_rnr(struct mac_context *mac_ctx,
 		}
 		lim_mlo_release_vdev_ref(wlan_vdev_list[link]);
 	}
+
+	populate_2link_rnr_info(session, dot11f);
+
 }
 
 void populate_dot11f_rnr_tbtt_info_16(struct mac_context *mac_ctx,