Jelajahi Sumber

qcacmn: Add T2LM IE changes as per IEEE802.11be draft 2.1

Add support to include mapping switch time and expected duration in T2LM
IE.

Removed the below functions as MCC uses ieee_link_id instead of hw_link_id.
Do this conversion in the WIN only code.

wlan_mlo_get_hw_link_id_mask, wlan_get_ieee_link_id_mask
wlan_mlo_parse_t2lm_provisioned_links, wlan_mlo_add_t2lm_provisioned_links

Change-Id: Icc36ff318de4177bf0941235243298baef83d1e6
CRs-Fixed: 3341502
Shashikala Prabhu 2 tahun lalu
induk
melakukan
b699679cb9

+ 3 - 0
umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h

@@ -2595,6 +2595,9 @@ struct wlan_ml_rv_linfo_perstaprof {
 /* All Updates Included */
 #define WLAN_RNR_NBRAPINFO_TBTTINFO_MLDPARAMS_ALLUPDATESINC_IDX          20
 #define WLAN_RNR_NBRAPINFO_TBTTINFO_MLDPARAMS_ALLUPDATESINC_BITS         1
+/* Disabled link indication */
+#define WLAN_RNR_NBRAPINFO_TBTTINFO_MLDPARAMS_DISABLEDLINKIND_IDX        21
+#define WLAN_RNR_NBRAPINFO_TBTTINFO_MLDPARAMS_DISABLEDLINKIND_BITS       1
 
 /*
  * End of definitions related to MLO specific aspects of Reduced Neighbor Report

+ 38 - 12
umac/mlo_mgr/inc/wlan_mlo_t2lm.h

@@ -40,34 +40,33 @@
 #define t2lm_debug(format, args...) \
 	QDF_TRACE_DEBUG(QDF_MODULE_ID_T2LM, format, ## args)
 
+#define t2lm_rl_debug(format, args...) \
+	QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_T2LM, format, ## args)
+
 #define WLAN_T2LM_MAX_NUM_LINKS 16
 
 /**
  * wlan_mlo_parse_t2lm_ie() - API to parse the T2LM IE
- * @peer: Pointer to peer structure
  * @t2lm: Pointer to T2LM structure
  * @ie: Pointer to T2LM IE
  *
  * Return: QDF_STATUS
  */
 QDF_STATUS wlan_mlo_parse_t2lm_ie(
-	struct wlan_objmgr_peer *peer,
 	struct wlan_t2lm_onging_negotiation_info *t2lm, uint8_t *ie);
 
 /**
  * wlan_mlo_add_t2lm_ie() - API to add TID-to-link mapping IE
  * @frm: Pointer to buffer
- * @peer: Pointer to peer structure
  * @t2lm: Pointer to t2lm mapping structure
  *
  * Return: Updated frame pointer
  */
-uint8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm, struct wlan_objmgr_peer *peer,
+uint8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm,
 			      struct wlan_t2lm_onging_negotiation_info *t2lm);
 
 /**
  * wlan_mlo_parse_t2lm_action_frame() - API to parse T2LM action frame
- * @peer: Pointer to peer structure
  * @t2lm: Pointer to T2LM structure
  * @action_frm: Pointer to action frame
  * @category: T2LM action frame category
@@ -75,14 +74,12 @@ uint8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm, struct wlan_objmgr_peer *peer,
  * Return: 0 - success, else failure
  */
 int wlan_mlo_parse_t2lm_action_frame(
-		struct wlan_objmgr_peer *peer,
 		struct wlan_t2lm_onging_negotiation_info *t2lm,
 		struct wlan_action_frame *action_frm,
 		enum wlan_t2lm_category category);
 
 /**
  * wlan_mlo_add_t2lm_action_frame() - API to add T2LM action frame
- * @peer: Pointer to peer structure
  * @frm: Pointer to a frame to add T2LM IE
  * @args: T2LM action frame related info
  * @buf: Pointer to T2LM IE values
@@ -91,19 +88,37 @@ int wlan_mlo_parse_t2lm_action_frame(
  * Return: Pointer to the updated frame buffer
  */
 uint8_t *wlan_mlo_add_t2lm_action_frame(
-		struct wlan_objmgr_peer *peer,
 		uint8_t *frm, struct wlan_action_frame_args *args,
 		uint8_t *buf, enum wlan_t2lm_category category);
