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