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