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