+
+/**
+ * wlan_mlo_parse_bcn_prbresp_t2lm_ie() - API to parse the T2LM IE from beacon/
+ * probe response frame
+ * @t2lm_ctx: T2LM context
+ * @ie: Pointer to T2LM IE
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_mlo_parse_bcn_prbresp_t2lm_ie(
+		struct wlan_t2lm_context *t2lm_ctx, uint8_t *ie);
+
+/**
+ * wlan_mlo_add_t2lm_info_ie() - Add T2LM IE for UL/DL/Bidirection
+ * @frm: Pointer to buffer
+ * @t2lm: Pointer to t2lm mapping structure
+ *
+ * Return: Updated frame pointer
+ */
+uint8_t *wlan_mlo_add_t2lm_info_ie(uint8_t *frm, struct wlan_t2lm_info *t2lm);
 #else
 static inline QDF_STATUS wlan_mlo_parse_t2lm_ie(
-	struct wlan_objmgr_peer *peer,
 	struct wlan_t2lm_onging_negotiation_info *t2lm, uint8_t *ie)
 {
 	return QDF_STATUS_E_FAILURE;
 }
 
 static inline
-int8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm, struct wlan_objmgr_peer *peer,
+int8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm,
 			     struct wlan_t2lm_onging_negotiation_info *t2lm)
 {
 	return frm;
@@ -111,7 +126,6 @@ int8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm, struct wlan_objmgr_peer *peer,
 
 static inline
 int wlan_mlo_parse_t2lm_action_frame(
-		struct wlan_objmgr_peer *peer,
 		struct wlan_t2lm_onging_negotiation_info *t2lm,
 		struct wlan_action_frame *action_frm,
 		enum wlan_t2lm_category category)
@@ -121,11 +135,23 @@ int wlan_mlo_parse_t2lm_action_frame(
 
 static inline
 uint8_t *wlan_mlo_add_t2lm_action_frame(
-		struct wlan_objmgr_peer *peer,
 		uint8_t *frm, struct wlan_action_frame_args *args,
 		uint8_t *buf, enum wlan_t2lm_category category)
 {
 	return frm;
 }
+
+static inline
+QDF_STATUS wlan_mlo_parse_bcn_prbresp_t2lm_ie(
+		struct wlan_t2lm_context *t2lm_ctx, uint8_t *ie)
+{
+	return QDF_STATUS_E_FAILURE;
+}
+
+static inline
+uint8_t *wlan_mlo_add_t2lm_info_ie(uint8_t *frm, struct wlan_t2lm_info *t2lm)
+{
+	return frm;
+}
 #endif /* WLAN_FEATURE_11BE */
 #endif /* _WLAN_MLO_T2LM_H_ */

+ 180 - 300
umac/mlo_mgr/src/wlan_mlo_t2lm.c

@@ -26,138 +26,34 @@
 #include <wlan_mlo_mgr_cmn.h>
 #include <qdf_util.h>
 
-/**
- * wlan_mlo_get_hw_link_id_mask() - Return hw_link_id mask for a given
- * ieee_link_id_mask.
- * @wlan_vdev_list: vdev list
- * @vdev_count: vdev count
- * @ieee_link_id_mask: IEEE link id mask
- *
- * Return: hw_link_id mask
- */
-static uint8_t wlan_mlo_get_hw_link_id_mask(
-		struct wlan_objmgr_vdev **wlan_vdev_list,
-		uint16_t vdev_count, uint16_t ieee_link_id_mask)
-{
-	struct wlan_objmgr_pdev *pdev;
-	struct wlan_objmgr_vdev *vdev;
-	uint8_t link_id;
-	uint16_t ieee_link_id;
-	uint16_t hw_link_id_mask = 0;
-	int i;
-
-	for (link_id = 0; link_id < WLAN_T2LM_MAX_NUM_LINKS; link_id++) {
-		ieee_link_id = ieee_link_id_mask & BIT(link_id);
-		if (!ieee_link_id)
-			continue;
-
-		for (i = 0; i < vdev_count; i++) {
-			vdev = wlan_vdev_list[i];
-			if (!vdev) {
-				t2lm_err("vdev is null");
-				continue;
-			}
-
-			if (ieee_link_id != BIT(vdev->vdev_mlme.mlo_link_id))
-				continue;
-
-			pdev = wlan_vdev_get_pdev(vdev);
-			if (!pdev) {
-				t2lm_err("pdev is null");
-				continue;
-			}
-
-			hw_link_id_mask |=
-				BIT(wlan_mlo_get_pdev_hw_link_id(pdev));
-			break;
-		}
-	}
-
-	return hw_link_id_mask;
-}
-
-/**
- * wlan_mlo_parse_t2lm_provisioned_links() - Parse the T2LM provisioned links
- * from the T2LM IE.
- * @peer: Pointer to peer structure
- * @link_mapping_presence_ind: This indicates whether the link mapping of TIDs
- *                             present in the T2LM IE.
- * @link_mapping_of_tids: Link mapping of each TID
- * @t2lm: Pointer to a T2LM structure
- * @dir: DL/UL/BIDI direction
- *
- * Return: QDF_STATUS
- */
-static QDF_STATUS wlan_mlo_parse_t2lm_provisioned_links(
-		struct wlan_objmgr_peer *peer,
-		uint8_t link_mapping_presence_ind,
-		uint8_t *link_mapping_of_tids,
-		struct wlan_t2lm_onging_negotiation_info *t2lm,
-		enum wlan_t2lm_direction dir)
-{
-	struct wlan_objmgr_vdev *vdev;
-	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {0};
-	uint16_t vdev_count = 0;
-	uint16_t hw_link_id_mask;
-	uint8_t tid_num;
-	uint16_t i;
-
-	vdev = wlan_peer_get_vdev(peer);
-	if (!vdev) {
-		t2lm_err("vdev is null");
-		return QDF_STATUS_E_NULL_VALUE;
-	}
-
-	mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list);
-	if (!vdev_count) {
-		t2lm_err("Number of VDEVs under MLD is reported as 0");
-		return QDF_STATUS_E_NULL_VALUE;
-	}
-
-	for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
-		if (link_mapping_presence_ind & BIT(tid_num)) {
-			hw_link_id_mask = wlan_mlo_get_hw_link_id_mask(
-					wlan_vdev_list, vdev_count,
-					*(uint16_t *)link_mapping_of_tids);
-			t2lm->t2lm_info[dir].hw_link_map_tid[tid_num] =
-				hw_link_id_mask;
-			link_mapping_of_tids += sizeof(uint16_t);
-		}
-	}
-
-	for (i = 0; i < vdev_count; i++)
-		mlo_release_vdev_ref(wlan_vdev_list[i]);
-
-	return QDF_STATUS_SUCCESS;
-}
-
 /**
  * wlan_mlo_parse_t2lm_info() - Parse T2LM IE fields
- * @peer: Pointer to peer structure
  * @ie: Pointer to T2LM IE
  * @t2lm: Pointer to T2LM structure
  *
  * Return: QDF_STATUS
  */
