1 /*
2 * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * DOC: wlan_tdls_ct.c
22 *
23 * TDLS connection tracker function definitions
24 */
25
26 #include "wlan_tdls_main.h"
27 #include "wlan_tdls_peer.h"
28 #include "wlan_tdls_ct.h"
29 #include "wlan_tdls_mgmt.h"
30 #include "wlan_mlo_mgr_sta.h"
31 #include "wlan_tdls_cmds_process.h"
32 #include "wlan_reg_services_api.h"
33 #include "wlan_policy_mgr_api.h"
34 #include "wlan_tdls_tgt_api.h"
35
tdls_is_vdev_authenticated(struct wlan_objmgr_vdev * vdev)36 bool tdls_is_vdev_authenticated(struct wlan_objmgr_vdev *vdev)
37 {
38 struct wlan_objmgr_peer *peer;
39 bool is_authenticated = false;
40
41 peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_NB_ID);
42 if (!peer) {
43 tdls_err("peer is null");
44 return false;
45 }
46
47 is_authenticated = wlan_peer_mlme_get_auth_state(peer);
48 wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID);
49 return is_authenticated;
50 }
51
52 /**
53 * tdls_peer_reset_discovery_processed() - reset discovery status
54 * @tdls_vdev: TDLS vdev object
55 *
56 * This function resets discovery processing bit for all TDLS peers
57 *
58 * Caller has to take the lock before calling this function
59 *
60 * Return: 0
61 */
tdls_peer_reset_discovery_processed(struct tdls_vdev_priv_obj * tdls_vdev)62 static int32_t tdls_peer_reset_discovery_processed(
63 struct tdls_vdev_priv_obj *tdls_vdev)
64 {
65 int i;
66 qdf_list_t *head;
67 qdf_list_node_t *p_node;
68 struct tdls_peer *peer;
69 QDF_STATUS status;
70
71 tdls_vdev->discovery_peer_cnt = 0;
72
73 for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
74 head = &tdls_vdev->peer_list[i];
75 status = qdf_list_peek_front(head, &p_node);
76 while (QDF_IS_STATUS_SUCCESS(status)) {
77 peer = qdf_container_of(p_node, struct tdls_peer, node);
78 peer->discovery_processed = 0;
79 status = qdf_list_peek_next(head, p_node, &p_node);
80 }
81 }
82
83 return 0;
84 }
85
tdls_discovery_timeout_peer_cb(void * user_data)86 void tdls_discovery_timeout_peer_cb(void *user_data)
87 {
88 int i;
89 qdf_list_t *head;
90 qdf_list_node_t *p_node;
91 struct tdls_peer *peer;
92 QDF_STATUS status;
93 struct tdls_vdev_priv_obj *tdls_vdev;
94 struct tdls_soc_priv_obj *tdls_soc;
95 struct wlan_objmgr_vdev *vdev;
96 struct wlan_objmgr_vdev *select_vdev;
97 struct wlan_objmgr_vdev *tdls_link_vdev;
98 struct tdls_rx_mgmt_frame *rx_mgmt;
99 uint8_t *mac;
100 bool unforce = true;
101
102 vdev = user_data;
103 if (!vdev) {
104 tdls_err("discovery time out vdev is null");
105 return;
106 }
107
108 tdls_soc = wlan_vdev_get_tdls_soc_obj(vdev);
109 if (!tdls_soc)
110 return;
111
112 /* timer_cnt is reset when link switch happens */
113 if (wlan_vdev_mlme_is_mlo_vdev(vdev) &&
114 qdf_atomic_read(&tdls_soc->timer_cnt) == 0)
115 return;
116
117 if (wlan_vdev_mlme_is_mlo_vdev(vdev) &&
118 qdf_atomic_dec_and_test(&tdls_soc->timer_cnt)) {
119 tdls_process_mlo_cal_tdls_link_score(vdev);
120 select_vdev = tdls_process_mlo_choice_tdls_vdev(vdev);
121 tdls_link_vdev = tdls_mlo_get_tdls_link_vdev(vdev);
122 if (select_vdev) {
123 tdls_vdev =
124 wlan_objmgr_vdev_get_comp_private_obj(select_vdev,
125 WLAN_UMAC_COMP_TDLS);
126 rx_mgmt = tdls_vdev->rx_mgmt;
127 if (tdls_link_vdev && tdls_link_vdev != select_vdev) {
128 tdls_debug("tdls link created on vdev %d",
129 wlan_vdev_get_id(tdls_link_vdev));
130 } else {
131 mac =
132 &rx_mgmt->buf[TDLS_80211_PEER_ADDR_OFFSET];
133 tdls_notice("[TDLS] TDLS Discovery Response,"
134 "QDF_MAC_ADDR_FMT RSSI[%d]<---OTA",
135 rx_mgmt->rx_rssi);
136 tdls_debug("discovery resp on vdev %d",
137 wlan_vdev_get_id(tdls_vdev->vdev));
138 tdls_recv_discovery_resp(tdls_vdev, mac);
139 tdls_set_rssi(tdls_vdev->vdev, mac,
140 rx_mgmt->rx_rssi);
141 if (tdls_soc && tdls_soc->tdls_rx_cb)
142 tdls_soc->tdls_rx_cb(
143 tdls_soc->tdls_rx_cb_data,
144 rx_mgmt);
145 }
146
147 qdf_mem_free(tdls_vdev->rx_mgmt);
148 tdls_vdev->rx_mgmt = NULL;
149 tdls_vdev->link_score = 0;
150
151 return;
152 }
153
154 tdls_debug("no discovery response");
155 }
156
157 tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev);
158 if (!tdls_vdev)
159 return;
160
161 for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
162 head = &tdls_vdev->peer_list[i];
163 status = qdf_list_peek_front(head, &p_node);
164 while (QDF_IS_STATUS_SUCCESS(status)) {
165 peer = qdf_container_of(p_node, struct tdls_peer,
166 node);
167
168 tdls_debug("Peer: " QDF_MAC_ADDR_FMT " link status %d, vdev id %d",
169 QDF_MAC_ADDR_REF(peer->peer_mac.bytes),
170 peer->link_status, wlan_vdev_get_id(vdev));
171
172 if (peer->link_status != TDLS_LINK_DISCOVERING &&
173 peer->link_status != TDLS_LINK_IDLE)
174 unforce = false;
175
176 if (TDLS_LINK_DISCOVERING != peer->link_status) {
177 status = qdf_list_peek_next(head, p_node,
178 &p_node);
179 continue;
180 }
181 tdls_debug(QDF_MAC_ADDR_FMT " to idle state",
182 QDF_MAC_ADDR_REF(peer->peer_mac.bytes));
183 tdls_set_peer_link_status(peer,
184 TDLS_LINK_IDLE,
185 TDLS_LINK_NOT_SUPPORTED);
186 }
187 }
188
189 if (wlan_vdev_mlme_is_mlo_vdev(vdev) && unforce) {
190 tdls_debug("try to set vdev %d to unforce",
191 wlan_vdev_get_id(vdev));
192 tdls_set_link_unforce(vdev);
193 }
194
195 tdls_vdev->discovery_sent_cnt = 0;
196 /* add tdls power save prohibited */
197
198 return;
199 }
200
201 /**
202 * tdls_reset_tx_rx() - reset tx/rx counters for all tdls peers
203 * @tdls_vdev: TDLS vdev object
204 *
205 * Caller has to take the TDLS lock before calling this function
206 *
207 * Return: Void
208 */
tdls_reset_tx_rx(struct tdls_vdev_priv_obj * tdls_vdev)209 static void tdls_reset_tx_rx(struct tdls_vdev_priv_obj *tdls_vdev)
210 {
211 int i;
212 qdf_list_t *head;
213 qdf_list_node_t *p_node;
214 struct tdls_peer *peer;
215 QDF_STATUS status;
216 struct tdls_soc_priv_obj *tdls_soc;
217
218 tdls_soc = wlan_vdev_get_tdls_soc_obj(tdls_vdev->vdev);
219 if (!tdls_soc)
220 return;
221
222 /* reset stale connection tracker */
223 qdf_spin_lock_bh(&tdls_soc->tdls_ct_spinlock);
224 tdls_vdev->valid_mac_entries = 0;
225 qdf_spin_unlock_bh(&tdls_soc->tdls_ct_spinlock);
226
227 for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
228 head = &tdls_vdev->peer_list[i];
229 status = qdf_list_peek_front(head, &p_node);
230 while (QDF_IS_STATUS_SUCCESS(status)) {
231 peer = qdf_container_of(p_node, struct tdls_peer, node);
232 peer->tx_pkt = 0;
233 peer->rx_pkt = 0;
234 status = qdf_list_peek_next(head, p_node, &p_node);
235 }
236 }
237 return;
238 }
239
tdls_implicit_disable(struct tdls_vdev_priv_obj * tdls_vdev)240 void tdls_implicit_disable(struct tdls_vdev_priv_obj *tdls_vdev)
241 {
242 tdls_debug("Disable Implicit TDLS");
243 tdls_timers_stop(tdls_vdev);
244 }
245
246 /**
247 * tdls_implicit_enable() - enable implicit tdls triggering
248 * @tdls_vdev: TDLS vdev
249 *
250 * Return: Void
251 */
tdls_implicit_enable(struct tdls_vdev_priv_obj * tdls_vdev)252 void tdls_implicit_enable(struct tdls_vdev_priv_obj *tdls_vdev)
253 {
254 if (!tdls_vdev)
255 return;
256
257 tdls_debug("vdev:%d Enable Implicit TDLS",
258 wlan_vdev_get_id(tdls_vdev->vdev));
259
260 tdls_peer_reset_discovery_processed(tdls_vdev);
261 tdls_reset_tx_rx(tdls_vdev);
262 /* TODO check whether tdls power save prohibited */
263
264 /* Restart the connection tracker timer */
265 tdls_timer_restart(tdls_vdev->vdev, &tdls_vdev->peer_update_timer,
266 tdls_vdev->threshold_config.tx_period_t);
267 }
268
269 /**
270 * tdls_ct_sampling_tx_rx() - collect tx/rx traffic sample
271 * @tdls_vdev: tdls vdev object
272 * @tdls_soc: tdls soc object
273 *
274 * Function to update data traffic information in tdls connection
275 * tracker data structure for connection tracker operation
276 *
277 * Return: None
278 */
tdls_ct_sampling_tx_rx(struct tdls_vdev_priv_obj * tdls_vdev,struct tdls_soc_priv_obj * tdls_soc)279 static void tdls_ct_sampling_tx_rx(struct tdls_vdev_priv_obj *tdls_vdev,
280 struct tdls_soc_priv_obj *tdls_soc)
281 {
282 struct tdls_peer *curr_peer;
283 uint8_t mac[QDF_MAC_ADDR_SIZE];
284 uint8_t mac_cnt;
285 uint8_t mac_entries;
286 struct tdls_conn_tracker_mac_table mac_table[WLAN_TDLS_CT_TABLE_SIZE];
287
288 qdf_spin_lock_bh(&tdls_soc->tdls_ct_spinlock);
289
290 if (0 == tdls_vdev->valid_mac_entries) {
291 qdf_spin_unlock_bh(&tdls_soc->tdls_ct_spinlock);
292 return;
293 }
294
295 mac_entries = QDF_MIN(tdls_vdev->valid_mac_entries,
296 WLAN_TDLS_CT_TABLE_SIZE);
297
298 qdf_mem_copy(mac_table, tdls_vdev->ct_peer_table,
299 (sizeof(struct tdls_conn_tracker_mac_table)) * mac_entries);
300
301 qdf_mem_zero(tdls_vdev->ct_peer_table,
302 (sizeof(struct tdls_conn_tracker_mac_table)) * mac_entries);
303
304 tdls_vdev->valid_mac_entries = 0;
305
306 qdf_spin_unlock_bh(&tdls_soc->tdls_ct_spinlock);
307
308 for (mac_cnt = 0; mac_cnt < mac_entries; mac_cnt++) {
309 qdf_mem_copy(mac, mac_table[mac_cnt].mac_address.bytes,
310 QDF_MAC_ADDR_SIZE);
311 curr_peer = tdls_get_peer(tdls_vdev, mac);
312 if (curr_peer) {
313 curr_peer->tx_pkt =
314 mac_table[mac_cnt].tx_packet_cnt;
315 curr_peer->rx_pkt =
316 mac_table[mac_cnt].rx_packet_cnt;
317 }
318 }
319 }
320
tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr * mac_addr,struct qdf_mac_addr * dest_mac_addr)321 void tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
322 struct qdf_mac_addr *mac_addr,
323 struct qdf_mac_addr *dest_mac_addr)
324 {
325 struct tdls_vdev_priv_obj *tdls_vdev_obj;
326 struct tdls_soc_priv_obj *tdls_soc_obj;
327 uint8_t mac_cnt;
328 uint8_t valid_mac_entries;
329 struct tdls_conn_tracker_mac_table *mac_table;
330 struct wlan_objmgr_peer *bss_peer;
331
332 if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj,
333 &tdls_soc_obj))
334 return;
335
336 if (!tdls_soc_obj->enable_tdls_connection_tracker)
337 return;
338
339 /* Here we do without lock to ensure that in high throughput scenarios
340 * its fast and we quickly check the right mac entry and increment
341 * the pkt count. Here it may happen that
342 * "tdls_vdev_obj->valid_mac_entries", "tdls_vdev_obj->ct_peer_table"
343 * becomes zero in another thread but we are ok as this will not
344 * lead to any crash.
345 */
346 valid_mac_entries = tdls_vdev_obj->valid_mac_entries;
347 mac_table = tdls_vdev_obj->ct_peer_table;
348
349 for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) {
350 if (qdf_mem_cmp(mac_table[mac_cnt].mac_address.bytes,
351 mac_addr, QDF_MAC_ADDR_SIZE) == 0) {
352 mac_table[mac_cnt].rx_packet_cnt++;
353 return;
354 }
355 }
356
357 if (qdf_is_macaddr_group(mac_addr))
358 return;
359
360 if (qdf_is_macaddr_group(dest_mac_addr))
361 return;
362
363 if (!qdf_mem_cmp(vdev->vdev_mlme.macaddr, mac_addr,
364 QDF_MAC_ADDR_SIZE))
365 return;
366
367 bss_peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_NB_ID);
368 if (bss_peer) {
369 if (!qdf_mem_cmp(bss_peer->macaddr, mac_addr,
370 QDF_MAC_ADDR_SIZE)) {
371 wlan_objmgr_peer_release_ref(bss_peer, WLAN_TDLS_NB_ID);
372 return;
373 }
374 wlan_objmgr_peer_release_ref(bss_peer, WLAN_TDLS_NB_ID);
375 }
376 qdf_spin_lock_bh(&tdls_soc_obj->tdls_ct_spinlock);
377
378 /* when we take the lock we need to get the valid mac entries
379 * again as it may become zero in another thread and if is 0 then
380 * we need to reset "mac_cnt" to zero so that at zeroth index we
381 * add new entry
382 */
383 valid_mac_entries = tdls_vdev_obj->valid_mac_entries;
384 if (!valid_mac_entries)
385 mac_cnt = 0;
386
387 /* If we have more than 8 peers within 30 mins. we will
388 * stop tracking till the old entries are removed
389 */
390 if (mac_cnt < WLAN_TDLS_CT_TABLE_SIZE) {
391 qdf_mem_copy(mac_table[mac_cnt].mac_address.bytes,
392 mac_addr, QDF_MAC_ADDR_SIZE);
393 tdls_vdev_obj->valid_mac_entries = mac_cnt+1;
394 mac_table[mac_cnt].rx_packet_cnt = 1;
395 }
396
397 qdf_spin_unlock_bh(&tdls_soc_obj->tdls_ct_spinlock);
398 return;
399 }
400
tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr * mac_addr)401 void tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
402 struct qdf_mac_addr *mac_addr)
403 {
404 struct tdls_vdev_priv_obj *tdls_vdev_obj;
405 struct tdls_soc_priv_obj *tdls_soc_obj;
406 uint8_t mac_cnt;
407 uint8_t valid_mac_entries;
408 struct tdls_conn_tracker_mac_table *mac_table;
409 struct wlan_objmgr_peer *bss_peer;
410
411 if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj,
412 &tdls_soc_obj))
413 return;
414
415 if (!tdls_soc_obj->enable_tdls_connection_tracker)
416 return;
417
418 /* Here we do without lock to ensure that in high throughput scenarios
419 * its fast and we quickly check the right mac entry and increment
420 * the pkt count. Here it may happen that
421 * "tdls_vdev_obj->valid_mac_entries", "tdls_vdev_obj->ct_peer_table"
422 * becomes zero in another thread but we are ok as this will not
423 * lead to any crash.
424 */
425 mac_table = tdls_vdev_obj->ct_peer_table;
426 valid_mac_entries = tdls_vdev_obj->valid_mac_entries;
427
428 for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) {
429 if (qdf_mem_cmp(mac_table[mac_cnt].mac_address.bytes,
430 mac_addr, QDF_MAC_ADDR_SIZE) == 0) {
431 mac_table[mac_cnt].tx_packet_cnt++;
432 return;
433 }
434 }
435
436 if (qdf_is_macaddr_group(mac_addr))
437 return;
438
439 if (!qdf_mem_cmp(vdev->vdev_mlme.macaddr, mac_addr,
440 QDF_MAC_ADDR_SIZE))
441 return;
442 bss_peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_NB_ID);
443 if (bss_peer) {
444 if (!qdf_mem_cmp(bss_peer->macaddr, mac_addr,
445 QDF_MAC_ADDR_SIZE)) {
446 wlan_objmgr_peer_release_ref(bss_peer, WLAN_TDLS_NB_ID);
447 return;
448 }
449 wlan_objmgr_peer_release_ref(bss_peer, WLAN_TDLS_NB_ID);
450 }
451
452 qdf_spin_lock_bh(&tdls_soc_obj->tdls_ct_spinlock);
453
454 /* when we take the lock we need to get the valid mac entries
455 * again as it may become zero in another thread and if is 0 then
456 * we need to reset "mac_cnt" to zero so that at zeroth index we
457 * add new entry
458 */
459 valid_mac_entries = tdls_vdev_obj->valid_mac_entries;
460 if (!valid_mac_entries)
461 mac_cnt = 0;
462
463 /* If we have more than 8 peers within 30 mins. we will
464 * stop tracking till the old entries are removed
465 */
466 if (mac_cnt < WLAN_TDLS_CT_TABLE_SIZE) {
467 qdf_mem_copy(mac_table[mac_cnt].mac_address.bytes,
468 mac_addr, QDF_MAC_ADDR_SIZE);
469 mac_table[mac_cnt].tx_packet_cnt = 1;
470 tdls_vdev_obj->valid_mac_entries++;
471 }
472
473 qdf_spin_unlock_bh(&tdls_soc_obj->tdls_ct_spinlock);
474 return;
475 }
476
477 void
tdls_implicit_send_discovery_request(struct tdls_vdev_priv_obj * tdls_vdev_obj)478 tdls_implicit_send_discovery_request(struct tdls_vdev_priv_obj *tdls_vdev_obj)
479 {
480 struct tdls_peer *curr_peer;
481 struct tdls_peer *temp_peer;
482 struct tdls_soc_priv_obj *tdls_psoc;
483 struct tdls_osif_indication tdls_ind;
484
485 if (!tdls_vdev_obj) {
486 tdls_notice("tdls_vdev_obj is NULL");
487 return;
488 }
489
490 tdls_psoc = wlan_vdev_get_tdls_soc_obj(tdls_vdev_obj->vdev);
491
492 if (!tdls_psoc) {
493 tdls_notice("tdls_psoc_obj is NULL");
494 return;
495 }
496
497 curr_peer = tdls_vdev_obj->curr_candidate;
498
499 if (!curr_peer) {
500 tdls_err("curr_peer is NULL");
501 return;
502 }
503
504 /* This function is called in mutex_lock */
505 temp_peer = tdls_is_progress(tdls_vdev_obj, NULL, 0);
506 if (temp_peer) {
507 tdls_notice(QDF_MAC_ADDR_FMT " ongoing. pre_setup ignored",
508 QDF_MAC_ADDR_REF(temp_peer->peer_mac.bytes));
509 goto done;
510 }
511
512 if (TDLS_CAP_UNKNOWN != curr_peer->tdls_support)
513 tdls_set_peer_link_status(curr_peer,
514 TDLS_LINK_DISCOVERING,
515 TDLS_LINK_SUCCESS);
516
517 qdf_mem_copy(tdls_ind.peer_mac, curr_peer->peer_mac.bytes,
518 QDF_MAC_ADDR_SIZE);
519
520 tdls_ind.vdev = tdls_vdev_obj->vdev;
521
522 tdls_debug("Implicit TDLS, Send Discovery request event");
523
524 tdls_psoc->tdls_event_cb(tdls_psoc->tdls_evt_cb_data,
525 TDLS_EVENT_DISCOVERY_REQ, &tdls_ind);
526
527 if (!wlan_vdev_mlme_is_mlo_vdev(tdls_vdev_obj->vdev)) {
528 tdls_vdev_obj->discovery_sent_cnt++;
529 tdls_timer_restart(tdls_vdev_obj->vdev,
530 &tdls_vdev_obj->peer_discovery_timer,
531 tdls_vdev_obj->threshold_config.tx_period_t -
532 TDLS_DISCOVERY_TIMEOUT_ERE_UPDATE);
533
534 tdls_debug("discovery count %u timeout %u msec",
535 tdls_vdev_obj->discovery_sent_cnt,
536 tdls_vdev_obj->threshold_config.tx_period_t -
537 TDLS_DISCOVERY_TIMEOUT_ERE_UPDATE);
538 }
539 done:
540 tdls_vdev_obj->curr_candidate = NULL;
541 tdls_vdev_obj->magic = 0;
542 return;
543 }
544
tdls_recv_discovery_resp(struct tdls_vdev_priv_obj * tdls_vdev,const uint8_t * mac)545 int tdls_recv_discovery_resp(struct tdls_vdev_priv_obj *tdls_vdev,
546 const uint8_t *mac)
547 {
548 struct tdls_peer *curr_peer;
549 struct tdls_soc_priv_obj *tdls_soc;
550 struct tdls_osif_indication indication;
551 struct tdls_config_params *tdls_cfg;
552 int status = 0;
553
554 if (!tdls_vdev)
555 return -EINVAL;
556
557 tdls_soc = wlan_vdev_get_tdls_soc_obj(tdls_vdev->vdev);
558 if (!tdls_soc) {
559 tdls_err("tdls soc is NULL");
560 return -EINVAL;
561 }
562
563 curr_peer = tdls_get_peer(tdls_vdev, mac);
564 if (!curr_peer) {
565 tdls_err("curr_peer is NULL");
566 return -EINVAL;
567 }
568
569 if (!wlan_vdev_mlme_is_mlo_vdev(tdls_vdev->vdev)) {
570 if (tdls_vdev->discovery_sent_cnt)
571 tdls_vdev->discovery_sent_cnt--;
572
573 if (tdls_vdev->discovery_sent_cnt == 0)
574 qdf_mc_timer_stop(&tdls_vdev->peer_discovery_timer);
575 }
576
577 tdls_debug("[TDLS] vdev:%d action:%d (%s) sent_count:%u from peer " QDF_MAC_ADDR_FMT
578 " link_status %d", wlan_vdev_get_id(tdls_vdev->vdev),
579 TDLS_DISCOVERY_RESPONSE,
580 "TDLS_DISCOVERY_RESPONSE",
581 tdls_vdev->discovery_sent_cnt,
582 QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes),
583 curr_peer->link_status);
584
585 /*
586 * Since peer link status bases on vdev and stream goes through
587 * vdev0 (assoc link) at start, rx/tx pkt count on vdev0, but
588 * it choices vdev1 as tdls link, the peer status does not change on
589 * vdev1 though it has been changed for vdev0 per the rx/tx pkt count.
590 */
591 if (wlan_vdev_mlme_is_mlo_vdev(tdls_vdev->vdev) &&
592 curr_peer->link_status == TDLS_LINK_IDLE)
593 tdls_set_peer_link_status(curr_peer, TDLS_LINK_DISCOVERING,
594 TDLS_LINK_SUCCESS);
595
596 tdls_cfg = &tdls_vdev->threshold_config;
597 if (TDLS_LINK_DISCOVERING == curr_peer->link_status) {
598 /* Since we are here, it means Throughput threshold is
599 * already met. Make sure RSSI threshold is also met
600 * before setting up TDLS link.
601 */
602 if ((int32_t) curr_peer->rssi >
603 (int32_t) tdls_cfg->rssi_trigger_threshold) {
604 tdls_set_peer_link_status(curr_peer,
605 TDLS_LINK_DISCOVERED,
606 TDLS_LINK_SUCCESS);
607 tdls_debug("Rssi Threshold met: " QDF_MAC_ADDR_FMT
608 " rssi = %d threshold= %d",
609 QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes),
610 curr_peer->rssi,
611 tdls_cfg->rssi_trigger_threshold);
612
613 qdf_mem_copy(indication.peer_mac, mac,
614 QDF_MAC_ADDR_SIZE);
615
616 indication.vdev = tdls_vdev->vdev;
617
618 tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
619 TDLS_EVENT_SETUP_REQ,
620 &indication);
621 } else {
622 tdls_debug("Rssi Threshold not met: " QDF_MAC_ADDR_FMT
623 " rssi = %d threshold = %d ",
624 QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes),
625 curr_peer->rssi,
626 tdls_cfg->rssi_trigger_threshold);
627
628 tdls_set_peer_link_status(curr_peer,
629 TDLS_LINK_IDLE,
630 TDLS_LINK_UNSPECIFIED);
631
632 /* if RSSI threshold is not met then allow
633 * further discovery attempts by decrementing
634 * count for the last attempt
635 */
636 if (curr_peer->discovery_attempt)
637 curr_peer->discovery_attempt--;
638 }
639 }
640
641 curr_peer->tdls_support = TDLS_CAP_SUPPORTED;
642
643 return status;
644 }
645
tdls_indicate_teardown(struct tdls_vdev_priv_obj * tdls_vdev,struct tdls_peer * curr_peer,uint16_t reason)646 void tdls_indicate_teardown(struct tdls_vdev_priv_obj *tdls_vdev,
647 struct tdls_peer *curr_peer,
648 uint16_t reason)
649 {
650 struct tdls_soc_priv_obj *tdls_soc;
651 struct tdls_osif_indication indication;
652
653 if (!tdls_vdev || !curr_peer) {
654 tdls_err("tdls_vdev: %pK, curr_peer: %pK",
655 tdls_vdev, curr_peer);
656 return;
657 }
658
659 tdls_soc = wlan_vdev_get_tdls_soc_obj(tdls_vdev->vdev);
660 if (!tdls_soc) {
661 tdls_err("tdls_soc: %pK", tdls_soc);
662 return;
663 }
664
665 if (curr_peer->link_status != TDLS_LINK_CONNECTED) {
666 tdls_err("link state %d peer:" QDF_MAC_ADDR_FMT,
667 curr_peer->link_status,
668 QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes));
669 return;
670 }
671
672 tdls_set_peer_link_status(curr_peer, TDLS_LINK_TEARING,
673 TDLS_LINK_UNSPECIFIED);
674 tdls_notice("vdev:%d Teardown reason %d peer:" QDF_MAC_ADDR_FMT,
675 wlan_vdev_get_id(tdls_vdev->vdev), reason,
676 QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes));
677
678 if (tdls_soc->tdls_dp_vdev_update)
679 tdls_soc->tdls_dp_vdev_update(
680 &tdls_soc->soc,
681 wlan_vdev_get_id(tdls_vdev->vdev),
682 tdls_soc->tdls_update_dp_vdev_flags,
683 false);
684
685 indication.reason = reason;
686 indication.vdev = tdls_vdev->vdev;
687 qdf_mem_copy(indication.peer_mac, curr_peer->peer_mac.bytes,
688 QDF_MAC_ADDR_SIZE);
689
690 if (tdls_soc->tdls_event_cb)
691 tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
692 TDLS_EVENT_TEARDOWN_REQ, &indication);
693 }
694
695 /**
696 * tdls_get_conn_info() - get the tdls connection information.
697 * @tdls_soc: tdls soc object
698 * @peer_mac: peer MAC address
699 *
700 * Function to check tdls sta index
701 *
702 * Return: tdls connection information
703 */
704 static struct tdls_conn_info *
tdls_get_conn_info(struct tdls_soc_priv_obj * tdls_soc,struct qdf_mac_addr * peer_mac)705 tdls_get_conn_info(struct tdls_soc_priv_obj *tdls_soc,
706 struct qdf_mac_addr *peer_mac)
707 {
708 uint8_t sta_idx;
709 /* check if there is available index for this new TDLS STA */
710 for (sta_idx = 0; sta_idx < WLAN_TDLS_STA_MAX_NUM; sta_idx++) {
711 if (!qdf_mem_cmp(
712 tdls_soc->tdls_conn_info[sta_idx].peer_mac.bytes,
713 peer_mac->bytes, QDF_MAC_ADDR_SIZE)) {
714 tdls_debug("tdls peer exists idx %d " QDF_MAC_ADDR_FMT,
715 sta_idx,
716 QDF_MAC_ADDR_REF(peer_mac->bytes));
717 tdls_soc->tdls_conn_info[sta_idx].index = sta_idx;
718 return &tdls_soc->tdls_conn_info[sta_idx];
719 }
720 }
721
722 tdls_err("tdls peer does not exists");
723 return NULL;
724 }
725
726 static void
tdls_ct_process_idle_handler(struct wlan_objmgr_vdev * vdev,struct tdls_conn_info * tdls_info)727 tdls_ct_process_idle_handler(struct wlan_objmgr_vdev *vdev,
728 struct tdls_conn_info *tdls_info)
729 {
730 struct tdls_peer *curr_peer;
731 struct tdls_vdev_priv_obj *tdls_vdev_obj;
732 struct tdls_soc_priv_obj *tdls_soc_obj;
733
734 if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj,
735 &tdls_soc_obj))
736 return;
737
738 if (!tdls_info->valid_entry) {
739 tdls_err("peer doesn't exists");
740 return;
741 }
742
743 curr_peer = tdls_find_peer(tdls_vdev_obj,
744 (u8 *) &tdls_info->peer_mac.bytes[0]);
745
746 if (!curr_peer) {
747 tdls_err("Invalid tdls idle timer expired");
748 return;
749 }
750
751 tdls_debug(QDF_MAC_ADDR_FMT
752 " tx_pkt: %d, rx_pkt: %d, idle_packet_n: %d",
753 QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes),
754 curr_peer->tx_pkt,
755 curr_peer->rx_pkt,
756 tdls_vdev_obj->threshold_config.idle_packet_n);
757
758 /* Check tx/rx statistics on this tdls link for recent activities and
759 * then decide whether to tear down the link or keep it.
760 */
761 if ((curr_peer->tx_pkt >=
762 tdls_vdev_obj->threshold_config.idle_packet_n) ||
763 (curr_peer->rx_pkt >=
764 tdls_vdev_obj->threshold_config.idle_packet_n)) {
765 /* this tdls link got back to normal, so keep it */
766 tdls_debug("tdls link to " QDF_MAC_ADDR_FMT
767 " back to normal, will stay",
768 QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes));
769 } else {
770 /* this tdls link needs to get torn down */
771 tdls_notice("trigger tdls link to "QDF_MAC_ADDR_FMT" down",
772 QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes));
773 tdls_indicate_teardown(tdls_vdev_obj,
774 curr_peer,
775 TDLS_TEARDOWN_PEER_UNSPEC_REASON);
776 }
777
778 return;
779 }
780
tdls_ct_idle_handler(void * user_data)781 void tdls_ct_idle_handler(void *user_data)
782 {
783 struct wlan_objmgr_vdev *vdev;
784 struct tdls_conn_info *tdls_info;
785 struct tdls_soc_priv_obj *tdls_soc_obj;
786 uint32_t idx;
787
788 tdls_info = (struct tdls_conn_info *)user_data;
789 if (!tdls_info)
790 return;
791
792 idx = tdls_info->index;
793 if (idx == INVALID_TDLS_PEER_INDEX || idx >= WLAN_TDLS_STA_MAX_NUM) {
794 tdls_debug("invalid peer index %d" QDF_MAC_ADDR_FMT, idx,
795 QDF_MAC_ADDR_REF(tdls_info->peer_mac.bytes));
796 return;
797 }
798
799 tdls_soc_obj = qdf_container_of(tdls_info, struct tdls_soc_priv_obj,
800 tdls_conn_info[idx]);
801
802 vdev = tdls_get_vdev(tdls_soc_obj->soc, WLAN_TDLS_NB_ID);
803 if (!vdev) {
804 tdls_err("Unable to fetch the vdev");
805 return;
806 }
807
808 tdls_ct_process_idle_handler(vdev, tdls_info);
809 wlan_objmgr_vdev_release_ref(vdev,
810 WLAN_TDLS_NB_ID);
811 }
812
813 /**
814 * tdls_ct_process_idle_and_discovery() - process the traffic data
815 * @curr_peer: tdls peer needs to be examined
816 * @tdls_vdev_obj: tdls vdev object
817 * @tdls_soc_obj: tdls soc object
818 *
819 * Function to check the peer traffic data in idle link and tdls
820 * discovering link
821 *
822 * Return: None
823 */
824 static void
tdls_ct_process_idle_and_discovery(struct tdls_peer * curr_peer,struct tdls_vdev_priv_obj * tdls_vdev_obj,struct tdls_soc_priv_obj * tdls_soc_obj)825 tdls_ct_process_idle_and_discovery(struct tdls_peer *curr_peer,
826 struct tdls_vdev_priv_obj *tdls_vdev_obj,
827 struct tdls_soc_priv_obj *tdls_soc_obj)
828 {
829 uint16_t valid_peers;
830
831 valid_peers = tdls_soc_obj->connected_peer_count;
832
833 if ((curr_peer->tx_pkt + curr_peer->rx_pkt) >=
834 tdls_vdev_obj->threshold_config.tx_packet_n) {
835 if (WLAN_TDLS_STA_MAX_NUM > valid_peers) {
836 tdls_notice("Tput trigger TDLS pre-setup");
837 tdls_vdev_obj->curr_candidate = curr_peer;
838 tdls_implicit_send_discovery_request(tdls_vdev_obj);
839 } else {
840 tdls_notice("Maximum peers connected already! %d",
841 valid_peers);
842 }
843 }
844 }
845
846 /**
847 * tdls_ct_process_connected_link() - process the traffic
848 * @curr_peer: tdls peer needs to be examined
849 * @tdls_vdev: tdls vdev
850 * @tdls_soc: tdls soc context
851 *
852 * Function to check the peer traffic data in active STA
853 * session
854 *
855 * Return: None
856 */
tdls_ct_process_connected_link(struct tdls_peer * curr_peer,struct tdls_vdev_priv_obj * tdls_vdev,struct tdls_soc_priv_obj * tdls_soc)857 static void tdls_ct_process_connected_link(
858 struct tdls_peer *curr_peer,
859 struct tdls_vdev_priv_obj *tdls_vdev,
860 struct tdls_soc_priv_obj *tdls_soc)
861 {
862 /* Don't trigger low rssi tear down here since FW will do it */
863 /* Only teardown based on non zero idle packet threshold, to address
864 * a use case where this threshold does not get consider for TEAR DOWN
865 */
866 if ((0 != tdls_vdev->threshold_config.idle_packet_n) &&
867 ((curr_peer->tx_pkt <
868 tdls_vdev->threshold_config.idle_packet_n) &&
869 (curr_peer->rx_pkt <
870 tdls_vdev->threshold_config.idle_packet_n))) {
871 if (!curr_peer->is_peer_idle_timer_initialised) {
872 struct tdls_conn_info *tdls_info;
873 tdls_info = tdls_get_conn_info(tdls_soc,
874 &curr_peer->peer_mac);
875 qdf_mc_timer_init(&curr_peer->peer_idle_timer,
876 QDF_TIMER_TYPE_SW,
877 tdls_ct_idle_handler,
878 (void *)tdls_info);
879 curr_peer->is_peer_idle_timer_initialised = true;
880 }
881 if (QDF_TIMER_STATE_RUNNING !=
882 curr_peer->peer_idle_timer.state) {
883 tdls_warn("Tx/Rx Idle timer start: "
884 QDF_MAC_ADDR_FMT "!",
885 QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes));
886 tdls_timer_restart(tdls_vdev->vdev,
887 &curr_peer->peer_idle_timer,
888 tdls_vdev->threshold_config.idle_timeout_t);
889 }
890 } else if (QDF_TIMER_STATE_RUNNING ==
891 curr_peer->peer_idle_timer.state) {
892 tdls_warn("Tx/Rx Idle timer stop: " QDF_MAC_ADDR_FMT "!",
893 QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes));
894 qdf_mc_timer_stop(&curr_peer->peer_idle_timer);
895 }
896 }
897
898 /**
899 * tdls_ct_process_cap_supported() - process TDLS supported peer.
900 * @curr_peer: tdls peer needs to be examined
901 * @tdls_vdev: tdls vdev context
902 * @tdls_soc_obj: tdls soc context
903 *
904 * Function to check the peer traffic data for tdls supported peer
905 *
906 * Return: None
907 */
908 static void
tdls_ct_process_cap_supported(struct tdls_peer * curr_peer,struct tdls_vdev_priv_obj * tdls_vdev,struct tdls_soc_priv_obj * tdls_soc_obj)909 tdls_ct_process_cap_supported(struct tdls_peer *curr_peer,
910 struct tdls_vdev_priv_obj *tdls_vdev,
911 struct tdls_soc_priv_obj *tdls_soc_obj)
912 {
913 if (curr_peer->rx_pkt || curr_peer->tx_pkt)
914 tdls_debug(QDF_MAC_ADDR_FMT "link_status %d tdls_support %d tx %d rx %d rssi %d vdev %d",
915 QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes),
916 curr_peer->link_status, curr_peer->tdls_support,
917 curr_peer->tx_pkt, curr_peer->rx_pkt,
918 curr_peer->rssi, wlan_vdev_get_id(tdls_vdev->vdev));
919
920 switch (curr_peer->link_status) {
921 case TDLS_LINK_IDLE:
922 case TDLS_LINK_DISCOVERING:
923 if (!curr_peer->is_forced_peer &&
924 TDLS_IS_EXTERNAL_CONTROL_ENABLED(
925 tdls_soc_obj->tdls_configs.tdls_feature_flags))
926 break;
927
928 tdls_ct_process_idle_and_discovery(curr_peer, tdls_vdev,
929 tdls_soc_obj);
930 break;
931 case TDLS_LINK_CONNECTED:
932 tdls_ct_process_connected_link(curr_peer, tdls_vdev,
933 tdls_soc_obj);
934 break;
935 default:
936 break;
937 }
938 }
939
940 /**
941 * tdls_ct_process_cap_unknown() - process unknown peer
942 * @curr_peer: tdls peer needs to be examined
943 * @tdls_vdev: tdls vdev object
944 * @tdls_soc: tdls soc object
945 *
946 * Function check the peer traffic data , when tdls capability is unknown
947 *
948 * Return: None
949 */
tdls_ct_process_cap_unknown(struct tdls_peer * curr_peer,struct tdls_vdev_priv_obj * tdls_vdev,struct tdls_soc_priv_obj * tdls_soc)950 static void tdls_ct_process_cap_unknown(struct tdls_peer *curr_peer,
951 struct tdls_vdev_priv_obj *tdls_vdev,
952 struct tdls_soc_priv_obj *tdls_soc)
953 {
954 if (!curr_peer->is_forced_peer &&
955 TDLS_IS_EXTERNAL_CONTROL_ENABLED(
956 tdls_soc->tdls_configs.tdls_feature_flags))
957 return;
958
959 if (curr_peer->rx_pkt || curr_peer->tx_pkt)
960 tdls_debug(QDF_MAC_ADDR_FMT " link_status %d tdls_support %d tx %d rx %d vdev %d",
961 QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes),
962 curr_peer->link_status, curr_peer->tdls_support,
963 curr_peer->tx_pkt, curr_peer->rx_pkt,
964 wlan_vdev_get_id(tdls_vdev->vdev));
965
966 if (TDLS_IS_LINK_CONNECTED(curr_peer))
967 return;
968
969 if ((curr_peer->tx_pkt + curr_peer->rx_pkt) >=
970 tdls_vdev->threshold_config.tx_packet_n) {
971 /*
972 * Ignore discovery attempt if External Control is enabled, that
973 * is, peer is forced. In that case, continue discovery attempt
974 * regardless attempt count
975 */
976 tdls_debug("TDLS UNKNOWN pre discover ");
977 if (curr_peer->is_forced_peer ||
978 curr_peer->discovery_attempt <
979 tdls_vdev->threshold_config.discovery_tries_n) {
980 tdls_debug("TDLS UNKNOWN discover num_attempts:%d num_left:%d forced_peer:%d",
981 curr_peer->discovery_attempt,
982 tdls_vdev->threshold_config.discovery_tries_n,
983 curr_peer->is_forced_peer);
984 tdls_vdev->curr_candidate = curr_peer;
985 tdls_implicit_send_discovery_request(tdls_vdev);
986
987 return;
988 }
989
990 if (curr_peer->link_status != TDLS_LINK_CONNECTING) {
991 curr_peer->tdls_support = TDLS_CAP_NOT_SUPPORTED;
992 tdls_set_peer_link_status(curr_peer, TDLS_LINK_IDLE,
993 TDLS_LINK_NOT_SUPPORTED);
994 }
995 }
996 }
997
998 /**
999 * tdls_ct_process_peers() - process the peer
1000 * @curr_peer: tdls peer needs to be examined
1001 * @tdls_vdev_obj: tdls vdev object
1002 * @tdls_soc_obj: tdls soc object
1003 *
1004 * This function check the peer capability and process the metadata from
1005 * the peer
1006 *
1007 * Return: None
1008 */
tdls_ct_process_peers(struct tdls_peer * curr_peer,struct tdls_vdev_priv_obj * tdls_vdev_obj,struct tdls_soc_priv_obj * tdls_soc_obj)1009 static void tdls_ct_process_peers(struct tdls_peer *curr_peer,
1010 struct tdls_vdev_priv_obj *tdls_vdev_obj,
1011 struct tdls_soc_priv_obj *tdls_soc_obj)
1012 {
1013 switch (curr_peer->tdls_support) {
1014 case TDLS_CAP_SUPPORTED:
1015 tdls_ct_process_cap_supported(curr_peer, tdls_vdev_obj,
1016 tdls_soc_obj);
1017 break;
1018
1019 case TDLS_CAP_UNKNOWN:
1020 tdls_ct_process_cap_unknown(curr_peer, tdls_vdev_obj,
1021 tdls_soc_obj);
1022 break;
1023 default:
1024 break;
1025 }
1026
1027 }
1028
tdls_ct_process_handler(struct wlan_objmgr_vdev * vdev)1029 static void tdls_ct_process_handler(struct wlan_objmgr_vdev *vdev)
1030 {
1031 int i;
1032 qdf_list_t *head;
1033 qdf_list_node_t *list_node;
1034 struct tdls_peer *curr_peer;
1035 QDF_STATUS status;
1036 struct tdls_vdev_priv_obj *tdls_vdev_obj;
1037 struct tdls_soc_priv_obj *tdls_soc_obj;
1038
1039 status = tdls_get_vdev_objects(vdev, &tdls_vdev_obj, &tdls_soc_obj);
1040 if (QDF_IS_STATUS_ERROR(status))
1041 return;
1042
1043 /* If any concurrency is detected */
1044 if (!tdls_soc_obj->enable_tdls_connection_tracker) {
1045 tdls_notice("Connection tracker is disabled");
1046 return;
1047 }
1048
1049 /* Update tx rx traffic sample in tdls data structures */
1050 tdls_ct_sampling_tx_rx(tdls_vdev_obj, tdls_soc_obj);
1051
1052 for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
1053 head = &tdls_vdev_obj->peer_list[i];
1054 status = qdf_list_peek_front(head, &list_node);
1055 while (QDF_IS_STATUS_SUCCESS(status)) {
1056 curr_peer = qdf_container_of(list_node,
1057 struct tdls_peer, node);
1058 tdls_ct_process_peers(curr_peer, tdls_vdev_obj,
1059 tdls_soc_obj);
1060 curr_peer->tx_pkt = 0;
1061 curr_peer->rx_pkt = 0;
1062 status = qdf_list_peek_next(head,
1063 list_node, &list_node);
1064 }
1065 }
1066
1067 tdls_timer_restart(tdls_vdev_obj->vdev,
1068 &tdls_vdev_obj->peer_update_timer,
1069 tdls_vdev_obj->threshold_config.tx_period_t);
1070
1071 }
1072
tdls_ct_handler(void * user_data)1073 void tdls_ct_handler(void *user_data)
1074 {
1075 struct wlan_objmgr_vdev *vdev;
1076 struct wlan_objmgr_vdev *link_vdev;
1077 QDF_STATUS status;
1078
1079 if (!user_data)
1080 return;
1081
1082 vdev = (struct wlan_objmgr_vdev *)user_data;
1083 if (!vdev)
1084 return;
1085
1086 link_vdev = tdls_mlo_get_tdls_link_vdev(vdev);
1087 if (link_vdev) {
1088 status = wlan_objmgr_vdev_try_get_ref(link_vdev,
1089 WLAN_TDLS_NB_ID);
1090 if (QDF_IS_STATUS_SUCCESS(status)) {
1091 tdls_ct_process_handler(link_vdev);
1092 wlan_objmgr_vdev_release_ref(link_vdev,
1093 WLAN_TDLS_NB_ID);
1094 }
1095 } else {
1096 tdls_ct_process_handler(vdev);
1097 }
1098 }
1099
tdls_set_tdls_offchannel(struct tdls_soc_priv_obj * tdls_soc,int offchannel)1100 int tdls_set_tdls_offchannel(struct tdls_soc_priv_obj *tdls_soc,
1101 int offchannel)
1102 {
1103 uint32_t tdls_feature_flags;
1104
1105 tdls_feature_flags = tdls_soc->tdls_configs.tdls_feature_flags;
1106
1107 if (TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) &&
1108 (TDLS_SUPPORT_EXP_TRIG_ONLY == tdls_soc->tdls_current_mode ||
1109 TDLS_SUPPORT_IMP_MODE == tdls_soc->tdls_current_mode ||
1110 TDLS_SUPPORT_EXT_CONTROL == tdls_soc->tdls_current_mode)) {
1111 if (offchannel < TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN ||
1112 offchannel > TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX) {
1113 tdls_err("Invalid tdls off channel %u", offchannel);
1114 return -EINVAL;
1115 }
1116 } else {
1117 tdls_err("Either TDLS or TDLS Off-channel is not enabled");
1118 return -ENOTSUPP;
1119 }
1120 tdls_notice("change tdls off channel from %d to %d",
1121 tdls_soc->tdls_off_channel, offchannel);
1122 tdls_soc->tdls_off_channel = offchannel;
1123 return 0;
1124 }
1125
tdls_set_tdls_secoffchanneloffset(struct tdls_soc_priv_obj * tdls_soc,int offchanoffset)1126 int tdls_set_tdls_secoffchanneloffset(struct tdls_soc_priv_obj *tdls_soc,
1127 int offchanoffset)
1128 {
1129 uint32_t tdls_feature_flags;
1130
1131 tdls_feature_flags = tdls_soc->tdls_configs.tdls_feature_flags;
1132
1133 if (!TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) ||
1134 TDLS_SUPPORT_SUSPENDED >= tdls_soc->tdls_current_mode) {
1135 tdls_err("Either TDLS or TDLS Off-channel is not enabled");
1136 return -ENOTSUPP;
1137 }
1138
1139 tdls_soc->tdls_channel_offset = BW_INVALID;
1140
1141 switch (offchanoffset) {
1142 case TDLS_SEC_OFFCHAN_OFFSET_0:
1143 tdls_soc->tdls_channel_offset = BW20;
1144 break;
1145 case TDLS_SEC_OFFCHAN_OFFSET_40PLUS:
1146 tdls_soc->tdls_channel_offset = BW40_HIGH_PRIMARY;
1147 break;
1148 case TDLS_SEC_OFFCHAN_OFFSET_40MINUS:
1149 tdls_soc->tdls_channel_offset = BW40_LOW_PRIMARY;
1150 break;
1151 case TDLS_SEC_OFFCHAN_OFFSET_80:
1152 tdls_soc->tdls_channel_offset = BW80;
1153 break;
1154 case TDLS_SEC_OFFCHAN_OFFSET_160:
1155 tdls_soc->tdls_channel_offset = BWALL;
1156 break;
1157 default:
1158 tdls_err("Invalid tdls secondary off channel offset %d",
1159 offchanoffset);
1160 return -EINVAL;
1161 } /* end switch */
1162
1163 tdls_notice("change tdls secondary off channel offset to 0x%x",
1164 tdls_soc->tdls_channel_offset);
1165 return 0;
1166 }
1167
1168 static inline void
tdls_update_opclass(struct wlan_objmgr_psoc * psoc,struct tdls_channel_switch_params * params)1169 tdls_update_opclass(struct wlan_objmgr_psoc *psoc,
1170 struct tdls_channel_switch_params *params)
1171 {
1172 params->oper_class = tdls_find_opclass(psoc, params->tdls_off_ch,
1173 params->tdls_off_ch_bw_offset);
1174 if (params->oper_class)
1175 return;
1176
1177 if (params->tdls_off_ch_bw_offset == BW40_HIGH_PRIMARY)
1178 params->oper_class = tdls_find_opclass(psoc,
1179 params->tdls_off_ch,
1180 BW40_LOW_PRIMARY);
1181 else if (params->tdls_off_ch_bw_offset == BW40_LOW_PRIMARY)
1182 params->oper_class = tdls_find_opclass(psoc,
1183 params->tdls_off_ch,
1184 BW40_HIGH_PRIMARY);
1185 }
1186
1187 #ifdef WLAN_FEATURE_TDLS_CONCURRENCIES
1188 static inline QDF_STATUS
tdls_update_peer_off_channel_list(struct wlan_objmgr_pdev * pdev,struct tdls_soc_priv_obj * tdls_soc,struct wlan_objmgr_vdev * vdev,struct tdls_peer * peer,struct tdls_channel_switch_params * params)1189 tdls_update_peer_off_channel_list(struct wlan_objmgr_pdev *pdev,
1190 struct tdls_soc_priv_obj *tdls_soc,
1191 struct wlan_objmgr_vdev *vdev,
1192 struct tdls_peer *peer,
1193 struct tdls_channel_switch_params *params)
1194 {
1195 struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
1196 struct tdls_peer_update_state *peer_info;
1197 struct tdls_ch_params *off_channels = params->allowed_off_channels;
1198 uint16_t i;
1199 qdf_freq_t freq, peer_freq;
1200
1201 if (!wlan_psoc_nif_fw_ext2_cap_get(psoc,
1202 WLAN_TDLS_CONCURRENCIES_SUPPORT)) {
1203 tdls_debug("TDLS Concurrencies FW cap is not supported");
1204 return QDF_STATUS_SUCCESS;
1205 }
1206
1207 if (!policy_mgr_get_allowed_tdls_offchannel_freq(psoc, vdev, &freq)) {
1208 tdls_debug("off channel not allowed for current concurrency");
1209 return QDF_STATUS_E_NOSUPPORT;
1210 }
1211
1212 /*
1213 * Overwrite the preferred off channel freq in case of concurrency
1214 */
1215 if (freq) {
1216 params->tdls_off_ch = wlan_reg_freq_to_chan(pdev, freq);
1217 params->tdls_off_chan_freq = freq;
1218
1219 /*
1220 * tdls_off_ch_bw_offset is already filled in the caller
1221 */
1222 if (tdls_soc->tdls_off_channel &&
1223 tdls_soc->tdls_channel_offset != BW_INVALID) {
1224 tdls_update_opclass(psoc, params);
1225 } else if (peer->off_channel_capable &&
1226 peer->pref_off_chan_freq) {
1227 params->oper_class =
1228 tdls_get_opclass_from_bandwidth(
1229 vdev, params->tdls_off_chan_freq,
1230 peer->pref_off_chan_width,
1231 ¶ms->tdls_off_ch_bw_offset);
1232 }
1233 }
1234
1235 peer_info = qdf_mem_malloc(sizeof(*peer_info));
1236 if (!peer_info)
1237 return QDF_STATUS_E_NOMEM;
1238
1239 tdls_extract_peer_state_param(peer_info, peer);
1240 params->num_off_channels = 0;
1241
1242 /*
1243 * If TDLS concurrency is supported and freq == 0,
1244 * then allow all the 5GHz and 6GHz peer supported frequencies for
1245 * off-channel operation. If particular frequency is provided based on
1246 * concurrency combination then only allow that channel for off-channel.
1247 */
1248 for (i = 0; i < peer_info->peer_cap.peer_chanlen; i++) {
1249 peer_freq = peer_info->peer_cap.peer_chan[i].ch_freq;
1250 if ((!freq || freq == peer_freq) &&
1251 (!wlan_reg_is_24ghz_ch_freq(peer_freq) ||
1252 (wlan_reg_is_6ghz_chan_freq(peer_freq) &&
1253 tdls_is_6g_freq_allowed(vdev, peer_freq)))) {
1254 off_channels[params->num_off_channels] =
1255 peer_info->peer_cap.peer_chan[i];
1256 tdls_debug("allowd_chan:%d idx:%d",
1257 off_channels[params->num_off_channels].ch_freq,
1258 params->num_off_channels);
1259 params->num_off_channels++;
1260 }
1261 }
1262 tdls_debug("Num allowed off channels:%d freq:%u",
1263 params->num_off_channels, freq);
1264 qdf_mem_free(peer_info);
1265
1266 return QDF_STATUS_SUCCESS;
1267 }
1268 #else
1269 static inline QDF_STATUS
tdls_update_peer_off_channel_list(struct wlan_objmgr_pdev * pdev,struct tdls_soc_priv_obj * tdls_soc,struct wlan_objmgr_vdev * vdev,struct tdls_peer * peer,struct tdls_channel_switch_params * params)1270 tdls_update_peer_off_channel_list(struct wlan_objmgr_pdev *pdev,
1271 struct tdls_soc_priv_obj *tdls_soc,
1272 struct wlan_objmgr_vdev *vdev,
1273 struct tdls_peer *peer,
1274 struct tdls_channel_switch_params *params)
1275 {
1276 return QDF_STATUS_SUCCESS;
1277 }
1278 #endif
1279
tdls_set_tdls_offchannelmode(struct wlan_objmgr_vdev * vdev,int offchanmode)1280 int tdls_set_tdls_offchannelmode(struct wlan_objmgr_vdev *vdev,
1281 int offchanmode)
1282 {
1283 struct tdls_peer *conn_peer = NULL;
1284 struct tdls_channel_switch_params *chan_switch_params;
1285 QDF_STATUS status = QDF_STATUS_E_FAILURE;
1286 int ret_value = 0;
1287 struct tdls_vdev_priv_obj *tdls_vdev;
1288 struct tdls_soc_priv_obj *tdls_soc;
1289 uint32_t tdls_feature_flags;
1290 struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev);
1291
1292 status = tdls_get_vdev_objects(vdev, &tdls_vdev, &tdls_soc);
1293
1294 if (status != QDF_STATUS_SUCCESS)
1295 return -EINVAL;
1296
1297
1298 if (offchanmode < ENABLE_CHANSWITCH ||
1299 offchanmode > DISABLE_ACTIVE_CHANSWITCH) {
1300 tdls_err("Invalid tdls off channel mode %d", offchanmode);
1301 return -EINVAL;
1302 }
1303
1304 if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) {
1305 tdls_err("tdls off channel req in not associated state %d",
1306 offchanmode);
1307 return -EPERM;
1308 }
1309
1310 tdls_feature_flags = tdls_soc->tdls_configs.tdls_feature_flags;
1311 if (!TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) ||
1312 TDLS_SUPPORT_SUSPENDED >= tdls_soc->tdls_current_mode) {
1313 tdls_err("Either TDLS or TDLS Off-channel is not enabled");
1314 return -ENOTSUPP;
1315 }
1316
1317 conn_peer = tdls_find_first_connected_peer(tdls_vdev);
1318 if (!conn_peer) {
1319 tdls_debug("No TDLS Connected Peer");
1320 return -EPERM;
1321 }
1322
1323 tdls_notice("TDLS Channel Switch in off_chan_mode=%d tdls_off_channel %d offchanoffset %d",
1324 offchanmode, tdls_soc->tdls_off_channel,
1325 tdls_soc->tdls_channel_offset);
1326
1327 chan_switch_params = qdf_mem_malloc(sizeof(*chan_switch_params));
1328 if (!chan_switch_params)
1329 return -ENOMEM;
1330
1331 switch (offchanmode) {
1332 case ENABLE_CHANSWITCH:
1333 if (tdls_soc->tdls_off_channel &&
1334 tdls_soc->tdls_channel_offset != BW_INVALID) {
1335 chan_switch_params->tdls_off_ch =
1336 tdls_soc->tdls_off_channel;
1337 chan_switch_params->tdls_off_ch_bw_offset =
1338 tdls_soc->tdls_channel_offset;
1339 tdls_update_opclass(wlan_pdev_get_psoc(pdev),
1340 chan_switch_params);
1341 } else if (conn_peer->off_channel_capable &&
1342 conn_peer->pref_off_chan_freq) {
1343 chan_switch_params->tdls_off_ch =
1344 wlan_reg_freq_to_chan(pdev,
1345 conn_peer->pref_off_chan_freq);
1346 chan_switch_params->oper_class =
1347 tdls_get_opclass_from_bandwidth(
1348 vdev, conn_peer->pref_off_chan_freq,
1349 conn_peer->pref_off_chan_width,
1350 &chan_switch_params->tdls_off_ch_bw_offset);
1351 chan_switch_params->tdls_off_chan_freq =
1352 conn_peer->pref_off_chan_freq;
1353 } else {
1354 tdls_err("TDLS off-channel parameters are not set yet!!!");
1355 qdf_mem_free(chan_switch_params);
1356 return -EINVAL;
1357
1358 }
1359
1360 /*
1361 * Retain the connected peer preferred off-channel frequency
1362 * and opclass that was calculated during update peer caps and
1363 * don't overwrite it based on concurrency in
1364 * tdls_update_peer_off_channel_list().
1365 */
1366 conn_peer->pref_off_chan_freq =
1367 wlan_reg_chan_opclass_to_freq(
1368 chan_switch_params->tdls_off_ch,
1369 chan_switch_params->oper_class, false);
1370 conn_peer->op_class_for_pref_off_chan =
1371 chan_switch_params->oper_class;
1372
1373 /*
1374 * Don't enable TDLS off channel if concurrency is not allowed
1375 */
1376 status = tdls_update_peer_off_channel_list(pdev, tdls_soc, vdev,
1377 conn_peer,
1378 chan_switch_params);
1379 if (QDF_IS_STATUS_ERROR(status)) {
1380 qdf_mem_free(chan_switch_params);
1381 return -EINVAL;
1382 }
1383
1384 break;
1385 case DISABLE_CHANSWITCH:
1386 case DISABLE_ACTIVE_CHANSWITCH:
1387 chan_switch_params->tdls_off_ch = 0;
1388 chan_switch_params->tdls_off_ch_bw_offset = 0;
1389 chan_switch_params->oper_class = 0;
1390 break;
1391 default:
1392 tdls_err("Incorrect Parameters mode: %d tdls_off_channel: %d offchanoffset: %d",
1393 offchanmode, tdls_soc->tdls_off_channel,
1394 tdls_soc->tdls_channel_offset);
1395 qdf_mem_free(chan_switch_params);
1396 return -EINVAL;
1397 } /* end switch */
1398
1399 chan_switch_params->vdev_id = tdls_vdev->session_id;
1400 chan_switch_params->tdls_sw_mode = offchanmode;
1401 chan_switch_params->is_responder = conn_peer->is_responder;
1402 qdf_mem_copy(&chan_switch_params->peer_mac_addr,
1403 &conn_peer->peer_mac.bytes, QDF_MAC_ADDR_SIZE);
1404 tdls_notice("Peer " QDF_MAC_ADDR_FMT " vdevId: %d, off channel: %d, offset: %d, num_allowed_off_chan:%d mode: %d, is_responder: %d",
1405 QDF_MAC_ADDR_REF(chan_switch_params->peer_mac_addr),
1406 chan_switch_params->vdev_id,
1407 chan_switch_params->tdls_off_ch,
1408 chan_switch_params->tdls_off_ch_bw_offset,
1409 chan_switch_params->num_off_channels,
1410 chan_switch_params->tdls_sw_mode,
1411 chan_switch_params->is_responder);
1412
1413 status = tgt_tdls_set_offchan_mode(tdls_soc->soc, chan_switch_params);
1414 if (QDF_IS_STATUS_ERROR(status)) {
1415 qdf_mem_free(chan_switch_params);
1416 tdls_err("Failed to send channel switch request to wmi");
1417 return -EINVAL;
1418 }
1419
1420 tdls_soc->tdls_fw_off_chan_mode = offchanmode;
1421 qdf_mem_free(chan_switch_params);
1422
1423 return ret_value;
1424 }
1425
tdls_delete_all_tdls_peers_flush_cb(struct scheduler_msg * msg)1426 static QDF_STATUS tdls_delete_all_tdls_peers_flush_cb(struct scheduler_msg *msg)
1427 {
1428 if (msg && msg->bodyptr) {
1429 qdf_mem_free(msg->bodyptr);
1430 msg->bodyptr = NULL;
1431 }
1432
1433 return QDF_STATUS_SUCCESS;
1434 }
1435 /**
1436 * tdls_delete_all_tdls_peers(): send request to delete tdls peers
1437 * @vdev: vdev object
1438 * @tdls_soc: tdls soc object
1439 *
1440 * This function sends request to lim to delete tdls peers
1441 *
1442 * Return: QDF_STATUS
1443 */
tdls_delete_all_tdls_peers(struct wlan_objmgr_vdev * vdev,struct tdls_soc_priv_obj * tdls_soc)1444 QDF_STATUS tdls_delete_all_tdls_peers(struct wlan_objmgr_vdev *vdev,
1445 struct tdls_soc_priv_obj *tdls_soc)
1446 {
1447 struct wlan_objmgr_peer *peer;
1448 struct tdls_del_all_tdls_peers *del_msg;
1449 struct scheduler_msg msg = {0};
1450 QDF_STATUS status;
1451
1452 peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_SB_ID);
1453 if (!peer) {
1454 tdls_err("bss peer is null");
1455 return QDF_STATUS_E_FAILURE;
1456 }
1457
1458 del_msg = qdf_mem_malloc(sizeof(*del_msg));
1459 if (!del_msg) {
1460 wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID);
1461 return QDF_STATUS_E_FAILURE;
1462 }
1463
1464 qdf_mem_copy(del_msg->bssid.bytes,
1465 wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE);
1466
1467 wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID);
1468
1469 del_msg->msg_type = tdls_soc->tdls_del_all_peers;
1470 del_msg->msg_len = (uint16_t) sizeof(*del_msg);
1471
1472 /* Send the request to PE. */
1473 qdf_mem_zero(&msg, sizeof(msg));
1474
1475 tdls_debug("sending delete all peers req to PE ");
1476
1477 msg.type = del_msg->msg_type;
1478 msg.bodyptr = del_msg;
1479 msg.flush_callback = tdls_delete_all_tdls_peers_flush_cb;
1480
1481 status = scheduler_post_message(QDF_MODULE_ID_TDLS,
1482 QDF_MODULE_ID_PE,
1483 QDF_MODULE_ID_PE, &msg);
1484 if (QDF_IS_STATUS_ERROR(status)) {
1485 tdls_err("post delete all peer req failed, status %d", status);
1486 qdf_mem_free(del_msg);
1487 }
1488
1489 return status;
1490 }
1491
tdls_disable_offchan_and_teardown_links(struct wlan_objmgr_vdev * vdev)1492 void tdls_disable_offchan_and_teardown_links(
1493 struct wlan_objmgr_vdev *vdev)
1494 {
1495 uint16_t connected_tdls_peers = 0;
1496 uint8_t staidx;
1497 struct tdls_peer *curr_peer = NULL;
1498 struct tdls_vdev_priv_obj *tdls_vdev;
1499 struct tdls_soc_priv_obj *tdls_soc;
1500 QDF_STATUS status;
1501 uint8_t vdev_id;
1502 bool tdls_in_progress = false;
1503 bool is_mlo_vdev;
1504
1505 is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev);
1506 if (is_mlo_vdev) {
1507 tdls_debug("try to set vdev %d to unforce",
1508 wlan_vdev_get_id(vdev));
1509 tdls_set_link_unforce(vdev);
1510 }
1511
1512 status = tdls_get_vdev_objects(vdev, &tdls_vdev, &tdls_soc);
1513 if (QDF_STATUS_SUCCESS != status) {
1514 tdls_err("tdls objects are NULL ");
1515 return;
1516 }
1517
1518 if (TDLS_SUPPORT_SUSPENDED >= tdls_soc->tdls_current_mode) {
1519 tdls_debug("TDLS mode %d is disabled OR not suspended now",
1520 tdls_soc->tdls_current_mode);
1521 return;
1522 }
1523
1524 connected_tdls_peers = tdls_soc->connected_peer_count;
1525 if (tdls_is_progress(tdls_vdev, NULL, 0))
1526 tdls_in_progress = true;
1527
1528 if (!(connected_tdls_peers || tdls_in_progress)) {
1529 vdev_id = vdev->vdev_objmgr.vdev_id;
1530 tdls_debug("No TDLS connected/progress peers to delete Disable tdls for vdev id %d, "
1531 "FW as second interface is coming up", vdev_id);
1532 tdls_send_update_to_fw(tdls_vdev, tdls_soc, true, true, false,
1533 vdev_id);
1534 return;
1535 }
1536
1537 /* TDLS is not supported in case of concurrency.
1538 * Disable TDLS Offchannel in FW to avoid more
1539 * than two concurrent channels and generate TDLS
1540 * teardown indication to supplicant.
1541 * Below function Finds the first connected peer and
1542 * disables TDLS offchannel for that peer.
1543 * FW enables TDLS offchannel only when there is
1544 * one TDLS peer. When there are more than one TDLS peer,
1545 * there will not be TDLS offchannel in FW.
1546 * So to avoid sending multiple request to FW, for now,
1547 * just invoke offchannel mode functions only once
1548 */
1549 tdls_set_tdls_offchannel(tdls_soc,
1550 tdls_soc->tdls_configs.tdls_pre_off_chan_num);
1551 tdls_set_tdls_secoffchanneloffset(tdls_soc,
1552 TDLS_SEC_OFFCHAN_OFFSET_40PLUS);
1553 tdls_set_tdls_offchannelmode(vdev, DISABLE_ACTIVE_CHANSWITCH);
1554
1555 /* Send Msg to PE for deleting all the TDLS peers */
1556 tdls_delete_all_tdls_peers(vdev, tdls_soc);
1557
1558 for (staidx = 0; staidx < tdls_soc->max_num_tdls_sta; staidx++) {
1559 if (!tdls_soc->tdls_conn_info[staidx].valid_entry)
1560 continue;
1561
1562 curr_peer = tdls_find_all_peer(tdls_soc,
1563 tdls_soc->tdls_conn_info[staidx].peer_mac.bytes);
1564 if (!curr_peer)
1565 continue;
1566
1567 tdls_notice("indicate TDLS teardown "QDF_MAC_ADDR_FMT,
1568 QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes));
1569
1570 /* Indicate teardown to supplicant */
1571 tdls_indicate_teardown(tdls_vdev, curr_peer,
1572 TDLS_TEARDOWN_PEER_UNSPEC_REASON);
1573
1574 tdls_decrement_peer_count(vdev, tdls_soc);
1575
1576 /*
1577 * Del Sta happened already as part of tdls_delete_all_tdls_peers
1578 * Hence clear tdls vdev data structure.
1579 */
1580 tdls_reset_peer(tdls_vdev, curr_peer->peer_mac.bytes);
1581
1582 tdls_soc->tdls_conn_info[staidx].valid_entry = false;
1583 tdls_soc->tdls_conn_info[staidx].session_id = 255;
1584 tdls_soc->tdls_conn_info[staidx].index =
1585 INVALID_TDLS_PEER_INDEX;
1586
1587 qdf_mem_zero(&tdls_soc->tdls_conn_info[staidx].peer_mac,
1588 sizeof(struct qdf_mac_addr));
1589 }
1590 }
1591
tdls_teardown_connections(struct tdls_link_teardown * tdls_teardown)1592 void tdls_teardown_connections(struct tdls_link_teardown *tdls_teardown)
1593 {
1594 struct tdls_vdev_priv_obj *tdls_vdev_obj;
1595 struct wlan_objmgr_vdev *tdls_vdev;
1596
1597 /* Get the tdls specific vdev and clear the links */
1598 tdls_vdev = tdls_get_vdev(tdls_teardown->psoc, WLAN_TDLS_SB_ID);
1599 if (!tdls_vdev) {
1600 tdls_err("Unable get the vdev");
1601 goto fail_vdev;
1602 }
1603
1604 tdls_vdev_obj = wlan_vdev_get_tdls_vdev_obj(tdls_vdev);
1605 if (!tdls_vdev_obj) {
1606 tdls_err("vdev priv is NULL");
1607 goto fail_tdls_vdev;
1608 }
1609
1610 tdls_debug("tdls teardown connections");
1611 wlan_vdev_mlme_feat_ext2_cap_clear(tdls_vdev,
1612 WLAN_VDEV_FEXT2_MLO_STA_TDLS);
1613
1614 tdls_disable_offchan_and_teardown_links(tdls_vdev);
1615 qdf_event_set(&tdls_vdev_obj->tdls_teardown_comp);
1616 fail_tdls_vdev:
1617 wlan_objmgr_vdev_release_ref(tdls_vdev, WLAN_TDLS_SB_ID);
1618 fail_vdev:
1619 wlan_objmgr_psoc_release_ref(tdls_teardown->psoc, WLAN_TDLS_SB_ID);
1620 qdf_mem_free(tdls_teardown);
1621 }
1622