xref: /wlan-dirver/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_t2lm_api.c (revision fe0c9461e0d07f801982087401e20be259f95eca)
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 TID to Link mapping related functionality
19  */
20 #include <wlan_cmn.h>
21 #include <wlan_cm_public_struct.h>
22 #include "wlan_t2lm_api.h"
23 #include <wlan_mlo_t2lm.h>
24 #include "wlan_cm_api.h"
25 #include "wlan_mlo_mgr_roam.h"
26 
27 #define T2LM_MIN_DIALOG_TOKEN         1
28 #define T2LM_MAX_DIALOG_TOKEN         0xFF
29 
30 static
31 const char *t2lm_get_event_str(enum wlan_t2lm_evt event)
32 {
33 	if (event > WLAN_T2LM_EV_ACTION_FRAME_MAX)
34 		return "";
35 
36 	switch (event) {
37 	CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_RX_REQ);
38 	CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_TX_RESP);
39 	CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_TX_REQ);
40 	CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_RX_RESP);
41 	CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_RX_TEARDOWN);
42 	CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_TX_TEARDOWN);
43 	default:
44 		return "Unknown";
45 	}
46 }
47 
48 static
49 bool t2lm_is_valid_t2lm_link_map(struct wlan_objmgr_vdev *vdev,
50 				 struct wlan_t2lm_onging_negotiation_info *t2lm,
51 				 enum wlan_t2lm_direction *valid_dir)
52 {
53 	uint8_t i, tid = 0;
54 	enum wlan_t2lm_direction dir = WLAN_T2LM_INVALID_DIRECTION;
55 	uint16_t ieee_link_mask = 0;
56 	uint16_t provisioned_links = 0;
57 	bool is_valid_link_mask = false;
58 	struct wlan_objmgr_vdev *ml_vdev = NULL;
59 	struct wlan_objmgr_vdev *ml_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL};
60 	uint16_t ml_vdev_cnt = 0;
61 
62 	/* Get the valid hw_link_id map from ML vdev list */
63 	mlo_get_ml_vdev_list(vdev, &ml_vdev_cnt, ml_vdev_list);
64 	if (!ml_vdev_cnt) {
65 		t2lm_err("Number of VDEVs under MLD is reported as 0");
66 		return false;
67 	}
68 
69 	for (i = 0; i < ml_vdev_cnt; i++) {
70 		ml_vdev = ml_vdev_list[i];
71 		if (!ml_vdev || !wlan_cm_is_vdev_connected(ml_vdev)) {
72 			t2lm_err("ML vdev is null");
73 			continue;
74 		}
75 
76 		ieee_link_mask |= BIT(wlan_vdev_get_link_id(ml_vdev));
77 	}
78 
79 	if (ml_vdev_cnt) {
80 		for (i = 0; i < ml_vdev_cnt; i++)
81 			mlo_release_vdev_ref(ml_vdev_list[i]);
82 	}
83 
84 	/* Check if the configured hw_link_id map is valid */
85 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {
86 		if (t2lm->t2lm_info[dir].direction ==
87 		    WLAN_T2LM_INVALID_DIRECTION)
88 			continue;
89 
90 		if (t2lm->t2lm_info[dir].default_link_mapping) {
91 			is_valid_link_mask = true;
92 			continue;
93 		}
94 
95 		for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++) {
96 			provisioned_links =
97 				t2lm->t2lm_info[dir].ieee_link_map_tid[tid];
98 
99 			for (i = 0; i < WLAN_T2LM_MAX_NUM_LINKS; i++) {
100 				if (!(provisioned_links & BIT(i)))
101 					continue;
102 
103 				if (ieee_link_mask & BIT(i)) {
104 					is_valid_link_mask = true;
105 					*valid_dir = dir;
106 					continue;
107 				} else {
108 					return false;
109 				}
110 			}
111 		}
112 	}
113 
114 	return is_valid_link_mask;
115 }
116 
117 static uint8_t
118 t2lm_gen_dialog_token(struct wlan_mlo_peer_t2lm_policy *t2lm_policy)
119 {
120 	if (!t2lm_policy)
121 		return 0;
122 
123 	if (t2lm_policy->self_gen_dialog_token == T2LM_MAX_DIALOG_TOKEN)
124 		/* wrap is ok */
125 		t2lm_policy->self_gen_dialog_token = T2LM_MIN_DIALOG_TOKEN;
126 	else
127 		t2lm_policy->self_gen_dialog_token += 1;
128 
129 	t2lm_debug("gen dialog token %d", t2lm_policy->self_gen_dialog_token);
130 	return t2lm_policy->self_gen_dialog_token;
131 }
132 
133 QDF_STATUS t2lm_handle_rx_req(struct wlan_objmgr_vdev *vdev,
134 			      struct wlan_objmgr_peer *peer,
135 			      void *event_data, uint8_t *token)
136 {
137 	struct wlan_t2lm_onging_negotiation_info t2lm_req = {0};
138 	struct wlan_t2lm_info *t2lm_info;
139 	enum wlan_t2lm_direction dir = WLAN_T2LM_MAX_DIRECTION;
140 	bool valid_map = false;
141 	QDF_STATUS status;
142 	struct wlan_mlo_peer_context *ml_peer;
143 
144 	ml_peer = peer->mlo_peer_ctx;
145 	if (!ml_peer)
146 		return QDF_STATUS_E_FAILURE;
147 
148 	status = wlan_mlo_parse_t2lm_action_frame(&t2lm_req, event_data,
149 						  WLAN_T2LM_CATEGORY_REQUEST);
150 	if (status != QDF_STATUS_SUCCESS) {
151 		mlme_err("Unable to parse T2LM request action frame");
152 		return QDF_STATUS_E_FAILURE;
153 	}
154 
155 	/*
156 	 * Check if ML vdevs are connected and link id matches with T2LM
157 	 * negotiation action request link id
158 	 */
159 	valid_map = t2lm_is_valid_t2lm_link_map(vdev, &t2lm_req, &dir);
160 	if (valid_map) {
161 		mlme_debug("Link match found,accept t2lm conf");
162 		status = QDF_STATUS_SUCCESS;
163 	} else {
164 		status = QDF_STATUS_E_FAILURE;
165 		mlme_err("reject t2lm conf");
166 	}
167 
168 	if (dir >= WLAN_T2LM_MAX_DIRECTION) {
169 		mlme_err("Received T2LM IE has invalid direction");
170 		status = QDF_STATUS_E_INVAL;
171 	}
172 
173 	if (QDF_IS_STATUS_SUCCESS(status) &&
174 	    t2lm_req.t2lm_info[dir].direction != WLAN_T2LM_INVALID_DIRECTION) {
175 		wlan_t2lm_clear_peer_negotiation(peer);
176 		/* Apply T2LM config to peer T2LM ctx */
177 		t2lm_info = &ml_peer->t2lm_policy.t2lm_negotiated_info.t2lm_info[dir];
178 		qdf_mem_copy(t2lm_info, &t2lm_req.t2lm_info[dir],
179 			     sizeof(struct wlan_t2lm_info));
180 	}
181 
182 	*token = t2lm_req.dialog_token;
183 
184 	return status;
185 }
186 
187 QDF_STATUS t2lm_handle_tx_resp(struct wlan_objmgr_vdev *vdev,
188 			       void *event_data, uint8_t *token)
189 {
190 	return QDF_STATUS_SUCCESS;
191 }
192 
193 QDF_STATUS t2lm_handle_tx_req(struct wlan_objmgr_vdev *vdev,
194 			      struct wlan_objmgr_peer *peer,
195 			      void *event_data, uint8_t *token)
196 {
197 	struct wlan_t2lm_onging_negotiation_info *t2lm_neg;
198 	struct wlan_action_frame_args args;
199 	QDF_STATUS status;
200 
201 	if (!vdev)
202 		return QDF_STATUS_E_NULL_VALUE;
203 
204 	if (!event_data) {
205 		t2lm_err("Null event data ptr");
206 		return QDF_STATUS_E_NULL_VALUE;
207 	}
208 
209 	t2lm_neg = (struct wlan_t2lm_onging_negotiation_info *)event_data;
210 	args.category = ACTION_CATEGORY_PROTECTED_EHT;
211 	args.action = EHT_T2LM_REQUEST;
212 	args.arg1 = *token;
213 
214 	status = lim_send_t2lm_action_req_frame(vdev,
215 						wlan_peer_get_macaddr(peer),
216 						&args, t2lm_neg,
217 						*token);
218 
219 	if (QDF_IS_STATUS_ERROR(status)) {
220 		t2lm_err("Failed to send T2LM action request frame");
221 	} else {
222 		t2lm_debug("Copy the ongoing neg to peer");
223 		qdf_mem_copy(&peer->mlo_peer_ctx->t2lm_policy.ongoing_tid_to_link_mapping,
224 			     t2lm_neg, sizeof(struct wlan_t2lm_onging_negotiation_info));
225 	}
226 
227 	return status;
228 }
229 
230 QDF_STATUS t2lm_handle_rx_resp(struct wlan_objmgr_vdev *vdev,
231 			       struct wlan_objmgr_peer *peer,
232 			       void *event_data, uint8_t *token)
233 {
234 	struct wlan_t2lm_onging_negotiation_info t2lm_rsp = {0};
235 	struct wlan_t2lm_onging_negotiation_info *t2lm_req;
236 	QDF_STATUS status;
237 	struct wlan_mlo_peer_context *ml_peer;
238 	struct wlan_t2lm_info *t2lm_info;
239 	uint8_t dir;
240 
241 	if (!peer) {
242 		t2lm_err("peer is null");
243 		return QDF_STATUS_E_NULL_VALUE;
244 	}
245 
246 	ml_peer = peer->mlo_peer_ctx;
247 	if (!ml_peer) {
248 		t2lm_err("ml peer is null");
249 		return QDF_STATUS_E_NULL_VALUE;
250 	}
251 
252 	/* ignore the frame if all links are not connected */
253 	if (!mlo_check_if_all_links_up(vdev))
254 		return QDF_STATUS_SUCCESS;
255 
256 	status = wlan_mlo_parse_t2lm_action_frame(&t2lm_rsp, event_data,
257 						  WLAN_T2LM_CATEGORY_RESPONSE);
258 	if (status != QDF_STATUS_SUCCESS) {
259 		mlme_err("Unable to parse T2LM request action frame");
260 		return QDF_STATUS_E_FAILURE;
261 	}
262 
263 	mlme_debug("t2lm rsp dialog token %d", t2lm_rsp.dialog_token);
264 	mlme_debug("t2lm rsp is %d", t2lm_rsp.t2lm_resp_type);
265 	t2lm_req = &ml_peer->t2lm_policy.ongoing_tid_to_link_mapping;
266 	if (!t2lm_req) {
267 		t2lm_err("Ongoing tid neg is null");
268 		return QDF_STATUS_E_FAILURE;
269 	}
270 
271 	for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) {
272 		t2lm_info = &t2lm_req->t2lm_info[dir];
273 		if (t2lm_info &&
274 		    t2lm_info->direction != WLAN_T2LM_INVALID_DIRECTION) {
275 			if (t2lm_rsp.dialog_token == t2lm_req->dialog_token &&
276 			    t2lm_rsp.t2lm_resp_type == WLAN_T2LM_RESP_TYPE_SUCCESS) {
277 				status = wlan_send_tid_to_link_mapping(vdev,
278 								       t2lm_info);
279 				if (QDF_IS_STATUS_ERROR(status)) {
280 					t2lm_err("sending t2lm wmi failed");
281 					break;
282 				}
283 			} else if (t2lm_rsp.dialog_token == t2lm_req->dialog_token &&
284 				   t2lm_rsp.t2lm_resp_type != WLAN_T2LM_RESP_TYPE_PREFERRED_TID_TO_LINK_MAPPING) {
285 				t2lm_debug("T2LM rsp status denied, clear ongoing tid mapping");
286 				wlan_t2lm_clear_ongoing_negotiation(peer);
287 			}
288 		}
289 	}
290 
291 	return status;
292 }
293 
294 QDF_STATUS t2lm_handle_rx_teardown(struct wlan_objmgr_vdev *vdev,
295 				   struct wlan_objmgr_peer *peer,
296 				   void *event_data)
297 {
298 	struct wlan_mlo_dev_context *mlo_dev_ctx;
299 	struct wlan_t2lm_context *t2lm_ctx;
300 
301 	if (!peer) {
302 		t2lm_err("peer is null");
303 		return QDF_STATUS_E_NULL_VALUE;
304 	}
305 
306 	if (!vdev) {
307 		t2lm_err("vdev is null");
308 		return QDF_STATUS_E_NULL_VALUE;
309 	}
310 
311 	mlo_dev_ctx = vdev->mlo_dev_ctx;
312 	if (!mlo_dev_ctx) {
313 		t2lm_err("mlo dev ctx is null");
314 		return QDF_STATUS_E_NULL_VALUE;
315 	}
316 
317 	t2lm_ctx = &mlo_dev_ctx->t2lm_ctx;
318 	if (!t2lm_ctx) {
319 		t2lm_err("t2lm ctx is null");
320 		return QDF_STATUS_E_NULL_VALUE;
321 	}
322 
323 	wlan_t2lm_clear_peer_negotiation(peer);
324 
325 	/* Notify the registered caller about the link update*/
326 	wlan_mlo_dev_t2lm_notify_link_update(vdev,
327 					     &t2lm_ctx->established_t2lm.t2lm);
328 	wlan_send_tid_to_link_mapping(vdev,
329 				      &t2lm_ctx->established_t2lm.t2lm);
330 
331 	return QDF_STATUS_SUCCESS;
332 }
333 
334 QDF_STATUS t2lm_handle_tx_teardown(struct wlan_objmgr_vdev *vdev,
335 				   void *event_data)
336 {
337 	return QDF_STATUS_SUCCESS;
338 }
339 
340 QDF_STATUS t2lm_deliver_event(struct wlan_objmgr_vdev *vdev,
341 			      struct wlan_objmgr_peer *peer,
342 			      enum wlan_t2lm_evt event,
343 			      void *event_data, uint8_t *token)
344 {
345 	struct wlan_objmgr_psoc *psoc;
346 	QDF_STATUS status;
347 
348 	psoc = wlan_vdev_get_psoc(vdev);
349 	if (!psoc)
350 		return QDF_STATUS_E_FAILURE;
351 
352 	mlme_debug("T2LM event received: %s(%d)",
353 		   t2lm_get_event_str(event), event);
354 
355 	switch (event) {
356 	case WLAN_T2LM_EV_ACTION_FRAME_RX_REQ:
357 		status = t2lm_handle_rx_req(vdev, peer, event_data, token);
358 		break;
359 	case WLAN_T2LM_EV_ACTION_FRAME_TX_RESP:
360 		status = t2lm_handle_tx_resp(vdev, event_data, token);
361 		break;
362 	case WLAN_T2LM_EV_ACTION_FRAME_TX_REQ:
363 		status = t2lm_handle_tx_req(vdev, peer, event_data, token);
364 		break;
365 	case WLAN_T2LM_EV_ACTION_FRAME_RX_RESP:
366 		status = t2lm_handle_rx_resp(vdev, peer, event_data, token);
367 		break;
368 	case WLAN_T2LM_EV_ACTION_FRAME_RX_TEARDOWN:
369 		status = t2lm_handle_rx_teardown(vdev, peer, event_data);
370 		break;
371 	case WLAN_T2LM_EV_ACTION_FRAME_TX_TEARDOWN:
372 		status = t2lm_handle_tx_teardown(vdev, event_data);
373 		break;
374 	default:
375 		status = QDF_STATUS_E_FAILURE;
376 		mlme_err("Unhandled T2LM event");
377 	}
378 
379 	return status;
380 }
381 
382 static uint16_t
383 t2lm_get_tids_mapped_link_id(uint16_t link_map_tid)
384 {
385 	uint16_t all_tids_mapped_link_id = 0;
386 	uint8_t i;
387 	uint8_t bit_mask = 1;
388 
389 	for (i = 0; i < WLAN_T2LM_MAX_NUM_LINKS; i++) {
390 		if (link_map_tid & bit_mask)
391 			all_tids_mapped_link_id = i;
392 		bit_mask = bit_mask << 1;
393 	}
394 
395 	return all_tids_mapped_link_id;
396 }
397 
398 static QDF_STATUS
399 t2lm_find_tid_mapped_link_id(struct wlan_t2lm_info *t2lm_info,
400 			     uint16_t *tid_mapped_link_id)
401 {
402 	uint16_t link_map_tid;
403 	uint8_t tid;
404 
405 	if (!t2lm_info)
406 		return QDF_STATUS_E_NULL_VALUE;
407 
408 	if (t2lm_info->default_link_mapping) {
409 		t2lm_debug("T2LM ie has default link mapping");
410 		*tid_mapped_link_id = 0xFFFF;
411 		return QDF_STATUS_SUCCESS;
412 	}
413 
414 	link_map_tid = t2lm_info->ieee_link_map_tid[0];
415 	for (tid = 1; tid < T2LM_MAX_NUM_TIDS; tid++) {
416 		if (link_map_tid != t2lm_info->ieee_link_map_tid[tid]) {
417 			mlme_debug("all tids are not mapped to same link set");
418 			return QDF_STATUS_E_FAILURE;
419 		}
420 	}
421 
422 	*tid_mapped_link_id = t2lm_get_tids_mapped_link_id(link_map_tid);
423 	return QDF_STATUS_SUCCESS;
424 }
425 
426 QDF_STATUS
427 wlan_t2lm_validate_candidate(struct cnx_mgr *cm_ctx,
428 			     struct scan_cache_entry *scan_entry)
429 {
430 	QDF_STATUS status = QDF_STATUS_SUCCESS;
431 	struct wlan_objmgr_vdev *vdev;
432 	struct wlan_t2lm_context t2lm_ctx;
433 	uint16_t tid_map_link_id;
434 	uint16_t established_tid_mapped_link_id = 0;
435 	uint16_t upcoming_tid_mapped_link_id = 0;
436 
437 	if (!scan_entry)
438 		return QDF_STATUS_E_NULL_VALUE;
439 
440 	if (!cm_ctx || !cm_ctx->vdev)
441 		return QDF_STATUS_E_NULL_VALUE;
442 
443 	vdev = cm_ctx->vdev;
444 
445 	if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) {
446 		mlme_debug("Skip t2lm validation for link vdev");
447 		return QDF_STATUS_SUCCESS;
448 	}
449 
450 	if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) &&
451 	    scan_entry->ie_list.t2lm[0]) {
452 		status = wlan_mlo_parse_bcn_prbresp_t2lm_ie(&t2lm_ctx,
453 						scan_entry->ie_list.t2lm[0]);
454 		if (QDF_IS_STATUS_ERROR(status))
455 			goto end;
456 
457 		status =
458 		   t2lm_find_tid_mapped_link_id(&t2lm_ctx.established_t2lm.t2lm,
459 					       &established_tid_mapped_link_id);
460 		if (QDF_IS_STATUS_ERROR(status))
461 			goto end;
462 
463 		status =
464 		      t2lm_find_tid_mapped_link_id(&t2lm_ctx.upcoming_t2lm.t2lm,
465 						  &upcoming_tid_mapped_link_id);
466 		if (QDF_IS_STATUS_ERROR(status))
467 			goto end;
468 		t2lm_debug("established_tid_mapped_link_id %x, upcoming_tid_mapped_link_id %x",
469 			   established_tid_mapped_link_id,
470 			   upcoming_tid_mapped_link_id);
471 
472 		tid_map_link_id =
473 		   established_tid_mapped_link_id & upcoming_tid_mapped_link_id;
474 		if (!tid_map_link_id)
475 			tid_map_link_id = established_tid_mapped_link_id;
476 
477 		if (tid_map_link_id == scan_entry->ml_info.self_link_id) {
478 			t2lm_debug("self link id %d, tid map link id %d match",
479 				   scan_entry->ml_info.self_link_id,
480 				   tid_map_link_id);
481 			status = QDF_STATUS_SUCCESS;
482 		} else {
483 			t2lm_debug("self link id %d, tid map link id %d do not match",
484 				   scan_entry->ml_info.self_link_id,
485 				   tid_map_link_id);
486 			status = QDF_STATUS_E_FAILURE;
487 		}
488 	} else {
489 		t2lm_debug("T2LM IE is not present in scan entry");
490 		status = QDF_STATUS_SUCCESS;
491 	}
492 
493 end:
494 	return status;
495 }
496 
497 void
498 wlan_t2lm_clear_ongoing_negotiation(struct wlan_objmgr_peer *peer)
499 {
500 	struct wlan_mlo_peer_context *ml_peer;
501 	struct wlan_t2lm_onging_negotiation_info *ongoing_tid_to_link_mapping;
502 	uint8_t i;
503 
504 	ml_peer = peer->mlo_peer_ctx;
505 	if (!ml_peer) {
506 		t2lm_err("ml peer is null");
507 		return;
508 	}
509 
510 	ongoing_tid_to_link_mapping = &ml_peer->t2lm_policy.ongoing_tid_to_link_mapping;
511 	if (!ongoing_tid_to_link_mapping) {
512 		t2lm_err("ongoing tid mapping is null");
513 		return;
514 	}
515 
516 	qdf_mem_zero(&ongoing_tid_to_link_mapping->t2lm_info,
517 		     sizeof(struct wlan_t2lm_info) * WLAN_T2LM_MAX_DIRECTION);
518 
519 	ongoing_tid_to_link_mapping->dialog_token = 0;
520 	ongoing_tid_to_link_mapping->category = WLAN_T2LM_CATEGORY_NONE;
521 	ongoing_tid_to_link_mapping->t2lm_resp_type = WLAN_T2LM_RESP_TYPE_INVALID;
522 	ongoing_tid_to_link_mapping->t2lm_tx_status = WLAN_T2LM_TX_STATUS_NONE;
523 
524 	for (i = 0; i < WLAN_T2LM_MAX_DIRECTION; i++)
525 		ongoing_tid_to_link_mapping->t2lm_info[i].direction =
526 				WLAN_T2LM_INVALID_DIRECTION;
527 }
528 
529 void
530 wlan_t2lm_clear_peer_negotiation(struct wlan_objmgr_peer *peer)
531 {
532 	struct wlan_mlo_peer_context *ml_peer;
533 	struct wlan_prev_t2lm_negotiated_info *t2lm_negotiated_info;
534 	uint8_t i;
535 
536 	ml_peer = peer->mlo_peer_ctx;
537 	if (!ml_peer) {
538 		t2lm_err("ml peer is null");
539 		return;
540 	}
541 
542 	qdf_mem_zero(&ml_peer->t2lm_policy.t2lm_negotiated_info.t2lm_info,
543 		     sizeof(struct wlan_t2lm_info) * WLAN_T2LM_MAX_DIRECTION);
544 
545 	ml_peer->t2lm_policy.t2lm_negotiated_info.dialog_token = 0;
546 	t2lm_negotiated_info = &ml_peer->t2lm_policy.t2lm_negotiated_info;
547 	for (i = 0; i < WLAN_T2LM_MAX_DIRECTION; i++)
548 		t2lm_negotiated_info->t2lm_info[i].direction =
549 				WLAN_T2LM_INVALID_DIRECTION;
550 }
551 
552 void
553 wlan_t2lm_clear_all_tid_mapping(struct wlan_objmgr_vdev *vdev)
554 {
555 	struct wlan_objmgr_peer *peer;
556 	struct wlan_t2lm_context *t2lm_ctx;
557 
558 	if (!vdev) {
559 		t2lm_err("Vdev is null");
560 		return;
561 	}
562 
563 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev))
564 		return;
565 
566 	if (!vdev->mlo_dev_ctx) {
567 		t2lm_err("mlo dev ctx is null");
568 		return;
569 	}
570 
571 	t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx;
572 	peer = wlan_vdev_get_bsspeer(vdev);
573 	if (!peer) {
574 		t2lm_err("peer is null");
575 		return;
576 	}
577 	qdf_mem_zero(&t2lm_ctx->established_t2lm,
578 		     sizeof(struct wlan_mlo_t2lm_ie));
579 	t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_BIDI_DIRECTION;
580 	t2lm_ctx->established_t2lm.t2lm.default_link_mapping = 1;
581 	t2lm_ctx->established_t2lm.t2lm.link_mapping_size = 0;
582 
583 	qdf_mem_zero(&t2lm_ctx->upcoming_t2lm,
584 		     sizeof(struct wlan_mlo_t2lm_ie));
585 	t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION;
586 
587 	wlan_t2lm_clear_peer_negotiation(peer);
588 	wlan_t2lm_clear_ongoing_negotiation(peer);
589 	wlan_mlo_t2lm_timer_stop(vdev);
590 }
591 
592 static bool
593 wlan_is_ml_link_disabled(uint32_t link_id_bitmap,
594 			 uint8_t ml_link_id)
595 {
596 	uint8_t link;
597 
598 	if (!link_id_bitmap) {
599 		t2lm_err("Link id bitmap is 0");
600 		return false;
601 	}
602 
603 	for (link = 0; link < WLAN_T2LM_MAX_NUM_LINKS; link++) {
604 		if ((link == ml_link_id) &&
605 		    (link_id_bitmap & BIT(link))) {
606 			return true;
607 		}
608 	}
609 
610 	return false;
611 }
612 
613 static void
614 wlan_t2lm_set_link_mapping_of_tids(uint8_t link_id,
615 				   struct wlan_t2lm_info *t2lm_info,
616 				   bool set)
617 {
618 	uint8_t tid_num;
619 
620 	if (link_id >= WLAN_T2LM_MAX_NUM_LINKS) {
621 		t2lm_err("Max 16 t2lm links are supported");
622 		return;
623 	}
624 
625 	for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) {
626 		if (set)
627 			t2lm_info->ieee_link_map_tid[tid_num] |= BIT(link_id);
628 		else
629 			t2lm_info->ieee_link_map_tid[tid_num] &= ~BIT(link_id);
630 	}
631 }
632 
633 QDF_STATUS
634 wlan_populate_link_disable_t2lm_frame(struct wlan_objmgr_vdev *vdev,
635 				      struct mlo_link_disable_request_evt_params *params)
636 {
637 	struct wlan_objmgr_peer *peer;
638 	struct wlan_mlo_dev_context *ml_dev_ctx;
639 	struct wlan_mlo_peer_t2lm_policy *t2lm_policy;
640 	struct wlan_objmgr_vdev *tmp_vdev;
641 	struct wlan_t2lm_onging_negotiation_info t2lm_neg = {0};
642 	uint8_t dir = WLAN_T2LM_BIDI_DIRECTION;
643 	uint8_t i = 0;
644 	QDF_STATUS status;
645 	uint8_t link_id;
646 
647 	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev,
648 						WLAN_MLO_MGR_ID);
649 
650 	if (!peer) {
651 		t2lm_err("peer is null");
652 		return QDF_STATUS_E_NULL_VALUE;
653 	}
654 
655 	if (!vdev->mlo_dev_ctx)
656 		return QDF_STATUS_E_NULL_VALUE;
657 
658 	t2lm_policy = &peer->mlo_peer_ctx->t2lm_policy;
659 	t2lm_neg = t2lm_policy->ongoing_tid_to_link_mapping;
660 
661 	t2lm_neg.category = WLAN_T2LM_CATEGORY_REQUEST;
662 	t2lm_neg.dialog_token = t2lm_gen_dialog_token(t2lm_policy);
663 	qdf_mem_zero(&t2lm_neg.t2lm_info,
664 		     sizeof(struct wlan_t2lm_info) * WLAN_T2LM_MAX_DIRECTION);
665 	for (i = 0; i < WLAN_T2LM_MAX_DIRECTION; i++)
666 		t2lm_neg.t2lm_info[i].direction = WLAN_T2LM_INVALID_DIRECTION;
667 
668 	t2lm_neg.t2lm_info[dir].default_link_mapping = 0;
669 	t2lm_neg.t2lm_info[dir].direction = WLAN_T2LM_BIDI_DIRECTION;
670 	t2lm_neg.t2lm_info[dir].mapping_switch_time_present = 0;
671 	t2lm_neg.t2lm_info[dir].expected_duration_present = 0;
672 	t2lm_neg.t2lm_info[dir].link_mapping_size = 1;
673 
674 	t2lm_debug("dir %d", t2lm_neg.t2lm_info[dir].direction);
675 	ml_dev_ctx = vdev->mlo_dev_ctx;
676 
677 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
678 		if (!ml_dev_ctx->wlan_vdev_list[i])
679 			continue;
680 
681 		tmp_vdev = ml_dev_ctx->wlan_vdev_list[i];
682 		link_id = wlan_vdev_get_link_id(tmp_vdev);
683 
684 		/* if link id matches disabled link id bitmap
685 		 * set that bit as 0.
686 		 */
687 		if (wlan_is_ml_link_disabled(params->link_id_bitmap,
688 					     link_id)) {
689 			wlan_t2lm_set_link_mapping_of_tids(link_id,
690 						&t2lm_neg.t2lm_info[dir],
691 						0);
692 			t2lm_debug("Disabled link id %d", link_id);
693 		} else {
694 			wlan_t2lm_set_link_mapping_of_tids(link_id,
695 						&t2lm_neg.t2lm_info[dir],
696 						1);
697 			t2lm_debug("Enabled link id %d", link_id);
698 		}
699 	}
700 
701 	status = t2lm_deliver_event(vdev, peer,
702 				    WLAN_T2LM_EV_ACTION_FRAME_TX_REQ,
703 				    &t2lm_neg,
704 				    &t2lm_neg.dialog_token);
705 
706 	wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
707 	return status;
708 }
709 
710 QDF_STATUS wlan_t2lm_deliver_event(struct wlan_objmgr_vdev *vdev,
711 				   struct wlan_objmgr_peer *peer,
712 				   enum wlan_t2lm_evt event,
713 				   void *event_data,
714 				   uint8_t *dialog_token)
715 {
716 	return t2lm_deliver_event(vdev, peer, event, event_data, dialog_token);
717 }
718