-static QDF_STATUS wlan_mlo_parse_t2lm_info(
-		struct wlan_objmgr_peer *peer, uint8_t *ie,
-		struct wlan_t2lm_onging_negotiation_info *t2lm)
+static QDF_STATUS wlan_mlo_parse_t2lm_info(uint8_t *ie,
+					   struct wlan_t2lm_info *t2lm)
 {
+	struct wlan_ie_tid_to_link_mapping *t2lm_ie;
 	enum wlan_t2lm_direction dir;
 	uint8_t *t2lm_control_field;
 	uint16_t t2lm_control;
 	uint8_t link_mapping_presence_ind;
 	uint8_t *link_mapping_of_tids;
 	uint8_t tid_num;
-	QDF_STATUS ret;
+	uint8_t *ie_ptr = NULL;
+
+	t2lm_ie = (struct wlan_ie_tid_to_link_mapping *)ie;
 
-	t2lm_control_field = ie + sizeof(struct wlan_ie_tid_to_link_mapping);
+	t2lm_control_field = t2lm_ie->data;
 	if (!t2lm_control_field) {
 		t2lm_err("t2lm_control_field is null");
 		return QDF_STATUS_E_NULL_VALUE;
 	}
 
-	t2lm_control = *(uint16_t *)t2lm_control_field;
+	t2lm_control = qdf_le16_to_cpu(*(uint16_t *)t2lm_control_field);
 
 	dir = QDF_GET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DIRECTION_IDX,
 			   WLAN_T2LM_CONTROL_DIRECTION_BITS);
@@ -166,58 +62,125 @@ static QDF_STATUS wlan_mlo_parse_t2lm_info(
 		return QDF_STATUS_E_NULL_VALUE;
 	}
 
-	t2lm->t2lm_info[dir].direction = dir;
-	t2lm->t2lm_info[dir].default_link_mapping =
+	t2lm->direction = dir;
+	t2lm->default_link_mapping =
 		QDF_GET_BITS(t2lm_control,
 			     WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_IDX,
 			     WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_BITS);
 
-	t2lm_debug("direction:%d default_link_mapping:%d",
-		   t2lm->t2lm_info[dir].direction,
-		   t2lm->t2lm_info[dir].default_link_mapping);
+	t2lm->mapping_switch_time_present =
+		QDF_GET_BITS(t2lm_control,
+			     WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_IDX,
+			     WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_BITS);
 
-	/* Link mapping of TIDs are not present when default mapping is set */
-	if (t2lm->t2lm_info[dir].default_link_mapping)
-		return QDF_STATUS_SUCCESS;
+	t2lm->expected_duration_present =
+		QDF_GET_BITS(t2lm_control,
+			     WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_IDX,
+			     WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_BITS);
 
