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(¶ms->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