xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_t2lm.c (revision 70a19e16789e308182f63b15c75decec7bf0b342)
1 /*
2  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /**
18  * DOC: contains T2LM APIs
19  */
20 
21 #include <wlan_objmgr_pdev_obj.h>
22 #include <wlan_objmgr_vdev_obj.h>
23 #include <wlan_objmgr_peer_obj.h>
24 #include <wlan_mlo_mgr_public_structs.h>
25 #include <wlan_mlo_t2lm.h>
26 #include <wlan_mlo_mgr_cmn.h>
27 #include <qdf_util.h>
28 #include <wlan_cm_api.h>
29 
30 QDF_STATUS wlan_mlo_parse_t2lm_info(uint8_t *ie,
31 				    struct wlan_t2lm_info *t2lm)
32 {
33 	struct wlan_ie_tid_to_link_mapping *t2lm_ie;
34 	enum wlan_t2lm_direction dir;
35 	uint8_t *t2lm_control_field;
36 	uint16_t t2lm_control;
37 	uint8_t link_mapping_presence_ind;
38 	uint8_t *link_mapping_of_tids;
39 	uint8_t tid_num;
40 	uint8_t *ie_ptr = NULL;
41 
42 	t2lm_ie = (struct wlan_ie_tid_to_link_mapping *)ie;
43 
44 	t2lm_control_field = t2lm_ie->data;
45 	if (!t2lm_control_field) {
46 		t2lm_err("t2lm_control_field is null");
47 		return QDF_STATUS_E_NULL_VALUE;
48 	}
49 
50 	t2lm_control = qdf_le16_to_cpu(*(uint16_t *)t2lm_control_field);
51 
52 	dir = QDF_GET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DIRECTION_IDX,
53 			   WLAN_T2LM_CONTROL_DIRECTION_BITS);
54 	if (dir > WLAN_T2LM_BIDI_DIRECTION) {
55 		t2lm_err("Invalid direction");
56 		return QDF_STATUS_E_NULL_VALUE;
57 	}
58 
59 	t2lm->direction = dir;
60 	t2lm->default_link_mapping =
61 		QDF_GET_BITS(t2lm_control,
62 			     WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_IDX,
63 			     WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_BITS);
64 
65 	t2lm->mapping_switch_time_present =
66 		QDF_GET_BITS(t2lm_control,
67 			     WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_IDX,
68 			     WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_BITS);
69 
70 	t2lm->expected_duration_present =
71 		QDF_GET_BITS(t2lm_control,
72 			     WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_IDX,
73 			     WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_BITS);
74 
75 	t2lm_debug("direction:%d default_link_mapping:%d mapping_switch_time_present:%d expected_duration_present:%d",
76 		   t2lm->direction, t2lm->default_link_mapping,
77 		    t2lm->mapping_switch_time_present,
78 		    t2lm->expected_duration_present);
79 
80 	if (t2lm->default_link_mapping) {
81 		ie_ptr = t2lm_control_field + sizeof(uint8_t);
82 	} else {
83 		link_mapping_presence_ind =
84 			QDF_GET_BITS(t2lm_control,
85 				     WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_IDX,
86 				     WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_BITS);
87 		ie_ptr = t2lm_control_field + sizeof(t2lm_control);
88 	}
89 
90 	if (t2lm->mapping_switch_time_present) {
91 		t2lm->mapping_switch_time =
92 			qdf_le16_to_cpu(*(uint16_t *)ie_ptr);
93 		ie_ptr += sizeof(uint16_t);
94 	}
95 
96 	if (t2lm->expected_duration_present) {
97 		qdf_mem_copy(&t2lm->expected_duration, ie_ptr,
98 			     WLAN_T2LM_EXPECTED_DURATION_SIZE *
99 			     (sizeof(uint8_t)));
100 		ie_ptr += WLAN_T2LM_EXPECTED_DURATION_SIZE * (sizeof(uint8_t));
101 	}
102 
103 	t2lm_debug("mapping_switch_time:%d expected_duration:%d",
104 		   t2lm->mapping_switch_time, t2lm->expected_duration);
105 
106 	if (t2lm->default_link_mapping)
107 		return QDF_STATUS_SUCCESS;
108 
109 	link_mapping_of_tids = ie_ptr;
110 
111 	for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
112 		if (!(link_mapping_presence_ind & BIT(tid_num)))
113 			continue;
114 
115 		t2lm->ieee_link_map_tid[tid_num] =
116 		    qdf_le16_to_cpu(*(uint16_t *)link_mapping_of_tids);
117 
118 		t2lm_rl_debug("link mapping of TID%d is %x", tid_num,
119 			      t2lm->ieee_link_map_tid[tid_num]);
120 
121 		link_mapping_of_tids += sizeof(uint16_t);
122 	}
123 
124 	return QDF_STATUS_SUCCESS;
125 }
126 
127 QDF_STATUS wlan_mlo_parse_bcn_prbresp_t2lm_ie(
128 		struct wlan_t2lm_context *t2lm_ctx, uint8_t *ie)
129 {
130 	struct wlan_t2lm_info t2lm = {0};
131 	struct extn_ie_header *ext_ie_hdr;
132 	QDF_STATUS retval;
133 	int i = 0;
134 
135 	qdf_mem_zero(&t2lm_ctx->established_t2lm,
136 		     sizeof(struct wlan_mlo_t2lm_ie));
137 	qdf_mem_zero(&t2lm_ctx->upcoming_t2lm, sizeof(struct wlan_mlo_t2lm_ie));
138 
139 	t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION;
140 	t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION;
141 
142 	for (i = 0; i < WLAN_MAX_T2LM_IE; i++) {
143 		if (!ie) {
144 			t2lm_err("ie is null");
145 			return QDF_STATUS_E_NULL_VALUE;
146 		}
147 
148 		ext_ie_hdr = (struct extn_ie_header *)ie;
149 
150 		if (!(ext_ie_hdr->ie_id == WLAN_ELEMID_EXTN_ELEM &&
151 		      ext_ie_hdr->ie_extn_id == WLAN_EXTN_ELEMID_T2LM))
152 			continue;
153 
154 		t2lm.direction = WLAN_T2LM_INVALID_DIRECTION;
155 		retval = wlan_mlo_parse_t2lm_info(ie, &t2lm);
156 		if (retval) {
157 			t2lm_err("Failed to parse the T2LM IE");
158 			return retval;
159 		}
160 
161 		if (!t2lm.mapping_switch_time_present &&
162 		    t2lm.expected_duration_present) {
163 			qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm, &t2lm,
164 				     sizeof(struct wlan_t2lm_info));
165 		} else if (t2lm.mapping_switch_time_present) {
166 			qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm, &t2lm,
167 				     sizeof(struct wlan_t2lm_info));
168 		}
169 
170 		ie += ext_ie_hdr->ie_len + sizeof(struct ie_header);
171 	}
172 
173 	return QDF_STATUS_SUCCESS;
174 }
175 
176 QDF_STATUS wlan_mlo_parse_t2lm_ie(
177 		struct wlan_t2lm_onging_negotiation_info *t2lm, uint8_t *ie)
178 {
179 	struct extn_ie_header *ext_ie_hdr = NULL;
180 	QDF_STATUS retval;
181 	enum wlan_t2lm_direction dir;
182 	struct wlan_t2lm_info t2lm_info;
183 
184 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++)
185 		t2lm->t2lm_info[dir].direction = WLAN_T2LM_INVALID_DIRECTION;
186 
187 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {
188 		if (!ie) {
189 			t2lm_err("ie is null");
190 			return QDF_STATUS_E_NULL_VALUE;
191 		}
192 
193 		ext_ie_hdr = (struct extn_ie_header *)ie;
194 
195 		if (ext_ie_hdr->ie_id == WLAN_ELEMID_EXTN_ELEM &&
196 		    ext_ie_hdr->ie_extn_id == WLAN_EXTN_ELEMID_T2LM) {
197 			qdf_mem_zero(&t2lm_info, sizeof(t2lm_info));
198 			retval = wlan_mlo_parse_t2lm_info(ie, &t2lm_info);
199 			if (!retval &&
200 			    t2lm_info.direction < WLAN_T2LM_MAX_DIRECTION) {
201 				qdf_mem_copy(&t2lm->t2lm_info[t2lm_info.direction],
202 					     &t2lm_info,
203 					     sizeof(struct wlan_t2lm_info));
204 			} else {
205 				t2lm_err("Failed to parse the T2LM IE");
206 				return retval;
207 			}
208 			ie += ext_ie_hdr->ie_len + sizeof(struct ie_header);
209 		}
210 	}
211 
212 	if ((t2lm->t2lm_info[WLAN_T2LM_DL_DIRECTION].direction ==
213 			WLAN_T2LM_DL_DIRECTION ||
214 	     t2lm->t2lm_info[WLAN_T2LM_UL_DIRECTION].direction ==
215 			WLAN_T2LM_UL_DIRECTION) &&
216 	    t2lm->t2lm_info[WLAN_T2LM_BIDI_DIRECTION].direction ==
217 			WLAN_T2LM_BIDI_DIRECTION) {
218 		t2lm_err("Both DL/UL and BIDI T2LM IEs should not be present at the same time");
219 
220 		qdf_mem_zero(t2lm, sizeof(*t2lm));
221 		for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {
222 			t2lm->t2lm_info[dir].direction =
223 			    WLAN_T2LM_INVALID_DIRECTION;
224 		}
225 
226 		return QDF_STATUS_E_FAILURE;
227 	}
228 
229 	return QDF_STATUS_SUCCESS;
230 }
231 
232 uint8_t *wlan_mlo_add_t2lm_info_ie(uint8_t *frm, struct wlan_t2lm_info *t2lm,
233 				   struct wlan_objmgr_vdev *vdev)
234 {
235 	struct wlan_ie_tid_to_link_mapping *t2lm_ie;
236 	uint16_t t2lm_control = 0;
237 	uint8_t *t2lm_control_field;
238 	uint8_t *link_mapping_of_tids;
239 	uint8_t tid_num;
240 	uint8_t num_tids = 0;
241 	uint8_t link_mapping_presence_indicator = 0;
242 	struct vdev_mlme_obj *vdev_mlme;
243 
244 	t2lm_ie = (struct wlan_ie_tid_to_link_mapping *)frm;
245 	t2lm_ie->elem_id = WLAN_ELEMID_EXTN_ELEM;
246 	t2lm_ie->elem_id_extn = WLAN_EXTN_ELEMID_T2LM;
247 
248 	t2lm_ie->elem_len = sizeof(*t2lm_ie) - sizeof(struct ie_header);
249 
250 	t2lm_control_field = t2lm_ie->data;
251 
252 	QDF_SET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DIRECTION_IDX,
253 		     WLAN_T2LM_CONTROL_DIRECTION_BITS, t2lm->direction);
254 
255 	QDF_SET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_IDX,
256 		     WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_BITS,
257 		     t2lm->default_link_mapping);
258 
259 	QDF_SET_BITS(t2lm_control,
260 		     WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_IDX,
261 		     WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_BITS,
262 		     t2lm->mapping_switch_time_present);
263 
264 	QDF_SET_BITS(t2lm_control,
265 		     WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_IDX,
266 		     WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_BITS,
267 		     t2lm->expected_duration_present);
268 
269 	if (t2lm->default_link_mapping) {
270 		/* Link mapping of TIDs are not present when default mapping is
271 		 * set. Hence, the size of TID-To-Link mapping control is one
272 		 * octet.
273 		 */
274 		*t2lm_control_field = (uint8_t)t2lm_control;
275 
276 		t2lm_ie->elem_len += sizeof(uint8_t);
277 
278 		t2lm_rl_debug("T2LM IE added, default_link_mapping: %d dir:%d",
279 			      t2lm->default_link_mapping, t2lm->direction);
280 
281 		frm += sizeof(*t2lm_ie) + sizeof(uint8_t);
282 	} else {
283 		for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++)
284 			if (t2lm->hw_link_map_tid[tid_num])
285 				link_mapping_presence_indicator |= BIT(tid_num);
286 
287 		QDF_SET_BITS(t2lm_control,
288 			     WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_IDX,
289 			     WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_BITS,
290 			     link_mapping_presence_indicator);
291 		t2lm_rl_debug("T2LM IE added, direction:%d link_mapping_presence_indicator:%x",
292 			      t2lm->direction, link_mapping_presence_indicator);
293 
294 		/* The size of TID-To-Link mapping control is two octets when
295 		 * default link mapping is not set.
296 		 */
297 		*(uint16_t *)t2lm_control_field = htole16(t2lm_control);
298 		frm += sizeof(*t2lm_ie) + sizeof(uint16_t);
299 		t2lm_ie->elem_len += sizeof(uint16_t);
300 	}
301 
302 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
303 	if (vdev_mlme && t2lm->mapping_switch_time_present) {
304 		/* Mapping switch time is different for each vdevs. Hence,
305 		 * populate the mapping switch time from vdev_mlme_obj.
306 		 */
307 		*(uint16_t *)frm =
308 			htole16(vdev_mlme->proto.ap.mapping_switch_time);
309 		frm += sizeof(uint16_t);
310 		t2lm_ie->elem_len += sizeof(uint16_t);
311 	}
312 
313 	if (t2lm->expected_duration_present) {
314 		qdf_mem_copy(frm, &t2lm->expected_duration,
315 			     WLAN_T2LM_EXPECTED_DURATION_SIZE *
316 			     sizeof(uint8_t));
317 		frm += WLAN_T2LM_EXPECTED_DURATION_SIZE * sizeof(uint8_t);
318 		t2lm_ie->elem_len +=
319 			WLAN_T2LM_EXPECTED_DURATION_SIZE * sizeof(uint8_t);
320 	}
321 
322 	t2lm_rl_debug("mapping_switch_time:%d expected_duration:%u",
323 		      t2lm->mapping_switch_time, t2lm->expected_duration);
324 
325 	if (t2lm->default_link_mapping)
326 		return frm;
327 
328 	link_mapping_of_tids = frm;
329 
330 	for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
331 		if (!t2lm->ieee_link_map_tid[tid_num])
332 			continue;
333 
334 		*(uint16_t *)link_mapping_of_tids =
335 			htole16(t2lm->ieee_link_map_tid[tid_num]);
336 		t2lm_rl_debug("link mapping of TID%d is %x", tid_num,
337 			      htole16(t2lm->ieee_link_map_tid[tid_num]));
338 		link_mapping_of_tids += sizeof(uint16_t);
339 		num_tids++;
340 	}
341 
342 	frm += num_tids * sizeof(uint16_t);
343 	t2lm_ie->elem_len += (num_tids * sizeof(uint16_t));
344 
345 	return frm;
346 }
347 
348 uint8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm,
349 			      struct wlan_t2lm_onging_negotiation_info *t2lm,
350 			      struct wlan_objmgr_vdev *vdev)
351 {
352 	uint8_t dir;
353 
354 	if (!frm) {
355 		t2lm_err("frm is null");
356 		return NULL;
357 	}
358 
359 	if (!t2lm) {
360 		t2lm_err("t2lm is null");
361 		return NULL;
362 	}
363 
364 	/* As per spec, the frame should include one or two T2LM IEs. When it is
365 	 * two, then direction should DL and UL.
366 	 */
367 	if ((t2lm->t2lm_info[WLAN_T2LM_DL_DIRECTION].direction ==
368 			WLAN_T2LM_DL_DIRECTION ||
369 	     t2lm->t2lm_info[WLAN_T2LM_UL_DIRECTION].direction ==
370 			WLAN_T2LM_UL_DIRECTION) &&
371 	    t2lm->t2lm_info[WLAN_T2LM_BIDI_DIRECTION].direction ==
372 			WLAN_T2LM_BIDI_DIRECTION) {
373 		t2lm_err("Both DL/UL and BIDI T2LM IEs should not be present at the same time");
374 		return NULL;
375 	}
376 
377 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {
378 		if (t2lm->t2lm_info[dir].direction !=
379 			WLAN_T2LM_INVALID_DIRECTION)
380 			frm = wlan_mlo_add_t2lm_info_ie(frm,
381 							&t2lm->t2lm_info[dir],
382 							vdev);
383 	}
384 
385 	return frm;
386 }
387 
388 /**
389  * wlan_mlo_parse_t2lm_request_action_frame() - API to parse T2LM request action
390  * frame.
391  * @t2lm: Pointer to T2LM structure
392  * @action_frm: Pointer to action frame
393  * @category: T2LM action frame category
394  *
395  * Return: QDF_STATUS
396  */
397 static QDF_STATUS wlan_mlo_parse_t2lm_request_action_frame(
398 		struct wlan_t2lm_onging_negotiation_info *t2lm,
399 		struct wlan_action_frame *action_frm,
400 		enum wlan_t2lm_category category)
401 {
402 	uint8_t *t2lm_action_frm;
403 
404 	t2lm->category = category;
405 
406 	/*
407 	 * T2LM request action frame
408 	 *
409 	 *   1-byte     1-byte     1-byte   variable
410 	 *-------------------------------------------
411 	 * |         |           |        |         |
412 	 * | Category| Protected | Dialog | T2LM IE |
413 	 * |         |    EHT    | token  |         |
414 	 * |         |  Action   |        |         |
415 	 *-------------------------------------------
416 	 */
417 
418 	t2lm_action_frm = (uint8_t *)action_frm + sizeof(*action_frm);
419 
420 	t2lm->dialog_token = *t2lm_action_frm;
421 
422 	return wlan_mlo_parse_t2lm_ie(t2lm,
423 				      t2lm_action_frm + sizeof(uint8_t));
424 }
425 
426 /**
427  * wlan_mlo_parse_t2lm_response_action_frame() - API to parse T2LM response
428  * action frame.
429  * @t2lm: Pointer to T2LM structure
430  * @action_frm: Pointer to action frame
431  * @category: T2LM action frame category
432  *
433  * Return: QDF_STATUS
434  */
435 static QDF_STATUS wlan_mlo_parse_t2lm_response_action_frame(
436 		struct wlan_t2lm_onging_negotiation_info *t2lm,
437 		struct wlan_action_frame *action_frm,
438 		enum wlan_t2lm_category category)
439 {
440 	uint8_t *t2lm_action_frm;
441 	QDF_STATUS ret_val = QDF_STATUS_SUCCESS;
442 
443 	t2lm->category = WLAN_T2LM_CATEGORY_RESPONSE;
444 	/*
445 	 * T2LM response action frame
446 	 *
447 	 *   1-byte     1-byte     1-byte   1-byte   variable
448 	 *----------------------------------------------------
449 	 * |         |           |        |        |         |
450 	 * | Category| Protected | Dialog | Status | T2LM IE |
451 	 * |         |    EHT    | token  |  code  |         |
452 	 * |         |  Action   |        |        |         |
453 	 *----------------------------------------------------
454 	 */
455 
456 	t2lm_action_frm = (uint8_t *)action_frm + sizeof(*action_frm);
457 
458 	t2lm->dialog_token = *t2lm_action_frm;
459 	t2lm->t2lm_resp_type = *(t2lm_action_frm + sizeof(uint8_t));
460 
461 	if (t2lm->t2lm_resp_type ==
462 			WLAN_T2LM_RESP_TYPE_PREFERRED_TID_TO_LINK_MAPPING) {
463 		t2lm_action_frm += sizeof(uint8_t) + sizeof(uint8_t);
464 		ret_val = wlan_mlo_parse_t2lm_ie(t2lm, t2lm_action_frm);
465 	}
466 
467 	return ret_val;
468 }
469 
470 int wlan_mlo_parse_t2lm_action_frame(
471 		struct wlan_t2lm_onging_negotiation_info *t2lm,
472 		struct wlan_action_frame *action_frm,
473 		enum wlan_t2lm_category category)
474 {
475 	QDF_STATUS ret_val = QDF_STATUS_SUCCESS;
476 
477 	switch (category) {
478 	case WLAN_T2LM_CATEGORY_REQUEST:
479 		{
480 			ret_val = wlan_mlo_parse_t2lm_request_action_frame(
481 					t2lm, action_frm, category);
482 			return qdf_status_to_os_return(ret_val);
483 		}
484 	case WLAN_T2LM_CATEGORY_RESPONSE:
485 		{
486 			ret_val = wlan_mlo_parse_t2lm_response_action_frame(
487 					t2lm, action_frm, category);
488 
489 			return qdf_status_to_os_return(ret_val);
490 		}
491 	case WLAN_T2LM_CATEGORY_TEARDOWN:
492 			/* Nothing to parse from T2LM teardown frame, just reset
493 			 * the mapping to default mapping.
494 			 *
495 			 * T2LM teardown action frame
496 			 *
497 			 *   1-byte     1-byte
498 			 *------------------------
499 			 * |         |           |
500 			 * | Category| Protected |
501 			 * |         |    EHT    |
502 			 * |         |  Action   |
503 			 *------------------------
504 			 */
505 			break;
506 	default:
507 			t2lm_err("Invalid category:%d", category);
508 	}
509 
510 	return ret_val;
511 }
512 
513 static uint8_t *wlan_mlo_add_t2lm_request_action_frame(
514 		uint8_t *frm,
515 		struct wlan_action_frame_args *args, uint8_t *buf,
516 		enum wlan_t2lm_category category)
517 {
518 	*frm++ = args->category;
519 	*frm++ = args->action;
520 	/* Dialog token*/
521 	*frm++ = args->arg1;
522 
523 	t2lm_info("T2LM request frame: category:%d action:%d dialog_token:%d",
524 		  args->category, args->action, args->arg1);
525 	return wlan_mlo_add_t2lm_ie(frm, (void *)buf, NULL);
526 }
527 
528 static uint8_t *wlan_mlo_add_t2lm_response_action_frame(
529 		uint8_t *frm,
530 		struct wlan_action_frame_args *args, uint8_t *buf,
531 		enum wlan_t2lm_category category)
532 {
533 	*frm++ = args->category;
534 	*frm++ = args->action;
535 	/* Dialog token*/
536 	*frm++ = args->arg1;
537 	/* Status code */
538 	*frm++ = args->arg2;
539 
540 	t2lm_info("T2LM response frame: category:%d action:%d dialog_token:%d status_code:%d",
541 		  args->category, args->action, args->arg1, args->arg2);
542 
543 	if (args->arg2 == WLAN_T2LM_RESP_TYPE_PREFERRED_TID_TO_LINK_MAPPING)
544 		frm = wlan_mlo_add_t2lm_ie(frm, (void *)buf, NULL);
545 
546 	return frm;
547 }
548 
549 uint8_t *wlan_mlo_add_t2lm_action_frame(
550 		uint8_t *frm,
551 		struct wlan_action_frame_args *args, uint8_t *buf,
552 		enum wlan_t2lm_category category)
553 {
554 
555 	switch (category) {
556 	case WLAN_T2LM_CATEGORY_REQUEST:
557 		return wlan_mlo_add_t2lm_request_action_frame(frm, args,
558 							      buf, category);
559 	case WLAN_T2LM_CATEGORY_RESPONSE:
560 		return wlan_mlo_add_t2lm_response_action_frame(frm, args,
561 							      buf, category);
562 	case WLAN_T2LM_CATEGORY_TEARDOWN:
563 		*frm++ = args->category;
564 		*frm++ = args->action;
565 		return frm;
566 	default:
567 		t2lm_err("Invalid category:%d", category);
568 	}
569 
570 	return frm;
571 }
572 
573 /**
574  * wlan_mlo_t2lm_handle_mapping_switch_time_expiry() - API to handle the mapping
575  * switch timer expiry.
576  * @t2lm_ctx: Pointer to T2LM context
577  * @vdev: Pointer to vdev structure
578  *
579  * Return: None
580  */
581 static void wlan_mlo_t2lm_handle_mapping_switch_time_expiry(
582 		struct wlan_t2lm_context *t2lm_ctx,
583 		struct wlan_objmgr_vdev *vdev)
584 {
585 	struct wlan_t2lm_info *t2lm;
586 
587 	t2lm_debug("Mapping switch time expired for vdev_id:%d ",
588 		   wlan_vdev_get_id(vdev));
589 
590 	qdf_mem_copy(&t2lm_ctx->established_t2lm, &t2lm_ctx->upcoming_t2lm,
591 		     sizeof(struct wlan_mlo_t2lm_ie));
592 
593 	t2lm_ctx->established_t2lm.t2lm.mapping_switch_time_present = false;
594 	t2lm_ctx->established_t2lm.t2lm.mapping_switch_time = 0;
595 
596 	t2lm = &t2lm_ctx->established_t2lm.t2lm;
597 	t2lm_debug("Established mapping: disabled_link_bitmap:%x dir:%d default_map:%d MSTP:%d EDP:%d MST:%d ED:%d ieee_link_map:%x hw_link_map:%x",
598 		   t2lm_ctx->established_t2lm.disabled_link_bitmap,
599 		   t2lm->direction, t2lm->default_link_mapping,
600 		   t2lm->mapping_switch_time_present,
601 		   t2lm->expected_duration_present,
602 		   t2lm->mapping_switch_time, t2lm->expected_duration,
603 		   t2lm->ieee_link_map_tid[0], t2lm->hw_link_map_tid[0]);
604 
605 	qdf_mem_zero(&t2lm_ctx->upcoming_t2lm, sizeof(struct wlan_mlo_t2lm_ie));
606 	t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION;
607 
608 	/* Notify the registered caller about the link update*/
609 	wlan_mlo_dev_t2lm_notify_link_update(vdev->mlo_dev_ctx);
610 }
611 
612 /**
613  * wlan_mlo_t2lm_handle_expected_duration_expiry() - API to handle the expected
614  * duration timer expiry.
615  * @t2lm_ctx: Pointer to T2LM context
616  * @vdev: Pointer to vdev structure
617  *
618  * Return: none
619  */
620 static void wlan_mlo_t2lm_handle_expected_duration_expiry(
621 		struct wlan_t2lm_context *t2lm_ctx,
622 		struct wlan_objmgr_vdev *vdev)
623 {
624 	t2lm_debug("Expected duration expired for vdev_id:%d ",
625 		   wlan_vdev_get_id(vdev));
626 
627 	if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) {
628 		/* Copy the new non-default ongoing mapping to established
629 		 * mapping if expected duration expires for the established
630 		 * mapping.
631 		 */
632 		wlan_mlo_t2lm_handle_mapping_switch_time_expiry(t2lm_ctx,
633 								vdev);
634 		return;
635 	}
636 
637 	/* Use the default mapping when expected duration expires for the
638 	 * established mapping and no new non-default T2LM announcement is
639 	 * ongoing.
640 	 */
641 	qdf_mem_zero(&t2lm_ctx->established_t2lm,
642 		     sizeof(struct wlan_mlo_t2lm_ie));
643 
644 	t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_BIDI_DIRECTION;
645 	t2lm_ctx->established_t2lm.t2lm.default_link_mapping = 1;
646 	t2lm_ctx->established_t2lm.disabled_link_bitmap = 0;
647 	t2lm_debug("Set established mapping to default mapping");
648 
649 	/* Notify the registered caller about the link update*/
650 	wlan_mlo_dev_t2lm_notify_link_update(vdev->mlo_dev_ctx);
651 }
652 
653 QDF_STATUS wlan_mlo_vdev_tid_to_link_map_event(
654 		struct wlan_objmgr_psoc *psoc,
655 		struct mlo_vdev_host_tid_to_link_map_resp *event)
656 {
657 	struct wlan_objmgr_vdev *vdev;
658 	struct wlan_t2lm_context *t2lm_ctx;
659 	struct vdev_mlme_obj *vdev_mlme;
660 
661 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id,
662 						    WLAN_MLO_MGR_ID);
663 	if (!vdev) {
664 		t2lm_err("null vdev");
665 		return QDF_STATUS_E_NULL_VALUE;
666 	}
667 
668 	if (!vdev->mlo_dev_ctx) {
669 		t2lm_err("null mlo_dev_ctx");
670 		return QDF_STATUS_E_NULL_VALUE;
671 	}
672 
673 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
674 	if (!vdev_mlme) {
675 		t2lm_err("null vdev_mlme");
676 		return QDF_STATUS_E_FAILURE;
677 	}
678 
679 	t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
680 
681 	t2lm_debug("psoc_id:%d vdev_id:%d status:%d",
682 		   wlan_psoc_get_id(psoc), event->vdev_id, event->status);
683 
684 	t2lm_dev_lock_acquire(t2lm_ctx);
685 	switch (event->status) {
686 	case WLAN_MAP_SWITCH_TIMER_TSF:
687 
688 		/* Mapping switch time is different for each AP vdev of a given
689 		 * MLD as these vdevs can have separate beacon TDF value.
690 		 */
691 		if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present)
692 			vdev_mlme->proto.ap.mapping_switch_time =
693 				(event->mapping_switch_tsf &
694 				 WLAN_T2LM_MAPPING_SWITCH_TSF_BITS) >> 10;
695 
696 		t2lm_debug("vdev_id:%d updated mapping switch time:%d",
697 			   event->vdev_id,
698 			   vdev_mlme->proto.ap.mapping_switch_time);
699 		break;
700 	case WLAN_MAP_SWITCH_TIMER_EXPIRED:
701 		vdev_mlme->proto.ap.mapping_switch_time = 0;
702 		wlan_mlo_t2lm_handle_mapping_switch_time_expiry(t2lm_ctx, vdev);
703 		break;
704 	case WLAN_EXPECTED_DUR_EXPIRED:
705 		wlan_mlo_t2lm_handle_expected_duration_expiry(t2lm_ctx, vdev);
706 		break;
707 	default:
708 		t2lm_err("Invalid status");
709 	}
710 
711 	t2lm_dev_lock_release(t2lm_ctx);
712 	mlo_release_vdev_ref(vdev);
713 
714 	return QDF_STATUS_SUCCESS;
715 }
716 
717 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
718 static
719 QDF_STATUS wlan_send_t2lm_info(struct wlan_objmgr_vdev *vdev,
720 			       struct wlan_t2lm_info *t2lm,
721 			       struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops)
722 {
723 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
724 
725 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
726 		t2lm_err("vdev is not MLO vdev");
727 		return status;
728 	}
729 
730 	status = mlo_tx_ops->send_tid_to_link_mapping(vdev, t2lm);
731 	if (QDF_IS_STATUS_ERROR(status))
732 		t2lm_err("Failed to send T2LM command to FW");
733 
734 	return status;
735 }
736 #else
737 static
738 QDF_STATUS wlan_send_t2lm_info(struct wlan_objmgr_vdev *vdev,
739 			       struct wlan_t2lm_info *t2lm,
740 			       struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops)
741 {
742 	struct wlan_objmgr_vdev *co_mld_vdev;
743 	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
744 	uint16_t vdev_count = 0;
745 	int i = 0;
746 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
747 
748 	mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list);
749 	if (!vdev_count) {
750 		t2lm_err("Number of VDEVs under MLD is reported as 0");
751 		return QDF_STATUS_E_NULL_VALUE;
752 	}
753 
754 	for (i = 0; i < vdev_count; i++) {
755 		co_mld_vdev = wlan_vdev_list[i];
756 		if (!co_mld_vdev) {
757 			t2lm_err("co_mld_vdev is null");
758 			mlo_release_vdev_ref(co_mld_vdev);
759 			continue;
760 		}
761 
762 		status = mlo_tx_ops->send_tid_to_link_mapping(co_mld_vdev,
763 							      t2lm);
764 		if (QDF_IS_STATUS_ERROR(status))
765 			t2lm_err("Failed to send T2LM command to FW");
766 		mlo_release_vdev_ref(co_mld_vdev);
767 	}
768 
769 	return status;
770 }
771 #endif
772 
773 QDF_STATUS wlan_send_tid_to_link_mapping(struct wlan_objmgr_vdev *vdev,
774 					 struct wlan_t2lm_info *t2lm)
775 {
776 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
777 	struct wlan_objmgr_psoc *psoc;
778 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
779 
780 	psoc = wlan_vdev_get_psoc(vdev);
781 	if (!psoc) {
782 		t2lm_err("null psoc");
783 		return QDF_STATUS_E_NULL_VALUE;
784 	}
785 
786 	mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops;
787 	if (!mlo_tx_ops) {
788 		t2lm_err("tx_ops is null!");
789 		return QDF_STATUS_E_NULL_VALUE;
790 	}
791 
792 	if (!mlo_tx_ops->send_tid_to_link_mapping) {
793 		t2lm_err("send_tid_to_link_mapping is null");
794 		return QDF_STATUS_E_NULL_VALUE;
795 	}
796 
797 	status = wlan_send_t2lm_info(vdev, t2lm, mlo_tx_ops);
798 
799 	return status;
800 }
801 
802 void wlan_mlo_t2lm_timer_expiry_handler(void *vdev)
803 {
804 	struct wlan_objmgr_vdev *vdev_ctx = (struct wlan_objmgr_vdev *)vdev;
805 
806 	struct wlan_t2lm_timer *t2lm_timer;
807 	struct wlan_t2lm_context *t2lm_ctx;
808 
809 	if (!vdev_ctx || !vdev_ctx->mlo_dev_ctx)
810 		return;
811 
812 	t2lm_ctx = &vdev_ctx->mlo_dev_ctx->t2lm_ctx;
813 	t2lm_timer = &vdev_ctx->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
814 
815 	wlan_mlo_t2lm_timer_stop(vdev_ctx);
816 
817 	/* Since qdf_mutex_acquire cannot be called from interrupt context,
818 	 * change needed to create a workqueue and offload the timer expiry
819 	 * handling to workqueue.
820 	 */
821 	if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present) {
822 		wlan_mlo_t2lm_handle_expected_duration_expiry(t2lm_ctx, vdev);
823 		wlan_send_tid_to_link_mapping(
824 				vdev, &t2lm_ctx->established_t2lm.t2lm);
825 
826 		wlan_handle_t2lm_timer(vdev_ctx);
827 	} else if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) {
828 		wlan_mlo_t2lm_handle_mapping_switch_time_expiry(t2lm_ctx, vdev);
829 		wlan_send_tid_to_link_mapping(
830 				vdev, &t2lm_ctx->established_t2lm.t2lm);
831 
832 		wlan_handle_t2lm_timer(vdev_ctx);
833 	}
834 
835 }
836 
837 QDF_STATUS
838 wlan_mlo_t2lm_timer_init(struct wlan_objmgr_vdev *vdev)
839 {
840 	struct wlan_t2lm_timer *t2lm_timer = NULL;
841 
842 	if (!vdev || !vdev->mlo_dev_ctx)
843 		return QDF_STATUS_E_FAILURE;
844 
845 	t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
846 	if (!t2lm_timer) {
847 		t2lm_err("t2lm timer ctx is null");
848 		return QDF_STATUS_E_NULL_VALUE;
849 	}
850 
851 	t2lm_dev_lock_create(&vdev->mlo_dev_ctx->t2lm_ctx);
852 	t2lm_dev_lock_acquire(&vdev->mlo_dev_ctx->t2lm_ctx);
853 	qdf_timer_init(NULL, &t2lm_timer->t2lm_timer,
854 		       wlan_mlo_t2lm_timer_expiry_handler,
855 		       vdev, QDF_TIMER_TYPE_WAKE_APPS);
856 
857 	t2lm_timer->timer_started = false;
858 	t2lm_timer->timer_interval = 0;
859 	t2lm_timer->timer_out_time = 0;
860 	t2lm_dev_lock_release(&vdev->mlo_dev_ctx->t2lm_ctx);
861 	return QDF_STATUS_SUCCESS;
862 }
863 
864 QDF_STATUS
865 wlan_mlo_t2lm_timer_start(struct wlan_objmgr_vdev *vdev,
866 			  uint32_t interval)
867 {
868 	struct wlan_t2lm_timer *t2lm_timer;
869 	struct wlan_t2lm_context *t2lm_ctx;
870 	uint32_t target_out_time;
871 
872 	if (!interval) {
873 		t2lm_debug("Timer interval is 0");
874 		return QDF_STATUS_E_NULL_VALUE;
875 	}
876 
877 	t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
878 	t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
879 	if (!t2lm_timer) {
880 		t2lm_err("t2lm timer ctx is null");
881 		return QDF_STATUS_E_NULL_VALUE;
882 	}
883 
884 	interval = (interval * 1024) / 1000;
885 	target_out_time = qdf_system_ticks_to_msecs(qdf_system_ticks());
886 	target_out_time += interval;
887 	t2lm_debug("earlier timer @%u ms out, new @%u ms out",
888 		   t2lm_timer->timer_out_time, target_out_time);
889 
890 	/* sometimes the host process the beacon maybe delay, it may help for
891 	 * update the new expected time.
892 	 */
893 	if (t2lm_timer->timer_out_time &&
894 	    (target_out_time > t2lm_timer->timer_out_time ||
895 	     (t2lm_timer->timer_out_time - target_out_time) <
896 	      WLAN_T2LM_MAPPING_SWITCH_TIME_DELAY))
897 		return QDF_STATUS_E_NULL_VALUE;
898 
899 	if (t2lm_timer->timer_started)
900 		qdf_timer_stop(&t2lm_timer->t2lm_timer);
901 
902 	t2lm_debug("t2lm timer started with interval %d ms", interval);
903 	t2lm_timer->timer_interval = interval;
904 	t2lm_timer->timer_started = true;
905 	t2lm_timer->timer_out_time = target_out_time;
906 	qdf_timer_start(&t2lm_timer->t2lm_timer, t2lm_timer->timer_interval);
907 
908 	return QDF_STATUS_SUCCESS;
909 }
910 
911 QDF_STATUS
912 wlan_mlo_t2lm_timer_stop(struct wlan_objmgr_vdev *vdev)
913 {
914 	struct wlan_t2lm_timer *t2lm_timer;
915 
916 	if (!vdev || !vdev->mlo_dev_ctx)
917 		return QDF_STATUS_E_NULL_VALUE;
918 
919 	t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
920 	if (!t2lm_timer) {
921 		t2lm_err("t2lm timer ctx is null");
922 		return QDF_STATUS_E_NULL_VALUE;
923 	}
924 
925 	t2lm_dev_lock_acquire(&vdev->mlo_dev_ctx->t2lm_ctx);
926 	if (t2lm_timer->timer_started) {
927 		qdf_timer_stop(&t2lm_timer->t2lm_timer);
928 		t2lm_timer->timer_started = false;
929 		t2lm_timer->timer_interval = 0;
930 		t2lm_timer->timer_out_time = 0;
931 	}
932 	t2lm_dev_lock_release(&vdev->mlo_dev_ctx->t2lm_ctx);
933 	return QDF_STATUS_SUCCESS;
934 }
935 
936 QDF_STATUS wlan_handle_t2lm_timer(struct wlan_objmgr_vdev *vdev)
937 {
938 	struct wlan_t2lm_context *t2lm_ctx;
939 	struct vdev_mlme_obj *vdev_mlme;
940 	QDF_STATUS status = QDF_STATUS_SUCCESS;
941 
942 	if (!vdev || !vdev->mlo_dev_ctx)
943 		return QDF_STATUS_E_NULL_VALUE;
944 
945 	t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
946 
947 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
948 	if (!vdev_mlme)
949 		return QDF_STATUS_E_FAILURE;
950 
951 	if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present) {
952 		if (t2lm_ctx->established_t2lm.t2lm.expected_duration ==
953 		    T2LM_EXPECTED_DURATION_MAX_VALUE) {
954 			return status;
955 		}
956 
957 		status = wlan_mlo_t2lm_timer_start(
958 				vdev,
959 				t2lm_ctx->established_t2lm.t2lm.expected_duration);
960 	} else if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) {
961 		status = wlan_mlo_t2lm_timer_start(
962 				vdev,
963 				t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time);
964 	}
965 
966 	return status;
967 }
968 
969 /**
970  * wlan_update_mapping_switch_time_expected_dur() - API to update the mapping
971  * switch time and expected duration.
972  * @vdev:Pointer to vdev
973  * @rx_t2lm: Pointer to received T2LM IE
974  * @tsf: TSF value of beacon/probe response
975  *
976  * Return: None
977  */
978 static QDF_STATUS wlan_update_mapping_switch_time_expected_dur(
979 		struct wlan_objmgr_vdev *vdev,
980 		struct wlan_t2lm_context *rx_t2lm, uint64_t tsf)
981 {
982 	struct wlan_t2lm_context *t2lm_ctx;
983 	uint16_t tsf_bit25_10, ms_time;
984 
985 	tsf_bit25_10 = (tsf & WLAN_T2LM_MAPPING_SWITCH_TSF_BITS) >> 10;
986 	t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
987 
988 	t2lm_dev_lock_acquire(t2lm_ctx);
989 
990 	if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present &&
991 	    rx_t2lm->established_t2lm.t2lm.expected_duration_present) {
992 		/* Established T2LM is already saved in the T2LM context.
993 		 * T2LM IE in the beacon/probe response frame has the updated
994 		 * expected duration.
995 		 */
996 		if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid,
997 				 rx_t2lm->established_t2lm.t2lm.ieee_link_map_tid,
998 				 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) {
999 			t2lm_ctx->established_t2lm.t2lm.expected_duration =
1000 				rx_t2lm->established_t2lm.t2lm.expected_duration;
1001 		}
1002 	} else if (rx_t2lm->established_t2lm.t2lm.expected_duration_present &&
1003 		   !rx_t2lm->established_t2lm.t2lm.mapping_switch_time_present) {
1004 		/* Mapping switch time is already expired when STA receives the
1005 		 * T2LM IE from beacon/probe response frame.
1006 		 */
1007 		qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm,
1008 			     &rx_t2lm->established_t2lm.t2lm,
1009 			     sizeof(struct wlan_t2lm_info));
1010 		wlan_send_tid_to_link_mapping(
1011 				vdev, &t2lm_ctx->established_t2lm.t2lm);
1012 	}
1013 
1014 	if (rx_t2lm->upcoming_t2lm.t2lm.mapping_switch_time_present) {
1015 		if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid,
1016 				 rx_t2lm->upcoming_t2lm.t2lm.ieee_link_map_tid,
1017 				 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) {
1018 			t2lm_debug("Ongoing mapping is already established");
1019 			t2lm_dev_lock_release(t2lm_ctx);
1020 			return QDF_STATUS_E_ALREADY;
1021 		}
1022 
1023 		qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm,
1024 			     &rx_t2lm->upcoming_t2lm.t2lm,
1025 			     sizeof(struct wlan_t2lm_info));
1026 
1027 		ms_time = t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time;
1028 		/* Per test, -300ms is fine */
1029 		if (ms_time > tsf_bit25_10) {
1030 			t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time =
1031 				(ms_time - tsf_bit25_10 - (3 * WLAN_T2LM_MAPPING_SWITCH_TIME_DELAY));
1032 		} else {
1033 			t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time =
1034 				0xFFFF - (tsf_bit25_10 - ms_time) - (3 * WLAN_T2LM_MAPPING_SWITCH_TIME_DELAY);
1035 		}
1036 	}
1037 
1038 	t2lm_dev_lock_release(t2lm_ctx);
1039 
1040 	return QDF_STATUS_SUCCESS;
1041 }
1042 
1043 QDF_STATUS wlan_process_bcn_prbrsp_t2lm_ie(
1044 		struct wlan_objmgr_vdev *vdev,
1045 		struct wlan_t2lm_context *rx_t2lm_ie, uint64_t tsf)
1046 {
1047 	struct wlan_t2lm_context *t2lm_ctx;
1048 	QDF_STATUS status;
1049 
1050 	/* Do not parse the T2LM IE if STA is not in connected state */
1051 	if (!wlan_cm_is_vdev_connected(vdev))
1052 		return QDF_STATUS_SUCCESS;
1053 
1054 	t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
1055 
1056 	status = wlan_update_mapping_switch_time_expected_dur(
1057 			vdev, rx_t2lm_ie, tsf);
1058 	if (QDF_IS_STATUS_ERROR(status))
1059 		return status;
1060 
1061 	t2lm_dev_lock_acquire(t2lm_ctx);
1062 	if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present ||
1063 	    t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) {
1064 		wlan_handle_t2lm_timer(vdev);
1065 	}
1066 	t2lm_dev_lock_release(t2lm_ctx);
1067 
1068 	return QDF_STATUS_SUCCESS;
1069 }
1070 
1071 int wlan_register_t2lm_link_update_notify_handler(
1072 		wlan_mlo_t2lm_link_update_handler handler,
1073 		struct wlan_mlo_dev_context *mldev)
1074 {
1075 	struct wlan_t2lm_context *t2lm_ctx = &mldev->t2lm_ctx;
1076 	int i;
1077 
1078 	for (i = 0; i < MAX_T2LM_HANDLERS; i++) {
1079 		if (t2lm_ctx->is_valid_handler[i])
1080 			continue;
1081 
1082 		t2lm_ctx->link_update_handler[i] = handler;
1083 		t2lm_ctx->is_valid_handler[i] = true;
1084 		break;
1085 	}
1086 
1087 	if (i == MAX_T2LM_HANDLERS) {
1088 		t2lm_err("Failed to register the link disablement callback");
1089 		return -EINVAL;
1090 	}
1091 
1092 	return i;
1093 }
1094 
1095 void wlan_unregister_t2lm_link_update_notify_handler(
1096 		struct wlan_mlo_dev_context *mldev,
1097 		uint8_t index)
1098 {
1099 	if (index >= MAX_T2LM_HANDLERS)
1100 		return;
1101 
1102 	mldev->t2lm_ctx.link_update_handler[index] = NULL;
1103 	mldev->t2lm_ctx.is_valid_handler[index] = false;
1104 }
1105 
1106 QDF_STATUS wlan_mlo_dev_t2lm_notify_link_update(
1107 		struct wlan_mlo_dev_context *mldev)
1108 {
1109 	struct wlan_t2lm_context *t2lm_ctx = &mldev->t2lm_ctx;
1110 	wlan_mlo_t2lm_link_update_handler handler;
1111 	int i;
1112 
1113 	for (i = 0; i < MAX_T2LM_HANDLERS; i++) {
1114 		if (!t2lm_ctx->is_valid_handler[i])
1115 			continue;
1116 
1117 		handler = t2lm_ctx->link_update_handler[i];
1118 		if (!handler)
1119 			continue;
1120 
1121 		handler(mldev,
1122 			&t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid[0]);
1123 	}
1124 	return QDF_STATUS_SUCCESS;
1125 }
1126 
1127 QDF_STATUS
1128 wlan_mlo_t2lm_timer_deinit(struct wlan_objmgr_vdev *vdev)
1129 {
1130 	struct wlan_t2lm_timer *t2lm_timer = NULL;
1131 
1132 	if (!vdev || !vdev->mlo_dev_ctx)
1133 		return QDF_STATUS_E_FAILURE;
1134 
1135 	t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
1136 	if (!t2lm_timer) {
1137 		t2lm_err("t2lm timer ctx is null");
1138 		return QDF_STATUS_E_NULL_VALUE;
1139 	}
1140 
1141 	t2lm_dev_lock_acquire(&vdev->mlo_dev_ctx->t2lm_ctx);
1142 	t2lm_timer->timer_started = false;
1143 	t2lm_timer->timer_interval = 0;
1144 	t2lm_dev_lock_release(&vdev->mlo_dev_ctx->t2lm_ctx);
1145 	qdf_timer_free(&t2lm_timer->t2lm_timer);
1146 	t2lm_dev_lock_destroy(&vdev->mlo_dev_ctx->t2lm_ctx);
1147 	return QDF_STATUS_SUCCESS;
1148 }
1149