xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_t2lm.c (revision a341ed26d8bfd26889c9f1b036dab2d7313313d9)
1 /*
2  * Copyright (c) 2022-2024 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_mgr_cmn.h>
26 #include <qdf_util.h>
27 #include <wlan_cm_api.h>
28 #include "wlan_utility.h"
29 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_11BE_MLO_ADV_FEATURE)
30 #include <wlan_t2lm_api.h>
31 #endif
32 #include <wlan_mlo_mgr_sta.h>
33 
34 QDF_STATUS wlan_mlo_parse_t2lm_info(uint8_t *ie,
35 				    struct wlan_t2lm_info *t2lm)
36 {
37 	struct wlan_ie_tid_to_link_mapping *t2lm_ie;
38 	enum wlan_t2lm_direction dir;
39 	uint8_t *t2lm_control_field;
40 	uint16_t t2lm_control;
41 	uint8_t link_mapping_presence_ind = 0;
42 	uint8_t *link_mapping_of_tids;
43 	uint8_t tid_num;
44 	uint8_t *ie_ptr = NULL;
45 
46 	t2lm_ie = (struct wlan_ie_tid_to_link_mapping *)ie;
47 
48 	t2lm_control_field = t2lm_ie->data;
49 	if (!t2lm_control_field) {
50 		t2lm_err("t2lm_control_field is null");
51 		return QDF_STATUS_E_NULL_VALUE;
52 	}
53 
54 	t2lm_control = qdf_le16_to_cpu(*(uint16_t *)t2lm_control_field);
55 
56 	dir = QDF_GET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DIRECTION_IDX,
57 			   WLAN_T2LM_CONTROL_DIRECTION_BITS);
58 	if (dir > WLAN_T2LM_BIDI_DIRECTION) {
59 		t2lm_err("Invalid direction");
60 		return QDF_STATUS_E_NULL_VALUE;
61 	}
62 
63 	t2lm->direction = dir;
64 	t2lm->default_link_mapping =
65 		QDF_GET_BITS(t2lm_control,
66 			     WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_IDX,
67 			     WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_BITS);
68 
69 	t2lm->mapping_switch_time_present =
70 		QDF_GET_BITS(t2lm_control,
71 			     WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_IDX,
72 			     WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_BITS);
73 
74 	t2lm->expected_duration_present =
75 		QDF_GET_BITS(t2lm_control,
76 			     WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_IDX,
77 			     WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_BITS);
78 
79 	t2lm->link_mapping_size =
80 		QDF_GET_BITS(t2lm_control,
81 			     WLAN_T2LM_CONTROL_LINK_MAPPING_SIZE_IDX,
82 			     WLAN_T2LM_CONTROL_LINK_MAPPING_SIZE_BITS);
83 
84 	t2lm_debug("direction:%d default_link_mapping:%d mapping_switch_time_present:%d expected_duration_present:%d link_mapping_size:%d",
85 		   t2lm->direction, t2lm->default_link_mapping,
86 		    t2lm->mapping_switch_time_present,
87 		    t2lm->expected_duration_present,
88 		    t2lm->link_mapping_size);
89 
90 	if (t2lm->default_link_mapping) {
91 		ie_ptr = t2lm_control_field + sizeof(uint8_t);
92 	} else {
93 		link_mapping_presence_ind =
94 			QDF_GET_BITS(t2lm_control,
95 				     WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_IDX,
96 				     WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_BITS);
97 		ie_ptr = t2lm_control_field + sizeof(t2lm_control);
98 	}
99 
100 	if (t2lm->mapping_switch_time_present) {
101 		t2lm->mapping_switch_time =
102 			qdf_le16_to_cpu(*(uint16_t *)ie_ptr);
103 		ie_ptr += sizeof(uint16_t);
104 	}
105 
106 	if (t2lm->expected_duration_present) {
107 		qdf_mem_copy(&t2lm->expected_duration, ie_ptr,
108 			     WLAN_T2LM_EXPECTED_DURATION_SIZE *
109 			     (sizeof(uint8_t)));
110 		ie_ptr += WLAN_T2LM_EXPECTED_DURATION_SIZE * (sizeof(uint8_t));
111 	}
112 
113 	t2lm_debug("mapping_switch_time:%d expected_duration:%d",
114 		   t2lm->mapping_switch_time, t2lm->expected_duration);
115 
116 	if (t2lm->default_link_mapping)
117 		return QDF_STATUS_SUCCESS;
118 
119 	link_mapping_of_tids = ie_ptr;
120 
121 	for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
122 		if (!(link_mapping_presence_ind & BIT(tid_num)))
123 			continue;
124 
125 		if (!t2lm->link_mapping_size) {
126 			t2lm->ieee_link_map_tid[tid_num] =
127 				qdf_le16_to_cpu(*(uint16_t *)link_mapping_of_tids);
128 			link_mapping_of_tids += sizeof(uint16_t);
129 		} else {
130 			t2lm->ieee_link_map_tid[tid_num] =
131 				*(uint8_t *)link_mapping_of_tids;
132 			link_mapping_of_tids += sizeof(uint8_t);
133 		}
134 
135 		t2lm_rl_debug("link mapping of TID%d is %x", tid_num,
136 			      t2lm->ieee_link_map_tid[tid_num]);
137 	}
138 
139 	return QDF_STATUS_SUCCESS;
140 }
141 
142 QDF_STATUS wlan_mlo_parse_bcn_prbresp_t2lm_ie(
143 		struct wlan_t2lm_context *t2lm_ctx, uint8_t *ie,
144 		uint32_t frame_len)
145 {
146 	struct wlan_t2lm_info t2lm = {0};
147 	struct extn_ie_header *ext_ie_hdr;
148 	QDF_STATUS retval;
149 	int i = 0;
150 	uint32_t ie_len_parsed = 0;
151 
152 	qdf_mem_zero(&t2lm_ctx->established_t2lm,
153 		     sizeof(struct wlan_mlo_t2lm_ie));
154 	qdf_mem_zero(&t2lm_ctx->upcoming_t2lm, sizeof(struct wlan_mlo_t2lm_ie));
155 
156 	t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION;
157 	t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION;
158 
159 	for (i = 0; i < WLAN_MAX_T2LM_IE; i++) {
160 		if (!ie || !frame_len) {
161 			t2lm_debug("ie is null or len is 0");
162 			return QDF_STATUS_E_NULL_VALUE;
163 		}
164 
165 		if (frame_len == ie_len_parsed)
166 			return QDF_STATUS_SUCCESS;
167 
168 		if (frame_len < (ie_len_parsed +
169 				 sizeof(struct extn_ie_header))) {
170 			t2lm_debug("Frame length is lesser than parsed T2LM IE header length");
171 			continue;
172 		}
173 
174 		ext_ie_hdr = (struct extn_ie_header *)ie;
175 
176 		if (!(ext_ie_hdr->ie_id == WLAN_ELEMID_EXTN_ELEM &&
177 		      ext_ie_hdr->ie_extn_id == WLAN_EXTN_ELEMID_T2LM))
178 			continue;
179 
180 		ie_len_parsed += ext_ie_hdr->ie_len + sizeof(struct ie_header);
181 		if (frame_len < ie_len_parsed) {
182 			t2lm_debug("Frame length is lesser than parsed T2LM IE length");
183 			continue;
184 		}
185 
186 		t2lm.direction = WLAN_T2LM_INVALID_DIRECTION;
187 		retval = wlan_mlo_parse_t2lm_info(ie, &t2lm);
188 		if (retval) {
189 			t2lm_err("Failed to parse the T2LM IE");
190 			return retval;
191 		}
192 
193 		if (!t2lm.mapping_switch_time_present &&
194 		    t2lm.expected_duration_present) {
195 			qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm, &t2lm,
196 				     sizeof(struct wlan_t2lm_info));
197 		} else if (t2lm.mapping_switch_time_present) {
198 			qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm, &t2lm,
199 				     sizeof(struct wlan_t2lm_info));
200 		}
201 
202 		ie += ext_ie_hdr->ie_len + sizeof(struct ie_header);
203 	}
204 
205 	return QDF_STATUS_SUCCESS;
206 }
207 
208 QDF_STATUS wlan_mlo_parse_t2lm_ie(
209 		struct wlan_t2lm_onging_negotiation_info *t2lm, uint8_t *ie,
210 		uint32_t frame_len)
211 {
212 	struct extn_ie_header *ext_ie_hdr = NULL;
213 	QDF_STATUS retval;
214 	enum wlan_t2lm_direction dir;
215 	struct wlan_t2lm_info t2lm_info;
216 	uint32_t ie_len_parsed = 0;
217 
218 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++)
219 		t2lm->t2lm_info[dir].direction = WLAN_T2LM_INVALID_DIRECTION;
220 
221 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {
222 		if (!ie || !frame_len) {
223 			t2lm_err("ie is null or len is 0");
224 			return QDF_STATUS_E_NULL_VALUE;
225 		}
226 
227 		if (frame_len == ie_len_parsed) {
228 			t2lm_debug("Received T2LM IEs are parsed successfully");
229 			return QDF_STATUS_SUCCESS;
230 		}
231 
232 		if (frame_len < (ie_len_parsed +
233 				 sizeof(struct extn_ie_header))) {
234 			t2lm_err("Frame length %d is lesser than parsed T2LM IE header length %zu",
235 				 frame_len,
236 				 ie_len_parsed + sizeof(struct extn_ie_header));
237 			return QDF_STATUS_E_PROTO;
238 		}
239 
240 		ext_ie_hdr = (struct extn_ie_header *)ie;
241 
242 		if (ext_ie_hdr->ie_id == WLAN_ELEMID_EXTN_ELEM &&
243 		    ext_ie_hdr->ie_extn_id == WLAN_EXTN_ELEMID_T2LM) {
244 			ie_len_parsed += ext_ie_hdr->ie_len + sizeof(struct ie_header);
245 			if (frame_len < ie_len_parsed) {
246 				t2lm_err("Frame length is lesser than parsed T2LM IE length");
247 				return QDF_STATUS_E_PROTO;
248 			}
249 			qdf_mem_zero(&t2lm_info, sizeof(t2lm_info));
250 			retval = wlan_mlo_parse_t2lm_info(ie, &t2lm_info);
251 			if (!retval &&
252 			    t2lm_info.direction < WLAN_T2LM_MAX_DIRECTION) {
253 				qdf_mem_copy(&t2lm->t2lm_info[t2lm_info.direction],
254 					     &t2lm_info,
255 					     sizeof(struct wlan_t2lm_info));
256 			} else {
257 				t2lm_err("Failed to parse the T2LM IE");
258 				return retval;
259 			}
260 			ie += ext_ie_hdr->ie_len + sizeof(struct ie_header);
261 		}
262 	}
263 
264 	if ((t2lm->t2lm_info[WLAN_T2LM_DL_DIRECTION].direction ==
265 			WLAN_T2LM_DL_DIRECTION ||
266 	     t2lm->t2lm_info[WLAN_T2LM_UL_DIRECTION].direction ==
267 			WLAN_T2LM_UL_DIRECTION) &&
268 	    t2lm->t2lm_info[WLAN_T2LM_BIDI_DIRECTION].direction ==
269 			WLAN_T2LM_BIDI_DIRECTION) {
270 		t2lm_err("Both DL/UL and BIDI T2LM IEs should not be present at the same time");
271 
272 		qdf_mem_zero(t2lm, sizeof(*t2lm));
273 		for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {
274 			t2lm->t2lm_info[dir].direction =
275 			    WLAN_T2LM_INVALID_DIRECTION;
276 		}
277 
278 		return QDF_STATUS_E_FAILURE;
279 	}
280 
281 	return QDF_STATUS_SUCCESS;
282 }
283 
284 uint8_t *wlan_mlo_add_t2lm_info_ie(uint8_t *frm, struct wlan_t2lm_info *t2lm,
285 				   struct wlan_objmgr_vdev *vdev)
286 {
287 	struct wlan_ie_tid_to_link_mapping *t2lm_ie;
288 	uint16_t t2lm_control = 0;
289 	uint8_t *t2lm_control_field;
290 	uint8_t *link_mapping_of_tids;
291 	uint8_t tid_num;
292 	uint8_t num_tids = 0;
293 	uint8_t link_mapping_presence_indicator = 0;
294 	struct vdev_mlme_obj *vdev_mlme;
295 	uint8_t *tmp_frm = frm;
296 
297 	t2lm_ie = (struct wlan_ie_tid_to_link_mapping *)frm;
298 	t2lm_ie->elem_id = WLAN_ELEMID_EXTN_ELEM;
299 	t2lm_ie->elem_id_extn = WLAN_EXTN_ELEMID_T2LM;
300 
301 	t2lm_ie->elem_len = sizeof(*t2lm_ie) - sizeof(struct ie_header);
302 
303 	t2lm_control_field = t2lm_ie->data;
304 
305 	QDF_SET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DIRECTION_IDX,
306 		     WLAN_T2LM_CONTROL_DIRECTION_BITS, t2lm->direction);
307 
308 	QDF_SET_BITS(t2lm_control, WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_IDX,
309 		     WLAN_T2LM_CONTROL_DEFAULT_LINK_MAPPING_BITS,
310 		     t2lm->default_link_mapping);
311 
312 	QDF_SET_BITS(t2lm_control,
313 		     WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_IDX,
314 		     WLAN_T2LM_CONTROL_MAPPING_SWITCH_TIME_PRESENT_BITS,
315 		     t2lm->mapping_switch_time_present);
316 
317 	QDF_SET_BITS(t2lm_control,
318 		     WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_IDX,
319 		     WLAN_T2LM_CONTROL_EXPECTED_DURATION_PRESENT_BITS,
320 		     t2lm->expected_duration_present);
321 
322 	QDF_SET_BITS(t2lm_control,
323 		     WLAN_T2LM_CONTROL_LINK_MAPPING_SIZE_IDX,
324 		     WLAN_T2LM_CONTROL_LINK_MAPPING_SIZE_BITS,
325 		     t2lm->link_mapping_size);
326 
327 	if (t2lm->default_link_mapping) {
328 		/* Link mapping of TIDs are not present when default mapping is
329 		 * set. Hence, the size of TID-To-Link mapping control is one
330 		 * octet.
331 		 */
332 		*t2lm_control_field = (uint8_t)t2lm_control;
333 
334 		t2lm_ie->elem_len += sizeof(uint8_t);
335 
336 		t2lm_rl_debug("T2LM IE added, default_link_mapping: %d dir:%d",
337 			      t2lm->default_link_mapping, t2lm->direction);
338 
339 		frm += sizeof(*t2lm_ie) + sizeof(uint8_t);
340 	} else {
341 		for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++)
342 			if (t2lm->hw_link_map_tid[tid_num] ||
343 			    t2lm->ieee_link_map_tid[tid_num])
344 				link_mapping_presence_indicator |= BIT(tid_num);
345 
346 		QDF_SET_BITS(t2lm_control,
347 			     WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_IDX,
348 			     WLAN_T2LM_CONTROL_LINK_MAPPING_PRESENCE_INDICATOR_BITS,
349 			     link_mapping_presence_indicator);
350 		t2lm_rl_debug("T2LM IE added, direction:%d link_mapping_presence_indicator:%x",
351 			      t2lm->direction, link_mapping_presence_indicator);
352 
353 		/* The size of TID-To-Link mapping control is two octets when
354 		 * default link mapping is not set.
355 		 */
356 		*(uint16_t *)t2lm_control_field = htole16(t2lm_control);
357 		frm += sizeof(*t2lm_ie) + sizeof(uint16_t);
358 		t2lm_ie->elem_len += sizeof(uint16_t);
359 	}
360 
361 	if (t2lm->mapping_switch_time_present) {
362 		/* Mapping switch time is different for each vdevs. Hence,
363 		 * populate the mapping switch time from vdev_mlme_obj.
364 		 */
365 		vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
366 		if (!vdev_mlme) {
367 			t2lm_err("null vdev_mlme");
368 			return tmp_frm;
369 		}
370 
371 		*(uint16_t *)frm =
372 			htole16(vdev_mlme->proto.ap.mapping_switch_time);
373 		frm += sizeof(uint16_t);
374 		t2lm_ie->elem_len += sizeof(uint16_t);
375 	}
376 
377 	if (t2lm->expected_duration_present) {
378 		qdf_mem_copy(frm, &t2lm->expected_duration,
379 			     WLAN_T2LM_EXPECTED_DURATION_SIZE *
380 			     sizeof(uint8_t));
381 		frm += WLAN_T2LM_EXPECTED_DURATION_SIZE * sizeof(uint8_t);
382 		t2lm_ie->elem_len +=
383 			WLAN_T2LM_EXPECTED_DURATION_SIZE * sizeof(uint8_t);
384 	}
385 
386 	t2lm_rl_debug("mapping_switch_time:%d expected_duration:%u",
387 		      t2lm->mapping_switch_time, t2lm->expected_duration);
388 
389 	if (t2lm->default_link_mapping)
390 		return frm;
391 
392 	link_mapping_of_tids = frm;
393 
394 	for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
395 		if (!t2lm->ieee_link_map_tid[tid_num])
396 			continue;
397 
398 		if (!t2lm->link_mapping_size) {
399 			*(uint16_t *)link_mapping_of_tids =
400 				htole16(t2lm->ieee_link_map_tid[tid_num]);
401 			t2lm_rl_debug("link mapping of TID%d is %x",
402 				      tid_num,
403 				      htole16(t2lm->ieee_link_map_tid[tid_num]));
404 			link_mapping_of_tids += sizeof(uint16_t);
405 		} else {
406 			*(uint8_t *)link_mapping_of_tids =
407 				t2lm->ieee_link_map_tid[tid_num];
408 			t2lm_rl_debug("link mapping of TID%d is %x",
409 				      tid_num,
410 				      t2lm->ieee_link_map_tid[tid_num]);
411 			link_mapping_of_tids += sizeof(uint8_t);
412 		}
413 		num_tids++;
414 	}
415 
416 	if (!t2lm->link_mapping_size) {
417 		frm += num_tids * sizeof(uint16_t);
418 		t2lm_ie->elem_len += (num_tids * sizeof(uint16_t));
419 	} else {
420 		frm += num_tids * sizeof(uint8_t);
421 		t2lm_ie->elem_len += (num_tids * sizeof(uint8_t));
422 	}
423 
424 	return frm;
425 }
426 
427 uint8_t *wlan_mlo_add_t2lm_ie(uint8_t *frm,
428 			      struct wlan_t2lm_onging_negotiation_info *t2lm,
429 			      struct wlan_objmgr_vdev *vdev)
430 {
431 	uint8_t dir;
432 
433 	if (!frm) {
434 		t2lm_err("frm is null");
435 		return NULL;
436 	}
437 
438 	if (!t2lm) {
439 		t2lm_err("t2lm is null");
440 		return NULL;
441 	}
442 
443 	/* As per spec, the frame should include one or two T2LM IEs. When it is
444 	 * two, then direction should DL and UL.
445 	 */
446 	if ((t2lm->t2lm_info[WLAN_T2LM_DL_DIRECTION].direction ==
447 			WLAN_T2LM_DL_DIRECTION ||
448 	     t2lm->t2lm_info[WLAN_T2LM_UL_DIRECTION].direction ==
449 			WLAN_T2LM_UL_DIRECTION) &&
450 	    t2lm->t2lm_info[WLAN_T2LM_BIDI_DIRECTION].direction ==
451 			WLAN_T2LM_BIDI_DIRECTION) {
452 		t2lm_err("Both DL/UL and BIDI T2LM IEs should not be present at the same time");
453 		return NULL;
454 	}
455 
456 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {
457 		if (t2lm->t2lm_info[dir].direction !=
458 			WLAN_T2LM_INVALID_DIRECTION)
459 			frm = wlan_mlo_add_t2lm_info_ie(frm,
460 							&t2lm->t2lm_info[dir],
461 							vdev);
462 	}
463 
464 	return frm;
465 }
466 
467 /**
468  * wlan_mlo_parse_t2lm_request_action_frame() - API to parse T2LM request action
469  * frame.
470  * @t2lm: Pointer to T2LM structure
471  * @action_frm: Pointer to action frame
472  * @frame_len: Received frame pointer
473  * @category: T2LM action frame category
474  *
475  * Return: QDF_STATUS
476  */
477 static QDF_STATUS wlan_mlo_parse_t2lm_request_action_frame(
478 		struct wlan_t2lm_onging_negotiation_info *t2lm,
479 		struct wlan_action_frame *action_frm,
480 		uint32_t frame_len,
481 		enum wlan_t2lm_category category)
482 {
483 	uint8_t *t2lm_action_frm;
484 	uint32_t ie_len_parsed;
485 
486 	t2lm->category = category;
487 
488 	/*
489 	 * T2LM request action frame
490 	 *
491 	 *   1-byte     1-byte     1-byte   variable
492 	 *-------------------------------------------
493 	 * |         |           |        |         |
494 	 * | Category| Protected | Dialog | T2LM IE |
495 	 * |         |    EHT    | token  |         |
496 	 * |         |  Action   |        |         |
497 	 *-------------------------------------------
498 	 */
499 
500 	ie_len_parsed = sizeof(*action_frm) + sizeof(uint8_t);
501 
502 	if (frame_len < ie_len_parsed) {
503 		t2lm_err("Action frame length %d too short", frame_len);
504 		return QDF_STATUS_E_FAILURE;
505 	}
506 
507 	t2lm_action_frm = (uint8_t *)action_frm + sizeof(*action_frm);
508 
509 	t2lm->dialog_token = *t2lm_action_frm;
510 
511 	return wlan_mlo_parse_t2lm_ie(t2lm,
512 				      t2lm_action_frm + sizeof(uint8_t),
513 				      frame_len - ie_len_parsed);
514 }
515 
516 /**
517  * wlan_mlo_parse_t2lm_response_action_frame() - API to parse T2LM response
518  * action frame.
519  * @t2lm: Pointer to T2LM structure
520  * @action_frm: Pointer to action frame
521  * @frame_len: Action frame length
522  * @category: T2LM action frame category
523  *
524  * Return: QDF_STATUS
525  */
526 static QDF_STATUS wlan_mlo_parse_t2lm_response_action_frame(
527 		struct wlan_t2lm_onging_negotiation_info *t2lm,
528 		struct wlan_action_frame *action_frm,
529 		uint32_t frame_len,
530 		enum wlan_t2lm_category category)
531 {
532 	uint8_t *t2lm_action_frm;
533 	QDF_STATUS ret_val = QDF_STATUS_SUCCESS;
534 	uint32_t ie_len_parsed;
535 
536 	t2lm->category = WLAN_T2LM_CATEGORY_RESPONSE;
537 	/*
538 	 * T2LM response action frame
539 	 *
540 	 *   1-byte     1-byte     1-byte   2-byte   variable
541 	 *----------------------------------------------------
542 	 * |         |           |        |        |         |
543 	 * | Category| Protected | Dialog | Status | T2LM IE |
544 	 * |         |    EHT    | token  |  code  |         |
545 	 * |         |  Action   |        |        |         |
546 	 *----------------------------------------------------
547 	 */
548 
549 	ie_len_parsed = sizeof(*action_frm) + sizeof(uint8_t) +
550 			sizeof(uint16_t);
551 
552 	if (frame_len < ie_len_parsed) {
553 		t2lm_err("Action frame length %d too short", frame_len);
554 		return QDF_STATUS_E_FAILURE;
555 	}
556 
557 	t2lm_action_frm = (uint8_t *)action_frm + sizeof(*action_frm);
558 
559 	t2lm->dialog_token = *t2lm_action_frm;
560 	t2lm->t2lm_resp_type =
561 	      qdf_le16_to_cpu(*(uint16_t *)(t2lm_action_frm + sizeof(uint8_t)));
562 
563 	if (t2lm->t2lm_resp_type ==
564 			WLAN_T2LM_RESP_TYPE_PREFERRED_TID_TO_LINK_MAPPING) {
565 		t2lm_action_frm += sizeof(uint8_t) + sizeof(uint16_t);
566 		ret_val = wlan_mlo_parse_t2lm_ie(t2lm, t2lm_action_frm,
567 						 frame_len - ie_len_parsed);
568 	}
569 
570 	return ret_val;
571 }
572 
573 int wlan_mlo_parse_t2lm_action_frame(
574 		struct wlan_t2lm_onging_negotiation_info *t2lm,
575 		struct wlan_action_frame *action_frm,
576 		uint32_t frame_len,
577 		enum wlan_t2lm_category category)
578 {
579 	QDF_STATUS ret_val = QDF_STATUS_SUCCESS;
580 
581 	switch (category) {
582 	case WLAN_T2LM_CATEGORY_REQUEST:
583 		{
584 			ret_val = wlan_mlo_parse_t2lm_request_action_frame(
585 					t2lm, action_frm, frame_len, category);
586 			return qdf_status_to_os_return(ret_val);
587 		}
588 	case WLAN_T2LM_CATEGORY_RESPONSE:
589 		{
590 			ret_val = wlan_mlo_parse_t2lm_response_action_frame(
591 					t2lm, action_frm, frame_len, category);
592 
593 			return qdf_status_to_os_return(ret_val);
594 		}
595 	case WLAN_T2LM_CATEGORY_TEARDOWN:
596 			/* Nothing to parse from T2LM teardown frame, just reset
597 			 * the mapping to default mapping.
598 			 *
599 			 * T2LM teardown action frame
600 			 *
601 			 *   1-byte     1-byte
602 			 *------------------------
603 			 * |         |           |
604 			 * | Category| Protected |
605 			 * |         |    EHT    |
606 			 * |         |  Action   |
607 			 *------------------------
608 			 */
609 			break;
610 	default:
611 			t2lm_err("Invalid category:%d", category);
612 	}
613 
614 	return ret_val;
615 }
616 
617 static uint8_t *wlan_mlo_add_t2lm_request_action_frame(
618 		uint8_t *frm,
619 		struct wlan_action_frame_args *args, uint8_t *buf,
620 		enum wlan_t2lm_category category)
621 {
622 	*frm++ = args->category;
623 	*frm++ = args->action;
624 	/* Dialog token*/
625 	*frm++ = args->arg1;
626 
627 	t2lm_info("T2LM request frame: category:%d action:%d dialog_token:%d",
628 		  args->category, args->action, args->arg1);
629 	return wlan_mlo_add_t2lm_ie(frm, (void *)buf, NULL);
630 }
631 
632 static uint8_t *wlan_mlo_add_t2lm_response_action_frame(
633 		uint8_t *frm,
634 		struct wlan_action_frame_args *args, uint8_t *buf,
635 		enum wlan_t2lm_category category)
636 {
637 	*frm++ = args->category;
638 	*frm++ = args->action;
639 	/* Dialog token*/
640 	*frm++ = args->arg1;
641 	/* Status code (2 bytes)*/
642 	*(uint16_t *)frm = htole16(args->arg2);
643 	frm += sizeof(uint16_t);
644 
645 	t2lm_info("T2LM response frame: category:%d action:%d dialog_token:%d status_code:%d",
646 		  args->category, args->action, args->arg1, args->arg2);
647 
648 	if (args->arg2 == WLAN_T2LM_RESP_TYPE_PREFERRED_TID_TO_LINK_MAPPING)
649 		frm = wlan_mlo_add_t2lm_ie(frm, (void *)buf, NULL);
650 
651 	return frm;
652 }
653 
654 uint8_t *wlan_mlo_add_t2lm_action_frame(
655 		uint8_t *frm,
656 		struct wlan_action_frame_args *args, uint8_t *buf,
657 		enum wlan_t2lm_category category)
658 {
659 
660 	switch (category) {
661 	case WLAN_T2LM_CATEGORY_REQUEST:
662 		return wlan_mlo_add_t2lm_request_action_frame(frm, args,
663 							      buf, category);
664 	case WLAN_T2LM_CATEGORY_RESPONSE:
665 		return wlan_mlo_add_t2lm_response_action_frame(frm, args,
666 							      buf, category);
667 	case WLAN_T2LM_CATEGORY_TEARDOWN:
668 		*frm++ = args->category;
669 		*frm++ = args->action;
670 		return frm;
671 	default:
672 		t2lm_err("Invalid category:%d", category);
673 	}
674 
675 	return frm;
676 }
677 
678 /**
679  * wlan_mlo_t2lm_handle_mapping_switch_time_expiry() - API to handle the mapping
680  * switch timer expiry.
681  * @t2lm_ctx: Pointer to T2LM context
682  * @vdev: Pointer to vdev structure
683  *
684  * Return: None
685  */
686 static void wlan_mlo_t2lm_handle_mapping_switch_time_expiry(
687 		struct wlan_t2lm_context *t2lm_ctx,
688 		struct wlan_objmgr_vdev *vdev)
689 {
690 	struct wlan_t2lm_info *t2lm;
691 
692 	t2lm_debug("Mapping switch time expired for vdev_id:%d ",
693 		   wlan_vdev_get_id(vdev));
694 
695 	qdf_mem_copy(&t2lm_ctx->established_t2lm, &t2lm_ctx->upcoming_t2lm,
696 		     sizeof(struct wlan_mlo_t2lm_ie));
697 
698 	t2lm_ctx->established_t2lm.t2lm.mapping_switch_time_present = false;
699 	t2lm_ctx->established_t2lm.t2lm.mapping_switch_time = 0;
700 
701 	t2lm = &t2lm_ctx->established_t2lm.t2lm;
702 	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",
703 		   t2lm_ctx->established_t2lm.disabled_link_bitmap,
704 		   t2lm->direction, t2lm->default_link_mapping,
705 		   t2lm->mapping_switch_time_present,
706 		   t2lm->expected_duration_present,
707 		   t2lm->mapping_switch_time, t2lm->expected_duration,
708 		   t2lm->ieee_link_map_tid[0], t2lm->hw_link_map_tid[0]);
709 
710 	qdf_mem_zero(&t2lm_ctx->upcoming_t2lm, sizeof(struct wlan_mlo_t2lm_ie));
711 	t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION;
712 }
713 
714 /**
715  * wlan_mlo_t2lm_handle_expected_duration_expiry() - API to handle the expected
716  * duration timer expiry.
717  * @t2lm_ctx: Pointer to T2LM context
718  * @vdev: Pointer to vdev structure
719  *
720  * Return: none
721  */
722 static void wlan_mlo_t2lm_handle_expected_duration_expiry(
723 		struct wlan_t2lm_context *t2lm_ctx,
724 		struct wlan_objmgr_vdev *vdev)
725 {
726 	t2lm_debug("Expected duration expired for vdev_id:%d ",
727 		   wlan_vdev_get_id(vdev));
728 
729 	if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) {
730 		/* Copy the new non-default ongoing mapping to established
731 		 * mapping if expected duration expires for the established
732 		 * mapping.
733 		 */
734 		wlan_mlo_t2lm_handle_mapping_switch_time_expiry(t2lm_ctx,
735 								vdev);
736 		return;
737 	}
738 
739 	/* Use the default mapping when expected duration expires for the
740 	 * established mapping and no new non-default T2LM announcement is
741 	 * ongoing.
742 	 */
743 	qdf_mem_zero(&t2lm_ctx->established_t2lm,
744 		     sizeof(struct wlan_mlo_t2lm_ie));
745 
746 	t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_BIDI_DIRECTION;
747 	t2lm_ctx->established_t2lm.t2lm.default_link_mapping = 1;
748 	t2lm_ctx->established_t2lm.disabled_link_bitmap = 0;
749 	t2lm_ctx->established_t2lm.t2lm.link_mapping_size = 0;
750 	t2lm_debug("Set established mapping to default mapping");
751 
752 	wlan_clear_peer_level_tid_to_link_mapping(vdev);
753 }
754 
755 QDF_STATUS wlan_mlo_vdev_tid_to_link_map_event(
756 		struct wlan_objmgr_psoc *psoc,
757 		struct mlo_vdev_host_tid_to_link_map_resp *event)
758 {
759 	struct wlan_objmgr_vdev *vdev;
760 	struct wlan_t2lm_context *t2lm_ctx;
761 	struct vdev_mlme_obj *vdev_mlme;
762 
763 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id,
764 						    WLAN_MLO_MGR_ID);
765 	if (!vdev) {
766 		t2lm_err("null vdev");
767 		return QDF_STATUS_E_NULL_VALUE;
768 	}
769 
770 	if (!vdev->mlo_dev_ctx) {
771 		t2lm_err("null mlo_dev_ctx");
772 		return QDF_STATUS_E_NULL_VALUE;
773 	}
774 
775 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
776 	if (!vdev_mlme) {
777 		t2lm_err("null vdev_mlme");
778 		return QDF_STATUS_E_FAILURE;
779 	}
780 
781 	t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
782 
783 	t2lm_debug("psoc_id:%d vdev_id:%d status:%d",
784 		   wlan_psoc_get_id(psoc), event->vdev_id, event->status);
785 
786 	t2lm_dev_lock_acquire(t2lm_ctx);
787 	switch (event->status) {
788 	case WLAN_MAP_SWITCH_TIMER_TSF:
789 
790 		/* Mapping switch time is different for each AP vdev of a given
791 		 * MLD as these vdevs can have separate beacon TDF value.
792 		 */
793 		if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present)
794 			vdev_mlme->proto.ap.mapping_switch_time =
795 				(event->mapping_switch_tsf &
796 				 WLAN_T2LM_MAPPING_SWITCH_TSF_BITS) >> 10;
797 
798 		t2lm_debug("vdev_id:%d updated mapping switch time:%d",
799 			   event->vdev_id,
800 			   vdev_mlme->proto.ap.mapping_switch_time);
801 		break;
802 	case WLAN_MAP_SWITCH_TIMER_EXPIRED:
803 		vdev_mlme->proto.ap.mapping_switch_time = 0;
804 		wlan_mlo_t2lm_handle_mapping_switch_time_expiry(t2lm_ctx, vdev);
805 
806 		/* Notify the registered caller about the link update*/
807 		wlan_mlo_dev_t2lm_notify_link_update(vdev,
808 					&t2lm_ctx->established_t2lm.t2lm);
809 		break;
810 	case WLAN_EXPECTED_DUR_EXPIRED:
811 		wlan_mlo_t2lm_handle_expected_duration_expiry(t2lm_ctx, vdev);
812 
813 		/* Notify the registered caller about the link update*/
814 		wlan_mlo_dev_t2lm_notify_link_update(vdev,
815 					&t2lm_ctx->established_t2lm.t2lm);
816 		break;
817 	default:
818 		t2lm_err("Invalid status");
819 	}
820 
821 	t2lm_dev_lock_release(t2lm_ctx);
822 	mlo_release_vdev_ref(vdev);
823 
824 	return QDF_STATUS_SUCCESS;
825 }
826 
827 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
828 static
829 QDF_STATUS wlan_send_t2lm_info(struct wlan_objmgr_vdev *vdev,
830 			       struct wlan_t2lm_info *t2lm,
831 			       struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops)
832 {
833 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
834 
835 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
836 		t2lm_err("vdev is not MLO vdev");
837 		return status;
838 	}
839 
840 	status = mlo_tx_ops->send_tid_to_link_mapping(vdev, t2lm);
841 	if (QDF_IS_STATUS_ERROR(status))
842 		t2lm_err("Failed to send T2LM command to FW");
843 
844 	return status;
845 }
846 #else
847 static
848 QDF_STATUS wlan_send_t2lm_info(struct wlan_objmgr_vdev *vdev,
849 			       struct wlan_t2lm_info *t2lm,
850 			       struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops)
851 {
852 	struct wlan_objmgr_vdev *co_mld_vdev;
853 	struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
854 	uint16_t vdev_count = 0;
855 	int i = 0;
856 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
857 
858 	mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list);
859 	if (!vdev_count) {
860 		t2lm_err("Number of VDEVs under MLD is reported as 0");
861 		return QDF_STATUS_E_NULL_VALUE;
862 	}
863 
864 	for (i = 0; i < vdev_count; i++) {
865 		co_mld_vdev = wlan_vdev_list[i];
866 		if (!co_mld_vdev) {
867 			t2lm_err("co_mld_vdev is null");
868 			mlo_release_vdev_ref(co_mld_vdev);
869 			continue;
870 		}
871 
872 		if (mlo_is_sta_bridge_vdev(co_mld_vdev)) {
873 			t2lm_debug("skip co_mld_vdev for bridge sta");
874 			mlo_release_vdev_ref(co_mld_vdev);
875 			continue;
876 		}
877 
878 		status = mlo_tx_ops->send_tid_to_link_mapping(co_mld_vdev,
879 							      t2lm);
880 		if (QDF_IS_STATUS_ERROR(status))
881 			t2lm_err("Failed to send T2LM command to FW");
882 		mlo_release_vdev_ref(co_mld_vdev);
883 	}
884 
885 	return status;
886 }
887 #endif
888 
889 QDF_STATUS wlan_send_tid_to_link_mapping(struct wlan_objmgr_vdev *vdev,
890 					 struct wlan_t2lm_info *t2lm)
891 {
892 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
893 	struct wlan_objmgr_psoc *psoc;
894 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
895 
896 	psoc = wlan_vdev_get_psoc(vdev);
897 	if (!psoc) {
898 		t2lm_err("null psoc");
899 		return QDF_STATUS_E_NULL_VALUE;
900 	}
901 
902 	mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops;
903 	if (!mlo_tx_ops) {
904 		t2lm_err("tx_ops is null!");
905 		return QDF_STATUS_E_NULL_VALUE;
906 	}
907 
908 	if (!mlo_tx_ops->send_tid_to_link_mapping) {
909 		t2lm_err("send_tid_to_link_mapping is null");
910 		return QDF_STATUS_E_NULL_VALUE;
911 	}
912 
913 	status = wlan_send_t2lm_info(vdev, t2lm, mlo_tx_ops);
914 
915 	return status;
916 }
917 
918 /**
919  * wlan_get_vdev_t2lm_mapping_status() - API to get vdev level T2LM info
920  * @vdev: vdev object
921  * @t2lm: T2LM info
922  *
923  * Return: QDF_STATUS
924  */
925 static
926 QDF_STATUS wlan_get_vdev_t2lm_mapping_status(struct wlan_objmgr_vdev *vdev,
927 					     struct wlan_t2lm_info *t2lm)
928 {
929 	struct wlan_t2lm_context *t2lm_ctx;
930 	int i = 0;
931 
932 	t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
933 
934 	t2lm_dev_lock_acquire(t2lm_ctx);
935 	qdf_mem_copy(&t2lm[i++], &t2lm_ctx->established_t2lm.t2lm,
936 		     sizeof(struct wlan_t2lm_info));
937 	t2lm_dev_lock_release(t2lm_ctx);
938 
939 	return QDF_STATUS_SUCCESS;
940 }
941 
942 /**
943  * wlan_get_peer_t2lm_mapping_status() - API to get peer level T2LM info
944  * @peer: peer object
945  * @t2lm: T2LM info
946  *
947  * Return: QDF_STATUS
948  */
949 static
950 QDF_STATUS wlan_get_peer_t2lm_mapping_status(struct wlan_objmgr_peer *peer,
951 					     struct wlan_t2lm_info *t2lm)
952 {
953 	enum wlan_t2lm_direction dir = WLAN_T2LM_INVALID_DIRECTION;
954 	struct wlan_mlo_peer_context *ml_peer;
955 	struct wlan_prev_t2lm_negotiated_info *t2lm_req;
956 	int i = 0;
957 
958 	ml_peer = peer->mlo_peer_ctx;
959 	if (!ml_peer)
960 		return QDF_STATUS_E_FAILURE;
961 
962 	t2lm_req = &ml_peer->t2lm_policy.t2lm_negotiated_info;
963 	if ((t2lm_req->t2lm_info[WLAN_T2LM_DL_DIRECTION].direction ==
964 			WLAN_T2LM_DL_DIRECTION ||
965 	     t2lm_req->t2lm_info[WLAN_T2LM_UL_DIRECTION].direction ==
966 			WLAN_T2LM_UL_DIRECTION) &&
967 	     t2lm_req->t2lm_info[WLAN_T2LM_BIDI_DIRECTION].direction ==
968 			WLAN_T2LM_BIDI_DIRECTION) {
969 		t2lm_err("Both DL/UL and BIDI T2LM IEs should not be present at the same time");
970 		return QDF_STATUS_E_FAILURE;
971 	}
972 
973 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {
974 		if (t2lm_req->t2lm_info[dir].direction !=
975 			WLAN_T2LM_INVALID_DIRECTION)
976 			qdf_mem_copy(&t2lm[i++], &t2lm_req->t2lm_info[dir],
977 				     sizeof(struct wlan_t2lm_info));
978 	}
979 
980 	if (i == 0)
981 		return QDF_STATUS_E_EMPTY;
982 
983 	return QDF_STATUS_SUCCESS;
984 }
985 
986 QDF_STATUS wlan_get_t2lm_mapping_status(struct wlan_objmgr_vdev *vdev,
987 					struct wlan_t2lm_info *t2lm)
988 {
989 	struct wlan_objmgr_peer *peer;
990 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
991 
992 	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLO_MGR_ID);
993 	if (!peer) {
994 		t2lm_err("peer not found");
995 		return QDF_STATUS_E_NULL_VALUE;
996 	}
997 
998 	status = wlan_get_peer_t2lm_mapping_status(peer, t2lm);
999 	if (QDF_IS_STATUS_SUCCESS(status)) {
1000 		t2lm_debug("peer level T2LM info");
1001 		goto peer_release;
1002 	}
1003 
1004 	t2lm_debug("vdev level T2LM info");
1005 	status = wlan_get_vdev_t2lm_mapping_status(vdev, t2lm);
1006 
1007 peer_release:
1008 	wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
1009 
1010 	return status;
1011 }
1012 
1013 QDF_STATUS
1014 wlan_send_peer_level_tid_to_link_mapping(struct wlan_objmgr_vdev *vdev,
1015 					 struct wlan_objmgr_peer *peer)
1016 {
1017 	uint8_t dir, idx = 0;
1018 	struct wlan_mlo_peer_context *ml_peer;
1019 	struct wlan_t2lm_info *t2lm_info;
1020 	QDF_STATUS status = QDF_STATUS_E_NULL_VALUE;
1021 
1022 	if (!peer) {
1023 		t2lm_err("peer is null");
1024 		return status;
1025 	}
1026 
1027 	ml_peer = peer->mlo_peer_ctx;
1028 	if (!ml_peer) {
1029 		t2lm_err("ml peer is null");
1030 		return status;
1031 	}
1032 
1033 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {
1034 		t2lm_info = &ml_peer->t2lm_policy.t2lm_negotiated_info.t2lm_info[dir];
1035 		if (t2lm_info && t2lm_info->direction !=
1036 		    WLAN_T2LM_INVALID_DIRECTION) {
1037 			t2lm_debug("send peer-level mapping to FW for dir: %d", dir);
1038 
1039 			/* Notify the registered caller about the link update*/
1040 			wlan_mlo_dev_t2lm_notify_link_update(vdev, t2lm_info);
1041 			status = wlan_send_tid_to_link_mapping(vdev, t2lm_info);
1042 			idx++;
1043 		}
1044 	}
1045 
1046 	if (!idx)
1047 		t2lm_debug("No peer-level mapping present");
1048 
1049 	return status;
1050 }
1051 
1052 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_11BE_MLO_ADV_FEATURE)
1053 void
1054 wlan_clear_peer_level_tid_to_link_mapping(struct wlan_objmgr_vdev *vdev)
1055 {
1056 	struct wlan_objmgr_peer *peer;
1057 
1058 	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLO_MGR_ID);
1059 	if (!peer) {
1060 		t2lm_err("Peer not found");
1061 		return;
1062 	}
1063 
1064 	wlan_t2lm_clear_peer_negotiation(peer);
1065 
1066 	wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
1067 }
1068 #endif
1069 
1070 void wlan_mlo_t2lm_timer_expiry_handler(void *vdev)
1071 {
1072 	struct wlan_objmgr_vdev *vdev_ctx = (struct wlan_objmgr_vdev *)vdev;
1073 
1074 	struct wlan_t2lm_timer *t2lm_timer;
1075 	struct wlan_t2lm_context *t2lm_ctx;
1076 
1077 	if (!vdev_ctx || !vdev_ctx->mlo_dev_ctx)
1078 		return;
1079 
1080 	t2lm_ctx = &vdev_ctx->mlo_dev_ctx->t2lm_ctx;
1081 	t2lm_timer = &vdev_ctx->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
1082 
1083 	wlan_mlo_t2lm_timer_stop(vdev_ctx);
1084 
1085 	/* Since qdf_mutex_acquire cannot be called from interrupt context,
1086 	 * change needed to create a workqueue and offload the timer expiry
1087 	 * handling to workqueue.
1088 	 */
1089 	if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present) {
1090 		wlan_mlo_t2lm_handle_expected_duration_expiry(t2lm_ctx, vdev);
1091 
1092 		/* Notify the registered caller about the link update*/
1093 		wlan_mlo_dev_t2lm_notify_link_update(vdev_ctx,
1094 					&t2lm_ctx->established_t2lm.t2lm);
1095 		wlan_send_tid_to_link_mapping(
1096 				vdev, &t2lm_ctx->established_t2lm.t2lm);
1097 
1098 		wlan_handle_t2lm_timer(vdev_ctx);
1099 	} else if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) {
1100 		wlan_mlo_t2lm_handle_mapping_switch_time_expiry(t2lm_ctx, vdev);
1101 
1102 		/* Notify the registered caller about the link update*/
1103 		wlan_mlo_dev_t2lm_notify_link_update(vdev_ctx,
1104 					&t2lm_ctx->established_t2lm.t2lm);
1105 		wlan_send_tid_to_link_mapping(
1106 				vdev, &t2lm_ctx->established_t2lm.t2lm);
1107 		wlan_handle_t2lm_timer(vdev_ctx);
1108 	}
1109 
1110 }
1111 
1112 #ifndef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
1113 /**
1114  * wlan_mlo_t2lm_update_peer_to_peer_negotiation() - API to update peer-to-peer
1115  * level T2LM negotiation data structure on mapping switch time expiry and
1116  * expected duration expiry.
1117  * @ml_dev: Pointer to ML dev structure
1118  * @ml_peer: Pointer to ML peer
1119  * @arg: Pointer to advertised T2LM structure
1120  *
1121  * Return: QDF_STATUS
1122  */
1123 static QDF_STATUS wlan_mlo_t2lm_update_peer_to_peer_negotiation(
1124 		struct wlan_mlo_dev_context *ml_dev,
1125 		void *ml_peer, void *arg)
1126 {
1127 	struct wlan_mlo_peer_context *mlo_peer;
1128 	struct wlan_t2lm_info *t2lm;
1129 	struct wlan_prev_t2lm_negotiated_info *negotiated_t2lm = NULL;
1130 	uint8_t dir = 0;
1131 
1132 	mlo_peer = (struct wlan_mlo_peer_context *)ml_peer;
1133 	if (!mlo_peer) {
1134 		t2lm_err("null mlo_peer");
1135 		return QDF_STATUS_E_NULL_VALUE;
1136 	}
1137 
1138 	t2lm = (struct wlan_t2lm_info *)arg;
1139 	if (!t2lm) {
1140 		t2lm_err("null T2LM");
1141 		return QDF_STATUS_E_NULL_VALUE;
1142 	}
1143 
1144 	negotiated_t2lm = &mlo_peer->t2lm_policy.t2lm_negotiated_info;
1145 	negotiated_t2lm->dialog_token = 0;
1146 
1147 	/* Reset the peer-to-peer level mapping to default mapping */
1148 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {
1149 		negotiated_t2lm->t2lm_info[dir].direction =
1150 			WLAN_T2LM_INVALID_DIRECTION;
1151 	}
1152 
1153 	/* Copy the Advertised T2LM established mapping to peer-to-peer level
1154 	 * DIBI direction data structure.
1155 	 */
1156 	qdf_mem_copy(&negotiated_t2lm->t2lm_info[WLAN_T2LM_BIDI_DIRECTION],
1157 		     t2lm, sizeof(struct wlan_t2lm_info));
1158 
1159 	return QDF_STATUS_SUCCESS;
1160 }
1161 
1162 /**
1163  * wlan_mlo_t2lm_link_update_notifier_callback() - This callback API is invoked
1164  * when mapping switch timer expires and expected duration expires.
1165  * @vdev: Pointer to vdev structure
1166  * @t2lm: Pointer to advertised T2LM structure
1167  *
1168  * Return: QDF_STATUS
1169  */
1170 static QDF_STATUS wlan_mlo_t2lm_link_update_notifier_callback(
1171 		struct wlan_objmgr_vdev *vdev,
1172 		struct wlan_t2lm_info *t2lm)
1173 {
1174 	/* Go over all MLO peers on this MLD and clear the peer-to-peer level
1175 	 * mapping.
1176 	 */
1177 	wlan_mlo_iterate_ml_peerlist(
1178 			vdev->mlo_dev_ctx,
1179 			wlan_mlo_t2lm_update_peer_to_peer_negotiation, t2lm);
1180 
1181 	return QDF_STATUS_SUCCESS;
1182 }
1183 
1184 QDF_STATUS wlan_mlo_t2lm_register_link_update_notify_handler(
1185 		struct wlan_mlo_dev_context *ml_dev)
1186 {
1187 	ml_dev->t2lm_ctx.link_update_callback_index =
1188 		wlan_register_t2lm_link_update_notify_handler(
1189 				wlan_mlo_t2lm_link_update_notifier_callback,
1190 				ml_dev);
1191 
1192 	return QDF_STATUS_SUCCESS;
1193 }
1194 #endif
1195 
1196 QDF_STATUS
1197 wlan_mlo_t2lm_timer_init(struct wlan_objmgr_vdev *vdev)
1198 {
1199 	struct wlan_t2lm_timer *t2lm_timer = NULL;
1200 
1201 	if (!vdev || !vdev->mlo_dev_ctx)
1202 		return QDF_STATUS_E_FAILURE;
1203 
1204 	t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
1205 	if (!t2lm_timer) {
1206 		t2lm_err("t2lm timer ctx is null");
1207 		return QDF_STATUS_E_NULL_VALUE;
1208 	}
1209 
1210 	t2lm_dev_lock_create(&vdev->mlo_dev_ctx->t2lm_ctx);
1211 	t2lm_dev_lock_acquire(&vdev->mlo_dev_ctx->t2lm_ctx);
1212 	qdf_timer_init(NULL, &t2lm_timer->t2lm_timer,
1213 		       wlan_mlo_t2lm_timer_expiry_handler,
1214 		       vdev, QDF_TIMER_TYPE_WAKE_APPS);
1215 
1216 	t2lm_timer->timer_started = false;
1217 	t2lm_timer->timer_interval = 0;
1218 	t2lm_timer->timer_out_time = 0;
1219 	t2lm_dev_lock_release(&vdev->mlo_dev_ctx->t2lm_ctx);
1220 	return QDF_STATUS_SUCCESS;
1221 }
1222 
1223 QDF_STATUS
1224 wlan_mlo_t2lm_timer_start(struct wlan_objmgr_vdev *vdev,
1225 			  uint32_t interval)
1226 {
1227 	struct wlan_t2lm_timer *t2lm_timer;
1228 	struct wlan_t2lm_context *t2lm_ctx;
1229 	uint32_t target_out_time;
1230 	struct wlan_mlo_dev_context *mlo_dev_ctx;
1231 
1232 	if (!interval) {
1233 		t2lm_debug("Timer interval is 0");
1234 		return QDF_STATUS_E_NULL_VALUE;
1235 	}
1236 
1237 	if (!vdev)
1238 		return QDF_STATUS_E_NULL_VALUE;
1239 
1240 	mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev);
1241 	if (!mlo_dev_ctx)
1242 		return QDF_STATUS_E_NULL_VALUE;
1243 
1244 	t2lm_ctx = &mlo_dev_ctx->t2lm_ctx;
1245 	t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
1246 	if (!t2lm_timer) {
1247 		t2lm_err("t2lm timer ctx is null");
1248 		return QDF_STATUS_E_NULL_VALUE;
1249 	}
1250 
1251 	interval = (interval * 1024) / 1000;
1252 	target_out_time = qdf_system_ticks_to_msecs(qdf_system_ticks());
1253 	target_out_time += interval;
1254 	t2lm_debug("earlier timer @%u ms out, new @%u ms out",
1255 		   t2lm_timer->timer_out_time, target_out_time);
1256 
1257 	/* sometimes the host process the beacon maybe delay, it may help for
1258 	 * update the new expected time.
1259 	 */
1260 	if (t2lm_timer->timer_out_time &&
1261 	    (target_out_time > t2lm_timer->timer_out_time ||
1262 	     (t2lm_timer->timer_out_time - target_out_time) <
1263 	      WLAN_T2LM_MAPPING_SWITCH_TIME_DELAY))
1264 		return QDF_STATUS_E_NULL_VALUE;
1265 
1266 	if (t2lm_timer->timer_started)
1267 		qdf_timer_stop(&t2lm_timer->t2lm_timer);
1268 
1269 	t2lm_debug("t2lm timer started with interval %d ms", interval);
1270 	t2lm_timer->timer_interval = interval;
1271 	t2lm_timer->timer_started = true;
1272 	t2lm_timer->timer_out_time = target_out_time;
1273 	qdf_timer_start(&t2lm_timer->t2lm_timer, t2lm_timer->timer_interval);
1274 
1275 	return QDF_STATUS_SUCCESS;
1276 }
1277 
1278 QDF_STATUS
1279 wlan_mlo_t2lm_timer_stop(struct wlan_objmgr_vdev *vdev)
1280 {
1281 	struct wlan_t2lm_timer *t2lm_timer;
1282 
1283 	if (!vdev || !vdev->mlo_dev_ctx)
1284 		return QDF_STATUS_E_NULL_VALUE;
1285 
1286 	t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
1287 	if (!t2lm_timer) {
1288 		t2lm_err("t2lm timer ctx is null");
1289 		return QDF_STATUS_E_NULL_VALUE;
1290 	}
1291 
1292 	if (t2lm_timer->timer_started) {
1293 		qdf_timer_stop(&t2lm_timer->t2lm_timer);
1294 		t2lm_timer->timer_started = false;
1295 		t2lm_timer->timer_interval = 0;
1296 		t2lm_timer->timer_out_time = 0;
1297 	}
1298 	return QDF_STATUS_SUCCESS;
1299 }
1300 
1301 QDF_STATUS wlan_handle_t2lm_timer(struct wlan_objmgr_vdev *vdev)
1302 {
1303 	struct wlan_t2lm_context *t2lm_ctx;
1304 	struct vdev_mlme_obj *vdev_mlme;
1305 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1306 
1307 	if (!vdev || !vdev->mlo_dev_ctx)
1308 		return QDF_STATUS_E_NULL_VALUE;
1309 
1310 	t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
1311 
1312 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
1313 	if (!vdev_mlme)
1314 		return QDF_STATUS_E_FAILURE;
1315 
1316 	if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present) {
1317 		if (t2lm_ctx->established_t2lm.t2lm.expected_duration ==
1318 		    T2LM_EXPECTED_DURATION_MAX_VALUE) {
1319 			return status;
1320 		}
1321 
1322 		status = wlan_mlo_t2lm_timer_start(
1323 				vdev,
1324 				t2lm_ctx->established_t2lm.t2lm.expected_duration);
1325 	} else if (t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) {
1326 		status = wlan_mlo_t2lm_timer_start(
1327 				vdev,
1328 				t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time);
1329 	}
1330 
1331 	return status;
1332 }
1333 
1334 /**
1335  * wlan_update_mapping_switch_time_expected_dur() - API to update the mapping
1336  * switch time and expected duration.
1337  * @vdev:Pointer to vdev
1338  * @rx_t2lm: Pointer to received T2LM IE
1339  * @tsf: TSF value of beacon/probe response
1340  *
1341  * Return: None
1342  */
1343 static QDF_STATUS wlan_update_mapping_switch_time_expected_dur(
1344 		struct wlan_objmgr_vdev *vdev,
1345 		struct wlan_t2lm_context *rx_t2lm, uint64_t tsf)
1346 {
1347 	struct wlan_t2lm_context *t2lm_ctx;
1348 	uint16_t tsf_bit25_10, ms_time;
1349 	struct wlan_mlo_dev_context *mlo_dev_ctx;
1350 
1351 	if (!vdev)
1352 		return QDF_STATUS_E_NULL_VALUE;
1353 
1354 	mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev);
1355 	if (!mlo_dev_ctx)
1356 		return QDF_STATUS_E_NULL_VALUE;
1357 
1358 	tsf_bit25_10 = (tsf & WLAN_T2LM_MAPPING_SWITCH_TSF_BITS) >> 10;
1359 	t2lm_ctx = &mlo_dev_ctx->t2lm_ctx;
1360 
1361 	t2lm_dev_lock_acquire(t2lm_ctx);
1362 
1363 	if ((t2lm_ctx->established_t2lm.t2lm.expected_duration_present &&
1364 	    rx_t2lm->established_t2lm.t2lm.expected_duration_present) &&
1365 	    (rx_t2lm->established_t2lm.t2lm.expected_duration <
1366 	     t2lm_ctx->established_t2lm.t2lm.expected_duration)) {
1367 		/* Established T2LM is already saved in the T2LM context.
1368 		 * T2LM IE in the beacon/probe response frame has the updated
1369 		 * expected duration.
1370 		 */
1371 		if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid,
1372 				 rx_t2lm->established_t2lm.t2lm.ieee_link_map_tid,
1373 				 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) {
1374 			t2lm_ctx->established_t2lm.t2lm.expected_duration =
1375 				rx_t2lm->established_t2lm.t2lm.expected_duration;
1376 		}
1377 	} else if (rx_t2lm->established_t2lm.t2lm.expected_duration_present &&
1378 		   !rx_t2lm->established_t2lm.t2lm.mapping_switch_time_present) {
1379 		if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid,
1380 				 rx_t2lm->established_t2lm.t2lm.ieee_link_map_tid,
1381 				 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) {
1382 			t2lm_debug("T2LM mapping is already configured");
1383 			t2lm_dev_lock_release(t2lm_ctx);
1384 			return QDF_STATUS_E_ALREADY;
1385 		}
1386 
1387 		/* Mapping switch time is already expired when STA receives the
1388 		 * T2LM IE from beacon/probe response frame.
1389 		 */
1390 		qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm,
1391 			     &rx_t2lm->established_t2lm.t2lm,
1392 			     sizeof(struct wlan_t2lm_info));
1393 
1394 		/* Notify the registered caller about the link update*/
1395 		wlan_mlo_dev_t2lm_notify_link_update(vdev,
1396 					&t2lm_ctx->established_t2lm.t2lm);
1397 		wlan_clear_peer_level_tid_to_link_mapping(vdev);
1398 		wlan_send_tid_to_link_mapping(
1399 				vdev, &t2lm_ctx->established_t2lm.t2lm);
1400 	}
1401 
1402 	if (rx_t2lm->upcoming_t2lm.t2lm.mapping_switch_time_present) {
1403 		if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid,
1404 				 rx_t2lm->upcoming_t2lm.t2lm.ieee_link_map_tid,
1405 				 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) {
1406 			t2lm_debug("Ongoing mapping is already established");
1407 			t2lm_dev_lock_release(t2lm_ctx);
1408 			return QDF_STATUS_E_ALREADY;
1409 		}
1410 
1411 		qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm,
1412 			     &rx_t2lm->upcoming_t2lm.t2lm,
1413 			     sizeof(struct wlan_t2lm_info));
1414 
1415 		ms_time = t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time;
1416 		/* Per test, -300ms is fine */
1417 		if (ms_time > tsf_bit25_10) {
1418 			t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time =
1419 				(ms_time - tsf_bit25_10 - (3 * WLAN_T2LM_MAPPING_SWITCH_TIME_DELAY));
1420 		} else {
1421 			t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time =
1422 				0xFFFF - (tsf_bit25_10 - ms_time) - (3 * WLAN_T2LM_MAPPING_SWITCH_TIME_DELAY);
1423 		}
1424 	}
1425 
1426 	t2lm_dev_lock_release(t2lm_ctx);
1427 
1428 	return QDF_STATUS_SUCCESS;
1429 }
1430 
1431 QDF_STATUS wlan_process_bcn_prbrsp_t2lm_ie(
1432 		struct wlan_objmgr_vdev *vdev,
1433 		struct wlan_t2lm_context *rx_t2lm_ie, uint64_t tsf)
1434 {
1435 	struct wlan_t2lm_context *t2lm_ctx;
1436 	QDF_STATUS status;
1437 	struct wlan_mlo_dev_context *mlo_dev_ctx;
1438 
1439 	/* Do not parse the T2LM IE if STA is not in connected state */
1440 	if (!wlan_cm_is_vdev_connected(vdev))
1441 		return QDF_STATUS_SUCCESS;
1442 
1443 	if (!vdev)
1444 		return QDF_STATUS_E_NULL_VALUE;
1445 
1446 	mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev);
1447 	if (!mlo_dev_ctx)
1448 		return QDF_STATUS_E_NULL_VALUE;
1449 
1450 	t2lm_ctx = &mlo_dev_ctx->t2lm_ctx;
1451 
1452 	status = wlan_update_mapping_switch_time_expected_dur(
1453 			vdev, rx_t2lm_ie, tsf);
1454 	if (QDF_IS_STATUS_ERROR(status))
1455 		return status;
1456 
1457 	t2lm_dev_lock_acquire(t2lm_ctx);
1458 	if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present ||
1459 	    t2lm_ctx->upcoming_t2lm.t2lm.mapping_switch_time_present) {
1460 		wlan_handle_t2lm_timer(vdev);
1461 	}
1462 	t2lm_dev_lock_release(t2lm_ctx);
1463 
1464 	return QDF_STATUS_SUCCESS;
1465 }
1466 
1467 int wlan_register_t2lm_link_update_notify_handler(
1468 		wlan_mlo_t2lm_link_update_handler handler,
1469 		struct wlan_mlo_dev_context *mldev)
1470 {
1471 	struct wlan_t2lm_context *t2lm_ctx = &mldev->t2lm_ctx;
1472 	int i;
1473 
1474 	for (i = 0; i < MAX_T2LM_HANDLERS; i++) {
1475 		if (t2lm_ctx->is_valid_handler[i])
1476 			continue;
1477 
1478 		t2lm_ctx->link_update_handler[i] = handler;
1479 		t2lm_ctx->is_valid_handler[i] = true;
1480 		break;
1481 	}
1482 
1483 	if (i == MAX_T2LM_HANDLERS) {
1484 		t2lm_err("Failed to register the link disablement callback");
1485 		return -EINVAL;
1486 	}
1487 
1488 	return i;
1489 }
1490 
1491 void wlan_unregister_t2lm_link_update_notify_handler(
1492 		struct wlan_mlo_dev_context *mldev,
1493 		uint8_t index)
1494 {
1495 	if (index >= MAX_T2LM_HANDLERS)
1496 		return;
1497 
1498 	mldev->t2lm_ctx.link_update_handler[index] = NULL;
1499 	mldev->t2lm_ctx.is_valid_handler[index] = false;
1500 }
1501 
1502 QDF_STATUS wlan_mlo_dev_t2lm_notify_link_update(
1503 		struct wlan_objmgr_vdev *vdev,
1504 		struct wlan_t2lm_info *t2lm)
1505 {
1506 	struct wlan_t2lm_context *t2lm_ctx;
1507 	wlan_mlo_t2lm_link_update_handler handler;
1508 	int i;
1509 
1510 	if (!vdev || !vdev->mlo_dev_ctx)
1511 		return QDF_STATUS_E_FAILURE;
1512 
1513 	if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE &&
1514 	    !wlan_cm_is_vdev_connected(vdev)) {
1515 		t2lm_err("Not associated!");
1516 		return QDF_STATUS_E_AGAIN;
1517 	}
1518 
1519 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
1520 		t2lm_err("failed due to non-ML connection");
1521 		return QDF_STATUS_E_INVAL;
1522 	}
1523 
1524 	t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
1525 	for (i = 0; i < MAX_T2LM_HANDLERS; i++) {
1526 		if (!t2lm_ctx->is_valid_handler[i])
1527 			continue;
1528 
1529 		handler = t2lm_ctx->link_update_handler[i];
1530 		if (!handler)
1531 			continue;
1532 
1533 		handler(vdev, t2lm);
1534 	}
1535 	return QDF_STATUS_SUCCESS;
1536 }
1537 
1538 QDF_STATUS
1539 wlan_mlo_t2lm_timer_deinit(struct wlan_objmgr_vdev *vdev)
1540 {
1541 	struct wlan_t2lm_timer *t2lm_timer = NULL;
1542 
1543 	if (!vdev || !vdev->mlo_dev_ctx)
1544 		return QDF_STATUS_E_FAILURE;
1545 
1546 	t2lm_timer = &vdev->mlo_dev_ctx->t2lm_ctx.t2lm_timer;
1547 	if (!t2lm_timer) {
1548 		t2lm_err("t2lm timer ctx is null");
1549 		return QDF_STATUS_E_NULL_VALUE;
1550 	}
1551 
1552 	t2lm_dev_lock_acquire(&vdev->mlo_dev_ctx->t2lm_ctx);
1553 	t2lm_timer->timer_started = false;
1554 	t2lm_timer->timer_interval = 0;
1555 	t2lm_dev_lock_release(&vdev->mlo_dev_ctx->t2lm_ctx);
1556 	qdf_timer_free(&t2lm_timer->t2lm_timer);
1557 	t2lm_dev_lock_destroy(&vdev->mlo_dev_ctx->t2lm_ctx);
1558 	return QDF_STATUS_SUCCESS;
1559 }
1560 
1561 #if defined(WLAN_FEATURE_11BE_MLO_ADV_FEATURE) && defined(WLAN_FEATURE_11BE)
1562 QDF_STATUS
1563 wlan_mlo_link_disable_request_handler(struct wlan_objmgr_psoc *psoc,
1564 				      void *evt_params)
1565 {
1566 	struct wlan_objmgr_vdev *vdev;
1567 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1568 	uint8_t vdev_id;
1569 	bool is_connected = false;
1570 	struct mlo_link_disable_request_evt_params *params;
1571 
1572 	if (!psoc)
1573 		return QDF_STATUS_E_NULL_VALUE;
1574 
1575 	if (!evt_params) {
1576 		t2lm_err("event params is null");
1577 		return QDF_STATUS_E_NULL_VALUE;
1578 	}
1579 
1580 	params = (struct mlo_link_disable_request_evt_params *)evt_params;
1581 	if (qdf_is_macaddr_zero(&params->mld_addr)) {
1582 		t2lm_err("mld mac addr in event params is null");
1583 		return QDF_STATUS_E_NULL_VALUE;
1584 	}
1585 
1586 	if (!params->link_id_bitmap) {
1587 		t2lm_debug("Link id bitmap is 0, no action frame to be sent");
1588 		return QDF_STATUS_SUCCESS;
1589 	}
1590 
1591 	is_connected = wlan_get_connected_vdev_by_mld_addr(psoc,
1592 							   params->mld_addr.bytes,
1593 							   &vdev_id);
1594 	if (!is_connected) {
1595 		t2lm_err("Not connected to peer MLD " QDF_MAC_ADDR_FMT,
1596 			 QDF_MAC_ADDR_REF(params->mld_addr.bytes));
1597 		return QDF_STATUS_E_FAILURE;
1598 	}
1599 
1600 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
1601 						    WLAN_MLO_MGR_ID);
1602 	if (!vdev) {
1603 		t2lm_err("vdev is null");
1604 		return QDF_STATUS_E_NULL_VALUE;
1605 	}
1606 
1607 	status = wlan_populate_link_disable_t2lm_frame(vdev, params);
1608 
1609 	if (QDF_IS_STATUS_ERROR(status))
1610 		t2lm_err("Failed to handle link disable");
1611 
1612 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
1613 	return status;
1614 }
1615 #endif
1616 
1617