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