blob: e4283f0d7acf2a8aa28245a7e400f350b918bdbc [file] [log] [blame]
Frank Liu7e890d62017-03-02 17:17:53 +08001/*
hangtiana7938f82019-01-07 16:35:49 +08002 * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
Frank Liu7e890d62017-03-02 17:17:53 +08003 *
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/**
20 * DOC: wlan_tdls_ct.c
21 *
22 * TDLS connection tracker function definitions
23 */
Kabilan Kannan00619ab2017-03-20 01:59:24 -070024
25#include "wlan_tdls_main.h"
26#include "wlan_tdls_peer.h"
27#include "wlan_tdls_ct.h"
Kabilan Kannance5880e2017-04-17 21:53:42 -070028#include "wlan_tdls_cmds_process.h"
Kabilan Kannan00619ab2017-03-20 01:59:24 -070029
Kabilan Kannanf3f11a72017-03-26 18:52:47 -070030bool tdls_is_vdev_authenticated(struct wlan_objmgr_vdev *vdev)
31{
32 struct wlan_objmgr_peer *peer;
33 bool is_authenticated = false;
34
sheenam monga0b2054b2019-05-02 14:17:31 +053035 peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_NB_ID);
Kabilan Kannanf3f11a72017-03-26 18:52:47 -070036 if (!peer) {
37 tdls_err("peer is null");
38 return false;
39 }
40
Kabilan Kannanf3f11a72017-03-26 18:52:47 -070041 is_authenticated = wlan_peer_mlme_get_auth_state(peer);
sheenam monga0b2054b2019-05-02 14:17:31 +053042 wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID);
Kabilan Kannanf3f11a72017-03-26 18:52:47 -070043 return is_authenticated;
44}
45
Kabilan Kannan00619ab2017-03-20 01:59:24 -070046/**
47 * tdls_peer_reset_discovery_processed() - reset discovery status
48 * @tdls_vdev: TDLS vdev object
49 *
50 * This function resets discovery processing bit for all TDLS peers
51 *
52 * Caller has to take the lock before calling this function
53 *
54 * Return: 0
55 */
56static int32_t tdls_peer_reset_discovery_processed(
57 struct tdls_vdev_priv_obj *tdls_vdev)
58{
59 int i;
60 qdf_list_t *head;
61 qdf_list_node_t *p_node;
62 struct tdls_peer *peer;
63 QDF_STATUS status;
64
65 tdls_vdev->discovery_peer_cnt = 0;
66
67 for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
68 head = &tdls_vdev->peer_list[i];
69 status = qdf_list_peek_front(head, &p_node);
70 while (QDF_IS_STATUS_SUCCESS(status)) {
71 peer = qdf_container_of(p_node, struct tdls_peer, node);
72 peer->discovery_processed = 0;
73 status = qdf_list_peek_next(head, p_node, &p_node);
74 }
75 }
76
77 return 0;
78}
79
80void tdls_discovery_timeout_peer_cb(void *user_data)
81{
82 int i;
83 qdf_list_t *head;
84 qdf_list_node_t *p_node;
85 struct tdls_peer *peer;
86 QDF_STATUS status;
87 struct tdls_vdev_priv_obj *tdls_vdev;
88
89 if (!user_data) {
90 tdls_err("discovery time out data is null");
91 return;
92 }
93
94 tdls_vdev = (struct tdls_vdev_priv_obj *) user_data;
95
96 for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
97 head = &tdls_vdev->peer_list[i];
98 status = qdf_list_peek_front(head, &p_node);
99 while (QDF_IS_STATUS_SUCCESS(status)) {
100 peer = qdf_container_of(p_node, struct tdls_peer,
101 node);
102 if (TDLS_LINK_DISCOVERING != peer->link_status) {
103 status = qdf_list_peek_next(head, p_node,
104 &p_node);
105 continue;
106 }
Dustin Brown759661d2018-01-25 11:46:31 -0800107 tdls_debug(QDF_MAC_ADDR_STR " to idle state",
108 QDF_MAC_ADDR_ARRAY(peer->peer_mac.bytes));
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700109 tdls_set_peer_link_status(peer,
110 TDLS_LINK_IDLE,
111 TDLS_LINK_NOT_SUPPORTED);
112 }
113 }
114 tdls_vdev->discovery_sent_cnt = 0;
115
116 /* add tdls power save prohibited */
117
118 return;
119}
120
121/**
122 * tdls_reset_tx_rx() - reset tx/rx counters for all tdls peers
123 * @tdls_vdev: TDLS vdev object
124 *
125 * Caller has to take the TDLS lock before calling this function
126 *
127 * Return: Void
128 */
129static void tdls_reset_tx_rx(struct tdls_vdev_priv_obj *tdls_vdev)
130{
131 int i;
132 qdf_list_t *head;
133 qdf_list_node_t *p_node;
134 struct tdls_peer *peer;
135 QDF_STATUS status;
136
137 for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
138 head = &tdls_vdev->peer_list[i];
139 status = qdf_list_peek_front(head, &p_node);
140 while (QDF_IS_STATUS_SUCCESS(status)) {
141 peer = qdf_container_of(p_node, struct tdls_peer, node);
142 peer->tx_pkt = 0;
143 peer->rx_pkt = 0;
144 status = qdf_list_peek_next(head, p_node, &p_node);
145 }
146 }
147 return;
148}
149
150void tdls_implicit_disable(struct tdls_vdev_priv_obj *tdls_vdev)
151{
152 tdls_debug("Disable Implicit TDLS");
153 tdls_timers_stop(tdls_vdev);
154}
155
156/**
157 * tdls_implicit_enable() - enable implicit tdls triggering
158 * @tdls_vdev: TDLS vdev
159 *
160 * Return: Void
161 */
162void tdls_implicit_enable(struct tdls_vdev_priv_obj *tdls_vdev)
163{
164 tdls_debug("Enable Implicit TDLS");
165 if (!tdls_vdev)
166 return;
167
168 tdls_peer_reset_discovery_processed(tdls_vdev);
169 tdls_reset_tx_rx(tdls_vdev);
170 /* TODO check whether tdls power save prohibited */
171
172 /* Restart the connection tracker timer */
173 tdls_timer_restart(tdls_vdev->vdev, &tdls_vdev->peer_update_timer,
174 tdls_vdev->threshold_config.tx_period_t);
175}
176
177/**
178 * tdls_ct_sampling_tx_rx() - collect tx/rx traffic sample
179 * @tdls_vdev_obj: tdls vdev object
180 * @tdls_soc_obj: tdls soc object
181 *
182 * Function to update data traffic information in tdls connection
183 * tracker data structure for connection tracker operation
184 *
185 * Return: None
186 */
187static void tdls_ct_sampling_tx_rx(struct tdls_vdev_priv_obj *tdls_vdev,
188 struct tdls_soc_priv_obj *tdls_soc)
189{
190 struct tdls_peer *curr_peer;
191 uint8_t mac[QDF_MAC_ADDR_SIZE];
192 uint8_t mac_cnt;
193 uint8_t mac_entries;
194 struct tdls_conn_tracker_mac_table mac_table[WLAN_TDLS_CT_TABLE_SIZE];
195
196 qdf_spin_lock_bh(&tdls_soc->tdls_ct_spinlock);
197
198 if (0 == tdls_vdev->valid_mac_entries) {
199 qdf_spin_unlock_bh(&tdls_soc->tdls_ct_spinlock);
200 return;
201 }
202
Bala Venkateshe1734052018-06-28 11:13:25 +0530203 mac_entries = QDF_MIN(tdls_vdev->valid_mac_entries,
204 WLAN_TDLS_CT_TABLE_SIZE);
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700205
206 qdf_mem_copy(mac_table, tdls_vdev->ct_peer_table,
207 (sizeof(struct tdls_conn_tracker_mac_table)) * mac_entries);
208
hangtian127c9532019-01-12 13:29:07 +0800209 qdf_mem_zero(tdls_vdev->ct_peer_table,
210 (sizeof(struct tdls_conn_tracker_mac_table)) * mac_entries);
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700211
212 tdls_vdev->valid_mac_entries = 0;
213
214 qdf_spin_unlock_bh(&tdls_soc->tdls_ct_spinlock);
215
216 for (mac_cnt = 0; mac_cnt < mac_entries; mac_cnt++) {
217 qdf_mem_copy(mac, mac_table[mac_cnt].mac_address.bytes,
218 QDF_MAC_ADDR_SIZE);
219 curr_peer = tdls_get_peer(tdls_vdev, mac);
Jeff Johnsonbdc473f2019-03-18 13:45:10 -0700220 if (curr_peer) {
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700221 curr_peer->tx_pkt =
222 mac_table[mac_cnt].tx_packet_cnt;
223 curr_peer->rx_pkt =
224 mac_table[mac_cnt].rx_packet_cnt;
225 }
226 }
227}
228
229void tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
hangtiana7938f82019-01-07 16:35:49 +0800230 struct qdf_mac_addr *mac_addr,
231 struct qdf_mac_addr *dest_mac_addr)
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700232{
233 struct tdls_vdev_priv_obj *tdls_vdev_obj;
234 struct tdls_soc_priv_obj *tdls_soc_obj;
235 uint8_t mac_cnt;
236 uint8_t valid_mac_entries;
237 struct tdls_conn_tracker_mac_table *mac_table;
Bala Venkateshd576fc52019-05-22 13:18:57 +0530238 struct wlan_objmgr_peer *bss_peer;
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700239
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700240 if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj,
Bala Venkateshd576fc52019-05-22 13:18:57 +0530241 &tdls_soc_obj))
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700242 return;
243
244 if (!tdls_soc_obj->enable_tdls_connection_tracker)
245 return;
246
247 if (qdf_is_macaddr_group(mac_addr))
248 return;
249
hangtiana7938f82019-01-07 16:35:49 +0800250 if (qdf_is_macaddr_group(dest_mac_addr))
251 return;
252
Bala Venkateshd576fc52019-05-22 13:18:57 +0530253 if (!qdf_mem_cmp(vdev->vdev_mlme.macaddr, mac_addr,
254 QDF_MAC_ADDR_SIZE))
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700255 return;
256
Bala Venkateshd576fc52019-05-22 13:18:57 +0530257 bss_peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_NB_ID);
258 if (bss_peer) {
259 if (!qdf_mem_cmp(bss_peer->macaddr, mac_addr,
260 QDF_MAC_ADDR_SIZE)) {
261 wlan_objmgr_peer_release_ref(bss_peer, WLAN_TDLS_NB_ID);
262 return;
263 }
264 wlan_objmgr_peer_release_ref(bss_peer, WLAN_TDLS_NB_ID);
265 }
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700266 qdf_spin_lock_bh(&tdls_soc_obj->tdls_ct_spinlock);
267 valid_mac_entries = tdls_vdev_obj->valid_mac_entries;
268 mac_table = tdls_vdev_obj->ct_peer_table;
269
270 for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) {
271 if (qdf_mem_cmp(mac_table[mac_cnt].mac_address.bytes,
272 mac_addr, QDF_MAC_ADDR_SIZE) == 0) {
273 mac_table[mac_cnt].rx_packet_cnt++;
274 goto rx_cnt_return;
275 }
276 }
277
278 /* If we have more than 8 peers within 30 mins. we will
279 * stop tracking till the old entries are removed
280 */
281 if (mac_cnt < WLAN_TDLS_CT_TABLE_SIZE) {
282 qdf_mem_copy(mac_table[mac_cnt].mac_address.bytes,
283 mac_addr, QDF_MAC_ADDR_SIZE);
284 tdls_vdev_obj->valid_mac_entries = mac_cnt+1;
285 mac_table[mac_cnt].rx_packet_cnt = 1;
286 }
287
288rx_cnt_return:
289 qdf_spin_unlock_bh(&tdls_soc_obj->tdls_ct_spinlock);
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700290 return;
291}
292
293void tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
294 struct qdf_mac_addr *mac_addr)
295{
296 struct tdls_vdev_priv_obj *tdls_vdev_obj;
297 struct tdls_soc_priv_obj *tdls_soc_obj;
298 uint8_t mac_cnt;
299 uint8_t valid_mac_entries;
300 struct tdls_conn_tracker_mac_table *mac_table;
Bala Venkateshd576fc52019-05-22 13:18:57 +0530301 struct wlan_objmgr_peer *bss_peer;
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700302
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700303 if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj,
Bala Venkateshd576fc52019-05-22 13:18:57 +0530304 &tdls_soc_obj))
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700305 return;
306
307 if (!tdls_soc_obj->enable_tdls_connection_tracker)
308 return;
309
310 if (qdf_is_macaddr_group(mac_addr))
311 return;
312
Bala Venkateshd576fc52019-05-22 13:18:57 +0530313 if (!qdf_mem_cmp(vdev->vdev_mlme.macaddr, mac_addr,
314 QDF_MAC_ADDR_SIZE))
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700315 return;
Bala Venkateshd576fc52019-05-22 13:18:57 +0530316 bss_peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_NB_ID);
317 if (bss_peer) {
318 if (!qdf_mem_cmp(bss_peer->macaddr, mac_addr,
319 QDF_MAC_ADDR_SIZE)) {
320 wlan_objmgr_peer_release_ref(bss_peer, WLAN_TDLS_NB_ID);
321 return;
322 }
323 wlan_objmgr_peer_release_ref(bss_peer, WLAN_TDLS_NB_ID);
324 }
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700325
326 qdf_spin_lock_bh(&tdls_soc_obj->tdls_ct_spinlock);
327 mac_table = tdls_vdev_obj->ct_peer_table;
328
329 valid_mac_entries = tdls_vdev_obj->valid_mac_entries;
330
331 for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) {
332 if (qdf_mem_cmp(mac_table[mac_cnt].mac_address.bytes,
333 mac_addr, QDF_MAC_ADDR_SIZE) == 0) {
334 mac_table[mac_cnt].tx_packet_cnt++;
335 goto tx_cnt_return;
336 }
337 }
338
339 /* If we have more than 8 peers within 30 mins. we will
340 * stop tracking till the old entries are removed
341 */
342 if (mac_cnt < WLAN_TDLS_CT_TABLE_SIZE) {
343 qdf_mem_copy(mac_table[mac_cnt].mac_address.bytes,
344 mac_addr, QDF_MAC_ADDR_SIZE);
345 mac_table[mac_cnt].tx_packet_cnt = 1;
346 tdls_vdev_obj->valid_mac_entries++;
347 }
348
349tx_cnt_return:
350 qdf_spin_unlock_bh(&tdls_soc_obj->tdls_ct_spinlock);
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700351 return;
352}
353
354void tdls_implicit_send_discovery_request(
355 struct tdls_vdev_priv_obj *tdls_vdev_obj)
356{
357 struct tdls_peer *curr_peer;
358 struct tdls_peer *temp_peer;
359 struct tdls_soc_priv_obj *tdls_psoc;
360 struct tdls_osif_indication tdls_ind;
361
Jeff Johnsonbdc473f2019-03-18 13:45:10 -0700362 if (!tdls_vdev_obj) {
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700363 tdls_notice("tdls_vdev_obj is NULL");
364 return;
365 }
366
367 tdls_psoc = wlan_vdev_get_tdls_soc_obj(tdls_vdev_obj->vdev);
368
Jeff Johnsonbdc473f2019-03-18 13:45:10 -0700369 if (!tdls_psoc) {
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700370 tdls_notice("tdls_psoc_obj is NULL");
371 return;
372 }
373
374 curr_peer = tdls_vdev_obj->curr_candidate;
375
Jeff Johnsonbdc473f2019-03-18 13:45:10 -0700376 if (!curr_peer) {
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700377 tdls_err("curr_peer is NULL");
378 return;
379 }
380
381 /* This function is called in mutex_lock */
382 temp_peer = tdls_is_progress(tdls_vdev_obj, NULL, 0);
Jeff Johnsonbdc473f2019-03-18 13:45:10 -0700383 if (temp_peer) {
Dustin Brown759661d2018-01-25 11:46:31 -0800384 tdls_notice(QDF_MAC_ADDR_STR " ongoing. pre_setup ignored",
385 QDF_MAC_ADDR_ARRAY(temp_peer->peer_mac.bytes));
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700386 goto done;
387 }
388
389 if (TDLS_CAP_UNKNOWN != curr_peer->tdls_support)
390 tdls_set_peer_link_status(curr_peer,
391 TDLS_LINK_DISCOVERING,
392 TDLS_LINK_SUCCESS);
393
394 qdf_mem_copy(tdls_ind.peer_mac, curr_peer->peer_mac.bytes,
395 QDF_MAC_ADDR_SIZE);
396
397 tdls_ind.vdev = tdls_vdev_obj->vdev;
398
399 tdls_debug("Implicit TDLS, Send Discovery request event");
400
401 tdls_psoc->tdls_event_cb(tdls_psoc->tdls_evt_cb_data,
402 TDLS_EVENT_DISCOVERY_REQ, &tdls_ind);
403
404 tdls_vdev_obj->discovery_sent_cnt++;
405
406 tdls_timer_restart(tdls_vdev_obj->vdev,
407 &tdls_vdev_obj->peer_discovery_timer,
408 tdls_vdev_obj->threshold_config.tx_period_t -
409 TDLS_DISCOVERY_TIMEOUT_ERE_UPDATE);
410
411 tdls_debug("discovery count %u timeout %u msec",
412 tdls_vdev_obj->discovery_sent_cnt,
413 tdls_vdev_obj->threshold_config.tx_period_t -
414 TDLS_DISCOVERY_TIMEOUT_ERE_UPDATE);
415done:
416 tdls_vdev_obj->curr_candidate = NULL;
417 tdls_vdev_obj->magic = 0;
418 return;
419}
420
421int tdls_recv_discovery_resp(struct tdls_vdev_priv_obj *tdls_vdev,
422 const uint8_t *mac)
423{
424 struct tdls_peer *curr_peer;
425 struct tdls_soc_priv_obj *tdls_soc;
426 struct tdls_osif_indication indication;
427 struct tdls_config_params *tdls_cfg;
428 int status = 0;
429
430 if (!tdls_vdev)
431 return -EINVAL;
432
433 tdls_soc = wlan_vdev_get_tdls_soc_obj(tdls_vdev->vdev);
Jeff Johnsonbdc473f2019-03-18 13:45:10 -0700434 if (!tdls_soc) {
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700435 tdls_err("tdls soc is NULL");
436 return -EINVAL;
437 }
438
439 curr_peer = tdls_get_peer(tdls_vdev, mac);
Jeff Johnsonbdc473f2019-03-18 13:45:10 -0700440 if (!curr_peer) {
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700441 tdls_err("curr_peer is NULL");
442 return -EINVAL;
443 }
444
445 if (tdls_vdev->discovery_sent_cnt)
446 tdls_vdev->discovery_sent_cnt--;
447
448 if (0 == tdls_vdev->discovery_sent_cnt)
449 qdf_mc_timer_stop(&tdls_vdev->peer_discovery_timer);
450
Dustin Brown759661d2018-01-25 11:46:31 -0800451 tdls_debug("Discovery(%u) Response from " QDF_MAC_ADDR_STR
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700452 " link_status %d", tdls_vdev->discovery_sent_cnt,
453 QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes),
454 curr_peer->link_status);
455
456 tdls_cfg = &tdls_vdev->threshold_config;
457 if (TDLS_LINK_DISCOVERING == curr_peer->link_status) {
458 /* Since we are here, it means Throughput threshold is
459 * already met. Make sure RSSI threshold is also met
460 * before setting up TDLS link.
461 */
462 if ((int32_t) curr_peer->rssi >
463 (int32_t) tdls_cfg->rssi_trigger_threshold) {
464 tdls_set_peer_link_status(curr_peer,
465 TDLS_LINK_DISCOVERED,
466 TDLS_LINK_SUCCESS);
Dustin Brown759661d2018-01-25 11:46:31 -0800467 tdls_debug("Rssi Threshold met: " QDF_MAC_ADDR_STR
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700468 " rssi = %d threshold= %d",
469 QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes),
470 curr_peer->rssi,
471 tdls_cfg->rssi_trigger_threshold);
472
473 qdf_mem_copy(indication.peer_mac, mac,
474 QDF_MAC_ADDR_SIZE);
475
476 indication.vdev = tdls_vdev->vdev;
477
478 tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
479 TDLS_EVENT_SETUP_REQ,
480 &indication);
481 } else {
Dustin Brown759661d2018-01-25 11:46:31 -0800482 tdls_debug("Rssi Threshold not met: " QDF_MAC_ADDR_STR
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700483 " rssi = %d threshold = %d ",
484 QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes),
485 curr_peer->rssi,
486 tdls_cfg->rssi_trigger_threshold);
487
488 tdls_set_peer_link_status(curr_peer,
489 TDLS_LINK_IDLE,
490 TDLS_LINK_UNSPECIFIED);
491
492 /* if RSSI threshold is not met then allow
493 * further discovery attempts by decrementing
494 * count for the last attempt
495 */
496 if (curr_peer->discovery_attempt)
497 curr_peer->discovery_attempt--;
498 }
499 }
500
501 curr_peer->tdls_support = TDLS_CAP_SUPPORTED;
502
503 return status;
504}
505
506void tdls_indicate_teardown(struct tdls_vdev_priv_obj *tdls_vdev,
507 struct tdls_peer *curr_peer,
508 uint16_t reason)
509{
510 struct tdls_soc_priv_obj *tdls_soc;
511 struct tdls_osif_indication indication;
512
Frank Liu90b989b2018-01-10 13:46:50 +0800513 if (!tdls_vdev || !curr_peer) {
514 tdls_err("tdls_vdev: %pK, curr_peer: %pK",
515 tdls_vdev, curr_peer);
516 return;
517 }
518
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700519 tdls_soc = wlan_vdev_get_tdls_soc_obj(tdls_vdev->vdev);
Frank Liu90b989b2018-01-10 13:46:50 +0800520 if (!tdls_soc) {
521 tdls_err("tdls_soc: %pK", tdls_soc);
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700522 return;
523 }
524
525 if (TDLS_LINK_CONNECTED != curr_peer->link_status)
526 return;
527
528 tdls_set_peer_link_status(curr_peer,
529 TDLS_LINK_TEARING,
530 TDLS_LINK_UNSPECIFIED);
531 tdls_notice("Teardown reason %d", reason);
532
Kabilan Kannan7c0093d2017-04-26 13:26:47 -0700533 if (tdls_soc->tdls_dp_vdev_update)
534 tdls_soc->tdls_dp_vdev_update(&tdls_soc->soc,
Yeshwanth Sriram Guntuka31990462019-08-02 17:33:50 +0530535 &curr_peer->peer_mac,
Kabilan Kannan7c0093d2017-04-26 13:26:47 -0700536 tdls_soc->tdls_update_dp_vdev_flags,
Kabilan Kannanc441d7b2017-09-07 20:06:17 -0700537 false);
Kabilan Kannan7c0093d2017-04-26 13:26:47 -0700538
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700539 indication.reason = reason;
540 indication.vdev = tdls_vdev->vdev;
541 qdf_mem_copy(indication.peer_mac, curr_peer->peer_mac.bytes,
542 QDF_MAC_ADDR_SIZE);
543
544 if (tdls_soc->tdls_event_cb)
545 tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
546 TDLS_EVENT_TEARDOWN_REQ, &indication);
547}
548
549/**
550 * tdls_get_conn_info() - get the tdls connection information.
551 * @tdls_soc: tdls soc object
Yeshwanth Sriram Guntuka4ac15842019-07-16 15:47:21 +0530552 * @peer_mac: peer MAC address
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700553 *
554 * Function to check tdls sta index
555 *
556 * Return: tdls connection information
557 */
558static struct tdls_conn_info *
Yeshwanth Sriram Guntuka4ac15842019-07-16 15:47:21 +0530559tdls_get_conn_info(struct tdls_soc_priv_obj *tdls_soc,
560 struct qdf_mac_addr *peer_mac)
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700561{
562 uint8_t sta_idx;
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700563 /* check if there is available index for this new TDLS STA */
564 for (sta_idx = 0; sta_idx < WLAN_TDLS_STA_MAX_NUM; sta_idx++) {
Yeshwanth Sriram Guntuka4ac15842019-07-16 15:47:21 +0530565 if (!qdf_mem_cmp(
566 tdls_soc->tdls_conn_info[sta_idx].peer_mac.bytes,
567 peer_mac->bytes, QDF_MAC_ADDR_SIZE)) {
568 tdls_debug("tdls peer exists %pM", peer_mac->bytes);
Bala Venkatesh2a773822019-02-04 19:52:27 +0530569 tdls_soc->tdls_conn_info[sta_idx].index = sta_idx;
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700570 return &tdls_soc->tdls_conn_info[sta_idx];
571 }
572 }
573
Yeshwanth Sriram Guntuka4ac15842019-07-16 15:47:21 +0530574 tdls_err("tdls peer does not exists");
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700575 return NULL;
576}
577
578static void
Bala Venkatesh2a773822019-02-04 19:52:27 +0530579tdls_ct_process_idle_handler(struct wlan_objmgr_vdev *vdev,
580 struct tdls_conn_info *tdls_info)
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700581{
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700582 struct tdls_peer *curr_peer;
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700583 struct tdls_vdev_priv_obj *tdls_vdev_obj;
584 struct tdls_soc_priv_obj *tdls_soc_obj;
585
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700586 if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj,
587 &tdls_soc_obj))
588 return;
589
Yeshwanth Sriram Guntuka4ac15842019-07-16 15:47:21 +0530590 if (!tdls_info->valid_entry) {
Yeshwanth Sriram Guntukae6b54242019-07-16 14:54:16 +0530591 tdls_err("peer doesn't exists");
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700592 return;
593 }
594
595 curr_peer = tdls_find_peer(tdls_vdev_obj,
596 (u8 *) &tdls_info->peer_mac.bytes[0]);
597
Jeff Johnsonbdc473f2019-03-18 13:45:10 -0700598 if (!curr_peer) {
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700599 tdls_err("Invalid tdls idle timer expired");
600 return;
601 }
602
Dustin Brown759661d2018-01-25 11:46:31 -0800603 tdls_debug(QDF_MAC_ADDR_STR
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700604 " tx_pkt: %d, rx_pkt: %d, idle_packet_n: %d",
605 QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes),
606 curr_peer->tx_pkt,
607 curr_peer->rx_pkt,
608 tdls_vdev_obj->threshold_config.idle_packet_n);
609
610 /* Check tx/rx statistics on this tdls link for recent activities and
611 * then decide whether to tear down the link or keep it.
612 */
613 if ((curr_peer->tx_pkt >=
614 tdls_vdev_obj->threshold_config.idle_packet_n) ||
615 (curr_peer->rx_pkt >=
616 tdls_vdev_obj->threshold_config.idle_packet_n)) {
617 /* this tdls link got back to normal, so keep it */
Dustin Brown759661d2018-01-25 11:46:31 -0800618 tdls_debug("tdls link to " QDF_MAC_ADDR_STR
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700619 " back to normal, will stay",
620 QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes));
621 } else {
622 /* this tdls link needs to get torn down */
Dustin Brown759661d2018-01-25 11:46:31 -0800623 tdls_notice("trigger tdls link to "QDF_MAC_ADDR_STR" down",
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700624 QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes));
625 tdls_indicate_teardown(tdls_vdev_obj,
626 curr_peer,
627 TDLS_TEARDOWN_PEER_UNSPEC_REASON);
628 }
629
630 return;
631}
632
633void tdls_ct_idle_handler(void *user_data)
634{
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700635 struct wlan_objmgr_vdev *vdev;
Bala Venkatesh2a773822019-02-04 19:52:27 +0530636 struct tdls_conn_info *tdls_info;
637 struct tdls_soc_priv_obj *tdls_soc_obj;
638 uint32_t idx;
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700639
Bala Venkatesh2a773822019-02-04 19:52:27 +0530640 tdls_info = (struct tdls_conn_info *)user_data;
641 if (!tdls_info)
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700642 return;
643
Bala Venkatesh2a773822019-02-04 19:52:27 +0530644 idx = tdls_info->index;
Bala Venkatesh4e3f2752019-06-18 19:35:16 +0530645 if (idx == INVALID_TDLS_PEER_INDEX || idx >= WLAN_TDLS_STA_MAX_NUM)
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700646 return;
647
Bala Venkatesh2a773822019-02-04 19:52:27 +0530648 tdls_soc_obj = qdf_container_of(tdls_info, struct tdls_soc_priv_obj,
649 tdls_conn_info[idx]);
650
651 vdev = tdls_get_vdev(tdls_soc_obj->soc, WLAN_TDLS_NB_ID);
652 if (!vdev) {
653 tdls_err("Unable to fetch the vdev");
654 return;
655 }
656
657 tdls_ct_process_idle_handler(vdev, tdls_info);
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700658 wlan_objmgr_vdev_release_ref(vdev,
659 WLAN_TDLS_NB_ID);
660}
661
662/**
663 * tdls_ct_process_idle_and_discovery() - process the traffic data
664 * @curr_peer: tdls peer needs to be examined
665 * @tdls_vdev_obj: tdls vdev object
666 * @tdls_soc_obj: tdls soc object
667 *
668 * Function to check the peer traffic data in idle link and tdls
669 * discovering link
670 *
671 * Return: None
672 */
673static void
674tdls_ct_process_idle_and_discovery(struct tdls_peer *curr_peer,
675 struct tdls_vdev_priv_obj *tdls_vdev_obj,
676 struct tdls_soc_priv_obj *tdls_soc_obj)
677{
678 uint16_t valid_peers;
679
680 valid_peers = tdls_soc_obj->connected_peer_count;
681
682 if ((curr_peer->tx_pkt + curr_peer->rx_pkt) >=
683 tdls_vdev_obj->threshold_config.tx_packet_n) {
684 if (WLAN_TDLS_STA_MAX_NUM > valid_peers) {
685 tdls_notice("Tput trigger TDLS pre-setup");
686 tdls_vdev_obj->curr_candidate = curr_peer;
687 tdls_implicit_send_discovery_request(tdls_vdev_obj);
688 } else {
689 tdls_notice("Maximum peers connected already! %d",
690 valid_peers);
691 }
692 }
693}
694
695/**
696 * tdls_ct_process_connected_link() - process the traffic
697 * @curr_peer: tdls peer needs to be examined
698 * @tdls_vdev_obj: tdls vdev
699 * @tdls_soc_obj: tdls soc context
700 *
701 * Function to check the peer traffic data in active STA
702 * session
703 *
704 * Return: None
705 */
706static void tdls_ct_process_connected_link(
707 struct tdls_peer *curr_peer,
708 struct tdls_vdev_priv_obj *tdls_vdev,
709 struct tdls_soc_priv_obj *tdls_soc)
710{
Wu Gaoeb2aa782019-04-17 18:57:56 +0800711 /* Don't trigger low rssi tear down here since FW will do it */
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700712 /* Only teardown based on non zero idle packet threshold, to address
713 * a use case where this threshold does not get consider for TEAR DOWN
714 */
715 if ((0 != tdls_vdev->threshold_config.idle_packet_n) &&
716 ((curr_peer->tx_pkt <
717 tdls_vdev->threshold_config.idle_packet_n) &&
718 (curr_peer->rx_pkt <
719 tdls_vdev->threshold_config.idle_packet_n))) {
720 if (!curr_peer->is_peer_idle_timer_initialised) {
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700721 struct tdls_conn_info *tdls_info;
Yeshwanth Sriram Guntuka4ac15842019-07-16 15:47:21 +0530722 tdls_info = tdls_get_conn_info(tdls_soc,
723 &curr_peer->peer_mac);
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700724 qdf_mc_timer_init(&curr_peer->peer_idle_timer,
725 QDF_TIMER_TYPE_SW,
726 tdls_ct_idle_handler,
Bala Venkatesh2a773822019-02-04 19:52:27 +0530727 (void *)tdls_info);
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700728 curr_peer->is_peer_idle_timer_initialised = true;
729 }
730 if (QDF_TIMER_STATE_RUNNING !=
731 curr_peer->peer_idle_timer.state) {
732 tdls_warn("Tx/Rx Idle timer start: "
Dustin Brown759661d2018-01-25 11:46:31 -0800733 QDF_MAC_ADDR_STR "!",
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700734 QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes));
735 tdls_timer_restart(tdls_vdev->vdev,
736 &curr_peer->peer_idle_timer,
737 tdls_vdev->threshold_config.idle_timeout_t);
738 }
739 } else if (QDF_TIMER_STATE_RUNNING ==
740 curr_peer->peer_idle_timer.state) {
Dustin Brown759661d2018-01-25 11:46:31 -0800741 tdls_warn("Tx/Rx Idle timer stop: " QDF_MAC_ADDR_STR "!",
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700742 QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes));
743 qdf_mc_timer_stop(&curr_peer->peer_idle_timer);
744 }
745}
746
747/**
748 * tdls_ct_process_cap_supported() - process TDLS supported peer.
749 * @curr_peer: tdls peer needs to be examined
750 * @tdls_vdev_obj: tdls vdev context
751 * @tdls_soc_obj: tdls soc context
752 *
753 * Function to check the peer traffic data for tdls supported peer
754 *
755 * Return: None
756 */
757static void tdls_ct_process_cap_supported(struct tdls_peer *curr_peer,
758 struct tdls_vdev_priv_obj *tdls_vdev,
759 struct tdls_soc_priv_obj *tdls_soc_obj)
760{
761 tdls_debug("tx %d rx %d thr.pkt %d/idle %d rssi %d thr.trig %d/tear %d",
762 curr_peer->tx_pkt, curr_peer->rx_pkt,
763 tdls_vdev->threshold_config.tx_packet_n,
764 tdls_vdev->threshold_config.idle_packet_n,
765 curr_peer->rssi,
766 tdls_vdev->threshold_config.rssi_trigger_threshold,
767 tdls_vdev->threshold_config.rssi_teardown_threshold);
768
769 switch (curr_peer->link_status) {
770 case TDLS_LINK_IDLE:
771 case TDLS_LINK_DISCOVERING:
772 if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(
773 tdls_soc_obj->tdls_configs.tdls_feature_flags) &&
774 (!curr_peer->is_forced_peer))
775 break;
776 tdls_ct_process_idle_and_discovery(curr_peer, tdls_vdev,
777 tdls_soc_obj);
778 break;
779 case TDLS_LINK_CONNECTED:
780 tdls_ct_process_connected_link(curr_peer, tdls_vdev,
781 tdls_soc_obj);
782 break;
783 default:
784 break;
785 }
786}
787
788/**
789 * tdls_ct_process_cap_unknown() - process unknown peer
790 * @curr_peer: tdls peer needs to be examined
791 * @tdls_vdev_obj: tdls vdev object
792 * @tdls_soc_obj: tdls soc object
793 *
794 * Function check the peer traffic data , when tdls capability is unknown
795 *
796 * Return: None
797 */
798static void tdls_ct_process_cap_unknown(struct tdls_peer *curr_peer,
799 struct tdls_vdev_priv_obj *tdls_vdev,
800 struct tdls_soc_priv_obj *tdlsa_soc)
801{
802 if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(
803 tdlsa_soc->tdls_configs.tdls_feature_flags) &&
804 (!curr_peer->is_forced_peer))
805 return;
806
807 tdls_debug("threshold tx pkt = %d peer tx_pkt = %d & rx_pkt = %d ",
808 tdls_vdev->threshold_config.tx_packet_n, curr_peer->tx_pkt,
809 curr_peer->rx_pkt);
810
811 if (!TDLS_IS_LINK_CONNECTED(curr_peer) &&
812 ((curr_peer->tx_pkt + curr_peer->rx_pkt) >=
813 tdls_vdev->threshold_config.tx_packet_n)) {
814 /* Ignore discovery attempt if External Control is enabled, that
815 * is, peer is forced. In that case, continue discovery attempt
816 * regardless attempt count
817 */
818 tdls_debug("TDLS UNKNOWN pre discover ");
819 if (curr_peer->is_forced_peer ||
820 curr_peer->discovery_attempt++ <
821 tdls_vdev->threshold_config.discovery_tries_n) {
822 tdls_debug("TDLS UNKNOWN discover ");
823 tdls_vdev->curr_candidate = curr_peer;
824 tdls_implicit_send_discovery_request(tdls_vdev);
825 } else {
826 curr_peer->tdls_support = TDLS_CAP_NOT_SUPPORTED;
827 tdls_set_peer_link_status(
828 curr_peer,
829 TDLS_LINK_IDLE,
830 TDLS_LINK_NOT_SUPPORTED);
831 }
832 }
833}
834
835/**
836 * tdls_ct_process_peers() - process the peer
837 * @curr_peer: tdls peer needs to be examined
838 * @tdls_vdev_obj: tdls vdev object
839 * @tdls_soc_obj: tdls soc object
840 *
841 * This function check the peer capability and process the metadata from
842 * the peer
843 *
844 * Return: None
845 */
846static void tdls_ct_process_peers(struct tdls_peer *curr_peer,
847 struct tdls_vdev_priv_obj *tdls_vdev_obj,
848 struct tdls_soc_priv_obj *tdls_soc_obj)
849{
Dustin Brown759661d2018-01-25 11:46:31 -0800850 tdls_debug(QDF_MAC_ADDR_STR " link_status %d tdls_support %d",
Kabilan Kannan00619ab2017-03-20 01:59:24 -0700851 QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes),
852 curr_peer->link_status, curr_peer->tdls_support);
853
854 switch (curr_peer->tdls_support) {
855 case TDLS_CAP_SUPPORTED:
856 tdls_ct_process_cap_supported(curr_peer, tdls_vdev_obj,
857 tdls_soc_obj);
858 break;
859
860 case TDLS_CAP_UNKNOWN:
861 tdls_ct_process_cap_unknown(curr_peer, tdls_vdev_obj,
862 tdls_soc_obj);
863 break;
864 default:
865 break;
866 }
867
868}
869
870static void tdls_ct_process_handler(struct wlan_objmgr_vdev *vdev)
871{
872 int i;
873 qdf_list_t *head;
874 qdf_list_node_t *list_node;
875 struct tdls_peer *curr_peer;
876 QDF_STATUS status;
877 struct tdls_vdev_priv_obj *tdls_vdev_obj;
878 struct tdls_soc_priv_obj *tdls_soc_obj;
879
880 if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj,
881 &tdls_soc_obj))
882 return;
883
884 /* If any concurrency is detected */
885 if (!tdls_soc_obj->enable_tdls_connection_tracker) {
886 tdls_notice("Connection tracker is disabled");
887 return;
888 }
889
890 /* Update tx rx traffic sample in tdls data structures */
891 tdls_ct_sampling_tx_rx(tdls_vdev_obj, tdls_soc_obj);
892
893 for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
894 head = &tdls_vdev_obj->peer_list[i];
895 status = qdf_list_peek_front(head, &list_node);
896 while (QDF_IS_STATUS_SUCCESS(status)) {
897 curr_peer = qdf_container_of(list_node,
898 struct tdls_peer, node);
899 tdls_ct_process_peers(curr_peer, tdls_vdev_obj,
900 tdls_soc_obj);
901 curr_peer->tx_pkt = 0;
902 curr_peer->rx_pkt = 0;
903 status = qdf_list_peek_next(head,
904 list_node, &list_node);
905 }
906 }
907
908 tdls_timer_restart(tdls_vdev_obj->vdev,
909 &tdls_vdev_obj->peer_update_timer,
910 tdls_vdev_obj->threshold_config.tx_period_t);
911
912}
913
914void tdls_ct_handler(void *user_data)
915{
916 struct wlan_objmgr_vdev *vdev;
917
918 if (!user_data)
919 return;
920
921 vdev = (struct wlan_objmgr_vdev *)user_data;
922
923 if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(vdev,
924 WLAN_TDLS_NB_ID))
925 return;
926
927 tdls_ct_process_handler(vdev);
928
929 wlan_objmgr_vdev_release_ref(vdev,
930 WLAN_TDLS_NB_ID);
931}
932
Kabilan Kannance5880e2017-04-17 21:53:42 -0700933int tdls_set_tdls_offchannel(struct tdls_soc_priv_obj *tdls_soc,
934 int offchannel)
935{
936 uint32_t tdls_feature_flags;
937
938 tdls_feature_flags = tdls_soc->tdls_configs.tdls_feature_flags;
939
940 if (TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) &&
941 (TDLS_SUPPORT_EXP_TRIG_ONLY == tdls_soc->tdls_current_mode ||
942 TDLS_SUPPORT_IMP_MODE == tdls_soc->tdls_current_mode ||
943 TDLS_SUPPORT_EXT_CONTROL == tdls_soc->tdls_current_mode)) {
944 if (offchannel < TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN ||
945 offchannel > TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX) {
946 tdls_err("Invalid tdls off channel %u", offchannel);
947 return -EINVAL;
948 }
949 } else {
950 tdls_err("Either TDLS or TDLS Off-channel is not enabled");
Bala Venkatesh5304ace2018-08-30 15:28:14 +0530951 return -ENOTSUPP;
Kabilan Kannance5880e2017-04-17 21:53:42 -0700952 }
953 tdls_notice("change tdls off channel from %d to %d",
954 tdls_soc->tdls_off_channel, offchannel);
955 tdls_soc->tdls_off_channel = offchannel;
956 return 0;
957}
958
Kabilan Kannance5880e2017-04-17 21:53:42 -0700959int tdls_set_tdls_secoffchanneloffset(struct tdls_soc_priv_obj *tdls_soc,
960 int offchanoffset)
961{
962 uint32_t tdls_feature_flags;
963
964 tdls_feature_flags = tdls_soc->tdls_configs.tdls_feature_flags;
965
966 if (!TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) ||
967 TDLS_SUPPORT_SUSPENDED >= tdls_soc->tdls_current_mode) {
968 tdls_err("Either TDLS or TDLS Off-channel is not enabled");
969 return -ENOTSUPP;
970 }
971
Rachit Kankane21a51732018-11-02 15:14:44 +0530972 tdls_soc->tdls_channel_offset = BW_INVALID;
Kabilan Kannance5880e2017-04-17 21:53:42 -0700973
974 switch (offchanoffset) {
975 case TDLS_SEC_OFFCHAN_OFFSET_0:
Bala Venkatesha105eee2018-10-03 10:51:38 +0530976 tdls_soc->tdls_channel_offset = BW20;
Kabilan Kannance5880e2017-04-17 21:53:42 -0700977 break;
978 case TDLS_SEC_OFFCHAN_OFFSET_40PLUS:
Bala Venkatesh36c69752019-08-20 18:32:03 +0530979 tdls_soc->tdls_channel_offset = BW40_HIGH_PRIMARY;
Bala Venkatesha105eee2018-10-03 10:51:38 +0530980 break;
Kabilan Kannance5880e2017-04-17 21:53:42 -0700981 case TDLS_SEC_OFFCHAN_OFFSET_40MINUS:
Bala Venkatesha105eee2018-10-03 10:51:38 +0530982 tdls_soc->tdls_channel_offset = BW40_LOW_PRIMARY;
Kabilan Kannance5880e2017-04-17 21:53:42 -0700983 break;
984 case TDLS_SEC_OFFCHAN_OFFSET_80:
Bala Venkatesha105eee2018-10-03 10:51:38 +0530985 tdls_soc->tdls_channel_offset = BW80;
Kabilan Kannance5880e2017-04-17 21:53:42 -0700986 break;
987 case TDLS_SEC_OFFCHAN_OFFSET_160:
Bala Venkatesha105eee2018-10-03 10:51:38 +0530988 tdls_soc->tdls_channel_offset = BWALL;
Kabilan Kannance5880e2017-04-17 21:53:42 -0700989 break;
990 default:
991 tdls_err("Invalid tdls secondary off channel offset %d",
992 offchanoffset);
993 return -EINVAL;
994 } /* end switch */
995
996 tdls_notice("change tdls secondary off channel offset to 0x%x",
997 tdls_soc->tdls_channel_offset);
998 return 0;
999}
1000
Kabilan Kannance5880e2017-04-17 21:53:42 -07001001int tdls_set_tdls_offchannelmode(struct wlan_objmgr_vdev *vdev,
1002 int offchanmode)
1003{
1004 struct tdls_peer *conn_peer = NULL;
1005 struct tdls_channel_switch_params chan_switch_params;
1006 QDF_STATUS status = QDF_STATUS_E_FAILURE;
1007 int ret_value = 0;
1008 struct tdls_vdev_priv_obj *tdls_vdev;
1009 struct tdls_soc_priv_obj *tdls_soc;
1010 uint32_t tdls_feature_flags;
1011
1012
1013 status = tdls_get_vdev_objects(vdev, &tdls_vdev, &tdls_soc);
1014
1015 if (status != QDF_STATUS_SUCCESS)
1016 return -EINVAL;
1017
1018
1019 if (offchanmode < ENABLE_CHANSWITCH ||
1020 offchanmode > DISABLE_CHANSWITCH) {
1021 tdls_err("Invalid tdls off channel mode %d", offchanmode);
1022 return -EINVAL;
1023 }
1024
Bala Venkatesh0f745452019-03-29 11:16:22 +05301025 if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) {
Kabilan Kannance5880e2017-04-17 21:53:42 -07001026 tdls_err("tdls off channel req in not associated state %d",
1027 offchanmode);
1028 return -EPERM;
1029 }
1030
1031 tdls_feature_flags = tdls_soc->tdls_configs.tdls_feature_flags;
1032 if (!TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) ||
1033 TDLS_SUPPORT_SUSPENDED >= tdls_soc->tdls_current_mode) {
1034 tdls_err("Either TDLS or TDLS Off-channel is not enabled");
1035 return -ENOTSUPP;
1036 }
1037
1038 conn_peer = tdls_find_first_connected_peer(tdls_vdev);
Jeff Johnsonbdc473f2019-03-18 13:45:10 -07001039 if (!conn_peer) {
Kabilan Kannance5880e2017-04-17 21:53:42 -07001040 tdls_err("No TDLS Connected Peer");
1041 return -EPERM;
1042 }
1043
1044 tdls_notice("TDLS Channel Switch in swmode=%d tdls_off_channel %d offchanoffset %d",
1045 offchanmode, tdls_soc->tdls_off_channel,
1046 tdls_soc->tdls_channel_offset);
1047
1048 switch (offchanmode) {
1049 case ENABLE_CHANSWITCH:
1050 if (tdls_soc->tdls_off_channel &&
Rachit Kankane21a51732018-11-02 15:14:44 +05301051 tdls_soc->tdls_channel_offset != BW_INVALID) {
Kabilan Kannance5880e2017-04-17 21:53:42 -07001052 chan_switch_params.tdls_off_ch =
1053 tdls_soc->tdls_off_channel;
1054 chan_switch_params.tdls_off_ch_bw_offset =
1055 tdls_soc->tdls_channel_offset;
1056 chan_switch_params.oper_class =
1057 tdls_find_opclass(tdls_soc->soc,
1058 chan_switch_params.tdls_off_ch,
1059 chan_switch_params.tdls_off_ch_bw_offset);
Bala Venkatesh36c69752019-08-20 18:32:03 +05301060 if (!chan_switch_params.oper_class) {
1061 if (chan_switch_params.tdls_off_ch_bw_offset ==
1062 BW40_HIGH_PRIMARY)
1063 chan_switch_params.oper_class =
1064 tdls_find_opclass(tdls_soc->soc,
1065 chan_switch_params.tdls_off_ch,
1066 BW40_LOW_PRIMARY);
1067 else if (chan_switch_params.
1068 tdls_off_ch_bw_offset ==
1069 BW40_LOW_PRIMARY)
1070 chan_switch_params.oper_class =
1071 tdls_find_opclass(tdls_soc->soc,
1072 chan_switch_params.tdls_off_ch,
1073 BW40_HIGH_PRIMARY);
1074 tdls_debug("oper_class:%d",
1075 chan_switch_params.oper_class);
1076 }
Kabilan Kannance5880e2017-04-17 21:53:42 -07001077 } else {
1078 tdls_err("TDLS off-channel parameters are not set yet!!!");
1079 return -EINVAL;
1080
1081 }
1082 break;
1083 case DISABLE_CHANSWITCH:
1084 chan_switch_params.tdls_off_ch = 0;
1085 chan_switch_params.tdls_off_ch_bw_offset = 0;
1086 chan_switch_params.oper_class = 0;
1087 break;
1088 default:
1089 tdls_err("Incorrect Parameters mode: %d tdls_off_channel: %d offchanoffset: %d",
1090 offchanmode, tdls_soc->tdls_off_channel,
1091 tdls_soc->tdls_channel_offset);
1092 return -EINVAL;
1093 } /* end switch */
1094
1095 chan_switch_params.vdev_id = tdls_vdev->session_id;
1096 chan_switch_params.tdls_sw_mode = offchanmode;
1097 chan_switch_params.is_responder =
1098 conn_peer->is_responder;
1099 qdf_mem_copy(&chan_switch_params.peer_mac_addr,
1100 &conn_peer->peer_mac.bytes,
1101 QDF_MAC_ADDR_SIZE);
Dustin Brown759661d2018-01-25 11:46:31 -08001102 tdls_notice("Peer " QDF_MAC_ADDR_STR " vdevId: %d, off channel: %d, offset: %d, mode: %d, is_responder: %d",
Kabilan Kannance5880e2017-04-17 21:53:42 -07001103 QDF_MAC_ADDR_ARRAY(chan_switch_params.peer_mac_addr),
1104 chan_switch_params.vdev_id,
1105 chan_switch_params.tdls_off_ch,
1106 chan_switch_params.tdls_off_ch_bw_offset,
1107 chan_switch_params.tdls_sw_mode,
1108 chan_switch_params.is_responder);
1109
1110 status = tdls_set_offchan_mode(tdls_soc->soc,
1111 &chan_switch_params);
1112
1113 if (status != QDF_STATUS_SUCCESS) {
1114 tdls_err("Failed to send channel switch request to wmi");
1115 return -EINVAL;
1116 }
1117
1118 tdls_soc->tdls_fw_off_chan_mode = offchanmode;
1119
1120 if (ENABLE_CHANSWITCH == offchanmode) {
1121 conn_peer = tdls_find_first_connected_peer(tdls_vdev);
Jeff Johnsonbdc473f2019-03-18 13:45:10 -07001122 if (!conn_peer) {
Kabilan Kannance5880e2017-04-17 21:53:42 -07001123 tdls_err("No TDLS Connected Peer");
1124 return -EPERM;
1125 }
1126 conn_peer->pref_off_chan_num =
1127 chan_switch_params.tdls_off_ch;
1128 conn_peer->op_class_for_pref_off_chan =
1129 chan_switch_params.oper_class;
1130 }
1131
1132 return ret_value;
1133}
1134
Frank Liuaf02af52018-10-24 15:08:00 +08001135static QDF_STATUS tdls_delete_all_tdls_peers_flush_cb(struct scheduler_msg *msg)
1136{
Frank Liu07c45b32018-11-16 11:41:20 +08001137 if (msg && msg->bodyptr) {
Frank Liuaf02af52018-10-24 15:08:00 +08001138 qdf_mem_free(msg->bodyptr);
Frank Liu07c45b32018-11-16 11:41:20 +08001139 msg->bodyptr = NULL;
1140 }
Frank Liuaf02af52018-10-24 15:08:00 +08001141
1142 return QDF_STATUS_SUCCESS;
1143}
Kabilan Kannance5880e2017-04-17 21:53:42 -07001144/**
1145 * tdls_delete_all_tdls_peers(): send request to delete tdls peers
1146 * @vdev: vdev object
1147 * @tdls_soc: tdls soc object
1148 *
1149 * This function sends request to lim to delete tdls peers
1150 *
1151 * Return: QDF_STATUS
1152 */
Kabilan Kannance5880e2017-04-17 21:53:42 -07001153QDF_STATUS tdls_delete_all_tdls_peers(struct wlan_objmgr_vdev *vdev,
1154 struct tdls_soc_priv_obj *tdls_soc)
1155{
1156 struct wlan_objmgr_peer *peer;
1157 struct tdls_del_all_tdls_peers *del_msg;
Kabilan Kannan1ac9c552017-04-20 10:33:39 -07001158 struct scheduler_msg msg = {0};
Kabilan Kannance5880e2017-04-17 21:53:42 -07001159 QDF_STATUS status;
1160
sheenam monga0b2054b2019-05-02 14:17:31 +05301161 peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_SB_ID);
1162 if (!peer) {
1163 tdls_err("bss peer is null");
Bala Venkatesh3b113c52019-03-18 13:37:13 +05301164 return QDF_STATUS_E_FAILURE;
sheenam monga0b2054b2019-05-02 14:17:31 +05301165 }
Kabilan Kannance5880e2017-04-17 21:53:42 -07001166
1167 del_msg = qdf_mem_malloc(sizeof(*del_msg));
Bala Venkatesh3b113c52019-03-18 13:37:13 +05301168 if (!del_msg) {
Kabilan Kannance5880e2017-04-17 21:53:42 -07001169 tdls_err("memory alloc failed");
Bala Venkatesh3b113c52019-03-18 13:37:13 +05301170 wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID);
Kabilan Kannance5880e2017-04-17 21:53:42 -07001171 return QDF_STATUS_E_FAILURE;
1172 }
1173
1174 qdf_mem_copy(del_msg->bssid.bytes,
1175 wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE);
1176
sheenam monga0b2054b2019-05-02 14:17:31 +05301177 wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID);
1178
Kabilan Kannance5880e2017-04-17 21:53:42 -07001179 del_msg->msg_type = tdls_soc->tdls_del_all_peers;
1180 del_msg->msg_len = (uint16_t) sizeof(*del_msg);
1181
1182 /* Send the request to PE. */
1183 qdf_mem_zero(&msg, sizeof(msg));
1184
1185 tdls_debug("sending delete all peers req to PE ");
1186
1187 msg.type = del_msg->msg_type;
1188 msg.bodyptr = del_msg;
Frank Liuaf02af52018-10-24 15:08:00 +08001189 msg.flush_callback = tdls_delete_all_tdls_peers_flush_cb;
Kabilan Kannance5880e2017-04-17 21:53:42 -07001190
gaurank kathpaliac5d02282018-08-28 19:50:21 +05301191 status = scheduler_post_message(QDF_MODULE_ID_TDLS,
1192 QDF_MODULE_ID_PE,
1193 QDF_MODULE_ID_PE, &msg);
Frank Liuaf02af52018-10-24 15:08:00 +08001194 if (QDF_IS_STATUS_ERROR(status)) {
1195 tdls_err("post delete all peer req failed, status %d", status);
1196 qdf_mem_free(del_msg);
1197 }
Kabilan Kannance5880e2017-04-17 21:53:42 -07001198
Kabilan Kannance5880e2017-04-17 21:53:42 -07001199 return status;
1200}
1201
1202void tdls_disable_offchan_and_teardown_links(
1203 struct wlan_objmgr_vdev *vdev)
1204{
1205 uint16_t connected_tdls_peers = 0;
1206 uint8_t staidx;
1207 struct tdls_peer *curr_peer = NULL;
1208 struct tdls_vdev_priv_obj *tdls_vdev;
1209 struct tdls_soc_priv_obj *tdls_soc;
1210 QDF_STATUS status;
Bala Venkatesh10a46e92018-09-06 14:38:13 +05301211 uint8_t vdev_id;
Bala Venkatesh223e9592018-10-29 14:47:43 +05301212 bool tdls_in_progress = false;
Kabilan Kannance5880e2017-04-17 21:53:42 -07001213
1214 status = tdls_get_vdev_objects(vdev, &tdls_vdev, &tdls_soc);
1215 if (QDF_STATUS_SUCCESS != status) {
1216 tdls_err("tdls objects are NULL ");
1217 return;
1218 }
1219
1220 if (TDLS_SUPPORT_SUSPENDED >= tdls_soc->tdls_current_mode) {
1221 tdls_notice("TDLS mode %d is disabled OR not suspended now",
1222 tdls_soc->tdls_current_mode);
1223 return;
1224 }
1225
1226 connected_tdls_peers = tdls_soc->connected_peer_count;
Bala Venkatesh223e9592018-10-29 14:47:43 +05301227 if (tdls_is_progress(tdls_vdev, NULL, 0))
1228 tdls_in_progress = true;
Kabilan Kannance5880e2017-04-17 21:53:42 -07001229
Bala Venkatesh223e9592018-10-29 14:47:43 +05301230 if (!(connected_tdls_peers || tdls_in_progress)) {
1231 tdls_notice("No TDLS connected/progress peers to delete");
Bala Venkatesh10a46e92018-09-06 14:38:13 +05301232 vdev_id = vdev->vdev_objmgr.vdev_id;
1233 if (tdls_soc->set_state_info.set_state_cnt > 0) {
1234 tdls_debug("Disable the tdls in FW as second interface is coming up");
1235 tdls_send_update_to_fw(tdls_vdev, tdls_soc, true,
1236 true, false, vdev_id);
1237 }
Kabilan Kannance5880e2017-04-17 21:53:42 -07001238 return;
1239 }
1240
1241 /* TDLS is not supported in case of concurrency.
1242 * Disable TDLS Offchannel in FW to avoid more
1243 * than two concurrent channels and generate TDLS
1244 * teardown indication to supplicant.
1245 * Below function Finds the first connected peer and
1246 * disables TDLS offchannel for that peer.
1247 * FW enables TDLS offchannel only when there is
1248 * one TDLS peer. When there are more than one TDLS peer,
1249 * there will not be TDLS offchannel in FW.
1250 * So to avoid sending multiple request to FW, for now,
1251 * just invoke offchannel mode functions only once
1252 */
1253 tdls_set_tdls_offchannel(tdls_soc,
1254 tdls_soc->tdls_configs.tdls_pre_off_chan_num);
1255 tdls_set_tdls_secoffchanneloffset(tdls_soc,
1256 TDLS_SEC_OFFCHAN_OFFSET_40PLUS);
1257 tdls_set_tdls_offchannelmode(vdev, DISABLE_CHANSWITCH);
1258
1259 /* Send Msg to PE for deleting all the TDLS peers */
1260 tdls_delete_all_tdls_peers(vdev, tdls_soc);
1261
1262 for (staidx = 0; staidx < tdls_soc->max_num_tdls_sta;
1263 staidx++) {
Yeshwanth Sriram Guntuka4ac15842019-07-16 15:47:21 +05301264 if (!tdls_soc->tdls_conn_info[staidx].valid_entry)
Kabilan Kannance5880e2017-04-17 21:53:42 -07001265 continue;
1266
1267 curr_peer = tdls_find_all_peer(tdls_soc,
1268 tdls_soc->tdls_conn_info[staidx].peer_mac.bytes);
1269 if (!curr_peer)
1270 continue;
1271
Yeshwanth Sriram Guntuka4ac15842019-07-16 15:47:21 +05301272 tdls_notice("indicate TDLS teardown %pM",
1273 curr_peer->peer_mac.bytes);
Kabilan Kannance5880e2017-04-17 21:53:42 -07001274
1275 /* Indicate teardown to supplicant */
1276 tdls_indicate_teardown(tdls_vdev,
1277 curr_peer,
1278 TDLS_TEARDOWN_PEER_UNSPEC_REASON);
1279
1280 /*
1281 * Del Sta happened already as part of tdls_delete_all_tdls_peers
1282 * Hence clear tdls vdev data structure.
1283 */
1284 tdls_reset_peer(tdls_vdev, curr_peer->peer_mac.bytes);
1285
Jeff Johnson31dade32018-03-01 15:31:35 -08001286 if (tdls_soc->tdls_dereg_peer)
1287 tdls_soc->tdls_dereg_peer(
1288 tdls_soc->tdls_peer_context,
1289 wlan_vdev_get_id(vdev),
Yeshwanth Sriram Guntuka4fb838c2019-08-02 18:28:33 +05301290 &curr_peer->peer_mac);
Kabilan Kannance5880e2017-04-17 21:53:42 -07001291 tdls_decrement_peer_count(tdls_soc);
Yeshwanth Sriram Guntuka4ac15842019-07-16 15:47:21 +05301292 tdls_soc->tdls_conn_info[staidx].valid_entry = false;
Kabilan Kannance5880e2017-04-17 21:53:42 -07001293 tdls_soc->tdls_conn_info[staidx].session_id = 255;
Bala Venkatesh2a773822019-02-04 19:52:27 +05301294 tdls_soc->tdls_conn_info[staidx].index =
1295 INVALID_TDLS_PEER_INDEX;
Kabilan Kannance5880e2017-04-17 21:53:42 -07001296
1297 qdf_mem_zero(&tdls_soc->tdls_conn_info[staidx].peer_mac,
1298 sizeof(struct qdf_mac_addr));
1299 }
1300}
1301
Bala Venkatesh9bb9c052019-05-27 14:16:40 +05301302void tdls_teardown_connections(struct wlan_objmgr_psoc *psoc)
Kabilan Kannance5880e2017-04-17 21:53:42 -07001303{
1304 struct tdls_osif_indication indication;
1305 struct tdls_soc_priv_obj *tdls_soc;
Bala Venkatesh9bb9c052019-05-27 14:16:40 +05301306 struct wlan_objmgr_vdev *tdls_vdev;
Kabilan Kannance5880e2017-04-17 21:53:42 -07001307
Kabilan Kannance5880e2017-04-17 21:53:42 -07001308
Bala Venkatesh9bb9c052019-05-27 14:16:40 +05301309 tdls_soc = wlan_psoc_get_tdls_soc_obj(psoc);
Kabilan Kannance5880e2017-04-17 21:53:42 -07001310 if (!tdls_soc)
1311 return;
1312
1313 /* Get the tdls specific vdev and clear the links */
Bala Venkatesh9bb9c052019-05-27 14:16:40 +05301314 tdls_vdev = tdls_get_vdev(psoc, WLAN_TDLS_SB_ID);
1315 if (!tdls_vdev) {
1316 tdls_err("Unable get the vdev");
1317 return;
Kabilan Kannance5880e2017-04-17 21:53:42 -07001318 }
Bala Venkatesh9bb9c052019-05-27 14:16:40 +05301319 tdls_disable_offchan_and_teardown_links(tdls_vdev);
Kabilan Kannance5880e2017-04-17 21:53:42 -07001320
Bala Venkatesh9bb9c052019-05-27 14:16:40 +05301321 indication.vdev = tdls_vdev;
Kabilan Kannance5880e2017-04-17 21:53:42 -07001322
1323 if (tdls_soc->tdls_event_cb)
1324 tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
1325 TDLS_EVENT_TEARDOWN_LINKS_DONE,
1326 &indication);
Bala Venkatesh9bb9c052019-05-27 14:16:40 +05301327 wlan_objmgr_vdev_release_ref(tdls_vdev, WLAN_TDLS_SB_ID);
Kabilan Kannance5880e2017-04-17 21:53:42 -07001328}