-	link_mapping_presence_ind = QDF_GET_BITS(
-		t2lm_control,
-		WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_IDX,
-		WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_BITS);
+	t2lm_debug("direction:%d default_link_mapping:%d mapping_switch_time_present:%d expected_duration_present:%d",
+		   t2lm->direction, t2lm->default_link_mapping,
+		    t2lm->mapping_switch_time_present,
+		    t2lm->expected_duration_present);
 
-	link_mapping_of_tids = t2lm_control_field + sizeof(t2lm_control);
+	if (t2lm->default_link_mapping) {
+		ie_ptr = t2lm_control_field + sizeof(uint8_t);
+	} else {
+		link_mapping_presence_ind =
+			QDF_GET_BITS(t2lm_control,
+				     WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_IDX,
+				     WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_BITS);
+		ie_ptr = t2lm_control_field + sizeof(t2lm_control);
+	}
 
-	ret = wlan_mlo_parse_t2lm_provisioned_links(peer,
-						    link_mapping_presence_ind,
-						    link_mapping_of_tids, t2lm,
-						    dir);
-	if (ret) {
-		t2lm_err("failed to populate provisioned links");
-		return ret;
+	if (t2lm->mapping_switch_time_present) {
+		t2lm->mapping_switch_time =
+			qdf_le16_to_cpu(*(uint16_t *)ie_ptr);
+		ie_ptr += sizeof(uint16_t);
 	}
 
+	if (t2lm->expected_duration_present) {
+		qdf_mem_copy(&t2lm->expected_duration, ie_ptr,
+			     WLAN_T2LM_EXPECTED_DURATION_SIZE *
+			     (sizeof(uint8_t)));
+		ie_ptr += WLAN_T2LM_EXPECTED_DURATION_SIZE * (sizeof(uint8_t));
+	}
+
+	t2lm_debug("direction:%d default_link_mapping:%d mapping_switch_time:%d expected_duration:%d",
+		   t2lm->direction, t2lm->default_link_mapping,
+		   t2lm->mapping_switch_time, t2lm->expected_duration);
+
+	if (t2lm->default_link_mapping)
+		return QDF_STATUS_SUCCESS;
+
+	link_mapping_of_tids = ie_ptr;
+
 	for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
-		if (link_mapping_presence_ind & BIT(tid_num))
-			t2lm_debug("link mapping of TID%d is %x", tid_num,
-				   t2lm->t2lm_info[dir].hw_link_map_tid[tid_num]);
+		if (!(link_mapping_presence_ind & BIT(tid_num)))
+			continue;
+
+		t2lm->ieee_link_map_tid[tid_num] =
+		    qdf_le16_to_cpu(*(uint16_t *)link_mapping_of_tids);
+
+		t2lm_debug("link mapping of TID%d is %x", tid_num,
+			   t2lm->ieee_link_map_tid[tid_num]);
+
+		link_mapping_of_tids += sizeof(uint16_t);
 	}
 
-	return ret;
+	return QDF_STATUS_SUCCESS;
 }
 
-QDF_STATUS wlan_mlo_parse_t2lm_ie(
-		struct wlan_objmgr_peer *peer,
-		struct wlan_t2lm_onging_negotiation_info *t2lm, uint8_t *ie)
+QDF_STATUS wlan_mlo_parse_bcn_prbresp_t2lm_ie(
+		struct wlan_t2lm_context *t2lm_ctx, uint8_t *ie)
 {
 	struct extn_ie_header *ext_ie_hdr;
-	enum wlan_t2lm_direction dir;
 	QDF_STATUS retval;
+	int i = 0;
 
-	if (!peer) {
-		t2lm_err("null peer");
-		return QDF_STATUS_E_NULL_VALUE;
+	for (i = 0; i < t2lm_ctx->num_of_t2lm_ie; i++) {
+		qdf_mem_zero(&t2lm_ctx->t2lm_ie[i].t2lm,
+			     sizeof(struct wlan_t2lm_info));
+		t2lm_ctx->t2lm_ie[i].t2lm.direction =
+			WLAN_T2LM_INVALID_DIRECTION;
 	}
 
+	t2lm_ctx->num_of_t2lm_ie = 0;
+
+	for (i = 0; i < WLAN_MAX_T2LM_IE; i++) {
+		if (!ie) {
+			t2lm_err("ie is null");
+			return QDF_STATUS_E_NULL_VALUE;
+		}
+
+		ext_ie_hdr = (struct extn_ie_header *)ie;
+
+		if (ext_ie_hdr->ie_id == WLAN_ELEMID_EXTN_ELEM &&
+		    ext_ie_hdr->ie_extn_id == WLAN_EXTN_ELEMID_T2LM) {
+			retval = wlan_mlo_parse_t2lm_info(
+					ie, &t2lm_ctx->t2lm_ie[i].t2lm);
+			if (retval) {
+				t2lm_err("Failed to parse the T2LM IE");
+				return retval;
+			}
+
+			t2lm_ctx->num_of_t2lm_ie++;
+
+			ie += ext_ie_hdr->ie_len + sizeof(struct ie_header);
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_mlo_parse_t2lm_ie(
+		struct wlan_t2lm_onging_negotiation_info *t2lm, uint8_t *ie)
+{
+	struct extn_ie_header *ext_ie_hdr = NULL;
+	QDF_STATUS retval;
+	enum wlan_t2lm_direction dir;
+	struct wlan_t2lm_info t2lm_info;
+
 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++)
 		t2lm->t2lm_info[dir].direction = WLAN_T2LM_INVALID_DIRECTION;
 
@@ -231,8 +194,14 @@ QDF_STATUS wlan_mlo_parse_t2lm_ie(
 
 		if (ext_ie_hdr->ie_id == WLAN_ELEMID_EXTN_ELEM &&
 		    ext_ie_hdr->ie_extn_id == WLAN_EXTN_ELEMID_T2LM) {
-			retval = wlan_mlo_parse_t2lm_info(peer, ie, t2lm);
-			if (retval) {
+			qdf_mem_zero(&t2lm_info, sizeof(t2lm_info));
+			retval = wlan_mlo_parse_t2lm_info(ie, &t2lm_info);
+			if (!retval &&
+			    t2lm_info.direction < WLAN_T2LM_MAX_DIRECTION) {
+				qdf_mem_copy(&t2lm->t2lm_info[t2lm_info.direction],
+					     &t2lm_info,
+					     sizeof(struct wlan_t2lm_info));
+			} else {
 				t2lm_err("Failed to parse the T2LM IE");
 				return retval;
 			}
@@ -261,125 +230,13 @@ QDF_STATUS wlan_mlo_parse_t2lm_ie(
 }
 
 /**
- * wlan_get_ieee_link_id_mask() - Get ieee_link_id mask from hw_link_id mask
- * @wlan_vdev_list: Pointer to vdev list
- * @vdev_count: vdev count
- * @hw_link_id_mask: hw_link_id mask
- *
- * Return: IEEE link ID mask
- */
-static uint8_t wlan_get_ieee_link_id_mask(
-		struct wlan_objmgr_vdev **wlan_vdev_list,
-		uint16_t vdev_count, uint16_t hw_link_id_mask)
-{
-	struct wlan_objmgr_pdev *pdev;
-	struct wlan_objmgr_vdev *vdev;
-	uint8_t link_id;
-	uint16_t hw_link_id;
-	uint16_t ieee_link_id_mask = 0;
-	int i;
-
-	for (link_id = 0; link_id < WLAN_T2LM_MAX_NUM_LINKS; link_id++) {
-		hw_link_id = hw_link_id_mask & BIT(link_id);
-		if (!hw_link_id)
-			continue;
-
-		for (i = 0; i < vdev_count; i++) {
-			vdev = wlan_vdev_list[i];
-			if (!vdev) {
-				t2lm_err("vdev is null");
-				continue;
-			}
-
-			pdev = wlan_vdev_get_pdev(vdev);
-			if (!pdev) {
-				t2lm_err("pdev is null");
-				continue;
-			}
-
-			if (hw_link_id != BIT(wlan_mlo_get_pdev_hw_link_id(pdev)))
-				continue;
-
-			ieee_link_id_mask |= BIT(vdev->vdev_mlme.mlo_link_id);
-			break;
-		}
-	}
-
-	return ieee_link_id_mask;
-}
-
-/**
- * wlan_mlo_add_t2lm_provisioned_links() - API to add provisioned links in the
- * T2LM IE
- * @peer: Pointer to peer structure
- * @link_mapping_presence_indicator: This indicates whether the link mapping of
- *                                   TIDs present in the T2LM IE.
- * @link_mapping_of_tids: Link mapping of each TID
- * @t2lm: Pointer to a T2LM structure
- * @num_tids: Pointer to save num TIDs
- *
- * Return: QDF_STATUS
- */
-static QDF_STATUS wlan_mlo_add_t2lm_provisioned_links(
-		struct wlan_objmgr_peer *peer,
-		uint8_t link_mapping_presence_indicator,
-		uint8_t *link_mapping_of_tids, struct wlan_t2lm_info *t2lm,
-		uint8_t *num_tids)
-{
-	struct wlan_objmgr_vdev *vdev;
-	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {0};
-	uint16_t vdev_count = 0;
-	uint16_t hw_link_id_mask;
-	uint16_t ieee_link_id_mask;
-	uint8_t tid_num;
-	uint16_t i;
-
-	vdev = wlan_peer_get_vdev(peer);
-	if (!vdev) {
-		t2lm_err("vdev is null");
-		return QDF_STATUS_E_NULL_VALUE;
-	}
-
-	mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list);
-	if (!vdev_count) {
-		t2lm_err("Number of VDEVs under MLD is reported as 0");
-		return QDF_STATUS_E_NULL_VALUE;
-	}
-
-	for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
-		ieee_link_id_mask = 0;
-
-		if (t2lm->hw_link_map_tid[tid_num]) {
-			hw_link_id_mask = t2lm->hw_link_map_tid[tid_num];
-			ieee_link_id_mask = wlan_get_ieee_link_id_mask(
-					wlan_vdev_list, vdev_count,
-					hw_link_id_mask);
-		}
-
-		*(uint16_t *)link_mapping_of_tids = ieee_link_id_mask;
-		t2lm_info("link mapping of TID%d is %x", tid_num,
-			  ieee_link_id_mask);
-		link_mapping_of_tids += sizeof(uint16_t);
-		(*num_tids)++;
-	}
-
-	for (i = 0; i < vdev_count; i++)
-		mlo_release_vdev_ref(wlan_vdev_list[i]);
-
-	return QDF_STATUS_SUCCESS;
-}
-
-/**
- * wlan_add_t2lm_info_ie() - Add T2LM IE for UL/DL/Bidirection
+ * wlan_mlo_add_t2lm_info_ie() - Add T2LM IE for UL/DL/Bidirection
  * @frm: Pointer to buffer
- * @peer: Pointer to peer structure
  * @t2lm: Pointer to t2lm mapping structure
  *
  * Return: Updated frame pointer
  */
-static uint8_t *wlan_add_t2lm_info_ie(uint8_t *frm,
-				      struct wlan_objmgr_peer *peer,
-				      struct wlan_t2lm_info *t2lm)
+uint8_t *wlan_mlo_add_t2lm_info_ie(uint8_t *frm, struct wlan_t2lm_info *t2lm)
 {
 	struct wlan_ie_tid_to_link_mapping *t2lm_ie;
 	uint16_t t2lm_control = 0;
@@ -388,8 +245,6 @@ static uint8_t *wlan_add_t2lm_info_ie(uint8_t *frm,
 	uint8_t tid_num;
 	uint8_t num_tids = 0;
 	uint8_t link_mapping_presence_indicator = 0;
-	uint8_t *efrm = frm;
-	int ret;
 
 	t2lm_ie = (struct wlan_ie_tid_to_link_mapping *)frm;
 	t2lm_ie->elem_id = WLAN_ELEMID_EXTN_ELEM;
@@ -406,6 +261,16 @@ static uint8_t *wlan_add_t2lm_info_ie(uint8_t *frm,
 		     WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_BITS,
 		     t2lm->default_link_mapping);
 
+	QDF_SET_BITS(t2lm_control,
+		     WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_IDX,
+		     WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_BITS,
+		     t2lm->mapping_switch_time_present);
+
+	QDF_SET_BITS(t2lm_control,
+		     WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_IDX,
+		     WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_BITS,
+		     t2lm->expected_duration_present);
+
 	if (t2lm->default_link_mapping) {
 		/* Link mapping of TIDs are not present when default mapping is
 		 * set. Hence, the size of TID-To-Link mapping control is one
@@ -415,8 +280,8 @@ static uint8_t *wlan_add_t2lm_info_ie(uint8_t *frm,
 
 		t2lm_ie->elem_len += sizeof(uint8_t);
 
-		t2lm_info("T2LM IE added, default_link_mapping: %d dir:%d",
-			  t2lm->default_link_mapping, t2lm->direction);
+		t2lm_rl_debug("T2LM IE added, default_link_mapping: %d dir:%d",
+			      t2lm->default_link_mapping, t2lm->direction);
 
 		frm += sizeof(*t2lm_ie) + sizeof(uint8_t);
 	} else {
@@ -428,35 +293,59 @@ static uint8_t *wlan_add_t2lm_info_ie(uint8_t *frm,
 			     WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_IDX,
 			     WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_BITS,
 			     link_mapping_presence_indicator);
-		t2lm_info("T2LM IE added, direction:%d link_mapping_presence_indicator:%x",
-			  t2lm->direction, link_mapping_presence_indicator);
+		t2lm_rl_debug("T2LM IE added, direction:%d link_mapping_presence_indicator:%x",
+			      t2lm->direction, link_mapping_presence_indicator);
 
 		/* The size of TID-To-Link mapping control is two octets when
 		 * default link mapping is not set.
 		 */
 		*(uint16_t *)t2lm_control_field = htole16(t2lm_control);
+		frm += sizeof(*t2lm_ie) + sizeof(uint16_t);
+		t2lm_ie->elem_len += sizeof(uint16_t);
+	}
 
-		link_mapping_of_tids = t2lm_control_field + sizeof(uint16_t);
+	if (t2lm->mapping_switch_time_present) {
+		*frm = htole16(t2lm->mapping_switch_time);
+		frm += sizeof(uint16_t);
+		t2lm_ie->elem_len += sizeof(uint16_t);
+	}
 
-		ret = wlan_mlo_add_t2lm_provisioned_links(
-			peer, link_mapping_presence_indicator,
-			link_mapping_of_tids, t2lm, &num_tids);
-		if (ret) {
-			t2lm_err("Failed to add t2lm provisioned links");
-			return efrm;
-		}
+	if (t2lm->expected_duration_present) {
+		qdf_mem_copy(frm, &t2lm->expected_duration,
+			     WLAN_T2LM_EXPECTED_DURATION_SIZE *
+			     sizeof(uint8_t));
+		frm += WLAN_T2LM_EXPECTED_DURATION_SIZE;
+		t2lm_ie->elem_len +=
+			WLAN_T2LM_EXPECTED_DURATION_SIZE * sizeof(uint8_t);
+	}
+
+	t2lm_rl_debug("mapping_switch_time:%d expected_duration:%u",
+		      t2lm->mapping_switch_time, t2lm->expected_duration);
 
-		t2lm_ie->elem_len += sizeof(uint16_t) +
-				     (num_tids * sizeof(uint16_t));
+	if (t2lm->default_link_mapping)
+		return frm;
+
+	link_mapping_of_tids = frm;
+
+	for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
+		if (!t2lm->ieee_link_map_tid[tid_num])
+			continue;
 
-		frm += sizeof(*t2lm_ie) + sizeof(uint16_t) +
-		       (num_tids * sizeof(uint16_t));
+		*(uint16_t *)link_mapping_of_tids =
+			htole16(t2lm->ieee_link_map_tid[tid_num]);
+		t2lm_rl_debug("link mapping of TID%d is %x", tid_num,
+			      htole16(t2lm->ieee_link_map_tid[tid_num]));
+		link_mapping_of_tids += sizeof(uint16_t);
+		num_tids++;
 	}
 
+	frm += num_tids * sizeof(uint16_t);
+	t2lm_ie->elem_len += (num_tids * sizeof(uint16_t));
+
 	return frm;
 }
 
-uint8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm, struct wlan_objmgr_peer *peer,
+uint8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm,
 			      struct wlan_t2lm_onging_negotiation_info *t2lm)
 {
 	uint8_t dir;
@@ -487,8 +376,8 @@ uint8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm, struct wlan_objmgr_peer *peer,
 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {
 		if (t2lm->t2lm_info[dir].direction !=
 			WLAN_T2LM_INVALID_DIRECTION)
-			frm = wlan_add_t2lm_info_ie(frm, peer,
-						    &t2lm->t2lm_info[dir]);
+			frm = wlan_mlo_add_t2lm_info_ie(frm,
+							&t2lm->t2lm_info[dir]);
 	}
 
 	return frm;
@@ -497,7 +386,6 @@ uint8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm, struct wlan_objmgr_peer *peer,
 /**
  * wlan_mlo_parse_t2lm_request_action_frame() - API to parse T2LM request action
  * frame.
- * @peer: Pointer to peer structure
  * @t2lm: Pointer to T2LM structure
  * @action_frm: Pointer to action frame
  * @category: T2LM action frame category
@@ -505,7 +393,6 @@ uint8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm, struct wlan_objmgr_peer *peer,
  * Return: QDF_STATUS
  */
 static QDF_STATUS wlan_mlo_parse_t2lm_request_action_frame(
-		struct wlan_objmgr_peer *peer,
 		struct wlan_t2lm_onging_negotiation_info *t2lm,
 		struct wlan_action_frame *action_frm,
 		enum wlan_t2lm_category category)
@@ -530,14 +417,13 @@ static QDF_STATUS wlan_mlo_parse_t2lm_request_action_frame(
 
 	t2lm->dialog_token = *t2lm_action_frm;
 
-	return wlan_mlo_parse_t2lm_ie(peer, t2lm,
+	return wlan_mlo_parse_t2lm_ie(t2lm,
 				      t2lm_action_frm + sizeof(uint8_t));
 }
 
 /**
  * wlan_mlo_parse_t2lm_response_action_frame() - API to parse T2LM response
  * action frame.
- * @peer: Pointer to peer structure
  * @t2lm: Pointer to T2LM structure
  * @action_frm: Pointer to action frame
  * @category: T2LM action frame category
@@ -545,7 +431,6 @@ static QDF_STATUS wlan_mlo_parse_t2lm_request_action_frame(
  * Return: QDF_STATUS
  */
 static QDF_STATUS wlan_mlo_parse_t2lm_response_action_frame(
-		struct wlan_objmgr_peer *peer,
 		struct wlan_t2lm_onging_negotiation_info *t2lm,
 		struct wlan_action_frame *action_frm,
 		enum wlan_t2lm_category category)
@@ -574,14 +459,13 @@ static QDF_STATUS wlan_mlo_parse_t2lm_response_action_frame(
 	if (t2lm->t2lm_resp_type ==
 			WLAN_T2LM_RESP_TYPE_PREFERRED_TID_TO_LINK_MAPPING) {
 		t2lm_action_frm += sizeof(uint8_t) + sizeof(uint8_t);
-		ret_val = wlan_mlo_parse_t2lm_ie(peer, t2lm, t2lm_action_frm);
+		ret_val = wlan_mlo_parse_t2lm_ie(t2lm, t2lm_action_frm);
 	}
 
 	return ret_val;
 }
 
 int wlan_mlo_parse_t2lm_action_frame(
-		struct wlan_objmgr_peer *peer,
 		struct wlan_t2lm_onging_negotiation_info *t2lm,
 		struct wlan_action_frame *action_frm,
 		enum wlan_t2lm_category category)
@@ -592,13 +476,13 @@ int wlan_mlo_parse_t2lm_action_frame(
 	case WLAN_T2LM_CATEGORY_REQUEST:
 		{
 			ret_val = wlan_mlo_parse_t2lm_request_action_frame(
-					peer, t2lm, action_frm, category);
+					t2lm, action_frm, category);
 			return qdf_status_to_os_return(ret_val);
 		}
 	case WLAN_T2LM_CATEGORY_RESPONSE:
 		{
 			ret_val = wlan_mlo_parse_t2lm_response_action_frame(
-					peer, t2lm, action_frm, category);
+					t2lm, action_frm, category);
 
 			return qdf_status_to_os_return(ret_val);
 		}
@@ -625,7 +509,7 @@ int wlan_mlo_parse_t2lm_action_frame(
 }
 
 static uint8_t *wlan_mlo_add_t2lm_request_action_frame(
-		struct wlan_objmgr_peer *peer, uint8_t *frm,
+		uint8_t *frm,
 		struct wlan_action_frame_args *args, uint8_t *buf,
 		enum wlan_t2lm_category category)
 {
@@ -636,11 +520,11 @@ static uint8_t *wlan_mlo_add_t2lm_request_action_frame(
 
 	t2lm_info("T2LM request frame: category:%d action:%d dialog_token:%d",
 		  args->category, args->action, args->arg1);
-	return wlan_mlo_add_t2lm_ie(frm, peer, (void *)buf);
+	return wlan_mlo_add_t2lm_ie(frm, (void *)buf);
 }
 
 static uint8_t *wlan_mlo_add_t2lm_response_action_frame(
-		struct wlan_objmgr_peer *peer, uint8_t *frm,
+		uint8_t *frm,
 		struct wlan_action_frame_args *args, uint8_t *buf,
 		enum wlan_t2lm_category category)
 {
@@ -655,27 +539,23 @@ static uint8_t *wlan_mlo_add_t2lm_response_action_frame(
 		  args->category, args->action, args->arg1, args->arg2);
 
 	if (args->arg2 == WLAN_T2LM_RESP_TYPE_PREFERRED_TID_TO_LINK_MAPPING)
-		frm = wlan_mlo_add_t2lm_ie(frm, peer, (void *)buf);
+		frm = wlan_mlo_add_t2lm_ie(frm, (void *)buf);
 
 	return frm;
 }
 
 uint8_t *wlan_mlo_add_t2lm_action_frame(
-		struct wlan_objmgr_peer *peer, uint8_t *frm,
+		uint8_t *frm,
 		struct wlan_action_frame_args *args, uint8_t *buf,
 		enum wlan_t2lm_category category)
 {
-	if (!peer) {
-		t2lm_err("null peer");
-		return NULL;
-	}
 
 	switch (category) {
 	case WLAN_T2LM_CATEGORY_REQUEST:
-		return wlan_mlo_add_t2lm_request_action_frame(peer, frm, args,
+		return wlan_mlo_add_t2lm_request_action_frame(frm, args,
 							      buf, category);
 	case WLAN_T2LM_CATEGORY_RESPONSE:
-		return wlan_mlo_add_t2lm_response_action_frame(peer, frm, args,
+		return wlan_mlo_add_t2lm_response_action_frame(frm, args,
 							      buf, category);
 	case WLAN_T2LM_CATEGORY_TEARDOWN:
 		*frm++ = args->category;