blob: 61781f13358bd94cc2fe6aff676e08d8ad16fc74 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Jeff Johnsonf1413bb2017-01-12 08:42:15 -08002 * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_tdls.c
30 *
31 * WLAN Host Device Driver implementation for TDLS
32 */
33
34#include <wlan_hdd_includes.h>
Archana Ramachandran2ad7de22016-04-22 16:53:25 -070035#include <ani_global.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080036#include <wlan_hdd_hostapd.h>
37#include <wlan_hdd_trace.h>
38#include <net/cfg80211.h>
39#include <linux/netdevice.h>
40#include <linux/skbuff.h>
41#include <linux/list.h>
42#include <linux/etherdevice.h>
43#include <net/ieee80211_radiotap.h>
44#include "wlan_hdd_tdls.h"
45#include "wlan_hdd_cfg80211.h"
46#include "cds_sched.h"
47#include "wma_types.h"
Kabilan Kannan36090ce2016-05-03 19:28:44 -070048#include "cds_concurrency.h"
Sandeep Puligillafdd201e2017-02-02 18:43:46 -080049#include <qca_vendor.h>
Kabilan Kannan36090ce2016-05-03 19:28:44 -070050
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080051
52static int32_t wlan_hdd_tdls_peer_reset_discovery_processed(tdlsCtx_t *
53 pHddTdlsCtx);
54static void wlan_hdd_tdls_timers_destroy(tdlsCtx_t *pHddTdlsCtx);
55int wpa_tdls_is_allowed_force_peer(tdlsCtx_t *pHddTdlsCtx, u8 *mac);
Kabilan Kannan36090ce2016-05-03 19:28:44 -070056static void wlan_hdd_tdls_ct_handler(void *user_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080057
Kabilan Kannand053aaf2016-10-26 02:06:14 -070058/**
59 * enum qca_wlan_vendor_tdls_trigger_mode_hdd_map: Maps the user space TDLS
60 * trigger mode in the host driver.
61 * @WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: TDLS Connection and
62 * disconnection handled by user space.
63 * @WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: TDLS connection and
64 * disconnection controlled by host driver based on data traffic.
65 * @WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: TDLS connection and
66 * disconnection jointly controlled by user space and host driver.
67 */
68enum qca_wlan_vendor_tdls_trigger_mode_hdd_map {
69 WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT =
70 QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT,
71 WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT =
72 QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT,
73 WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL =
74 ((QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT |
75 QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT) << 1),
76};
77
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +053078/*
79 * wlan_hdd_tdls_determine_channel_opclass() - determine channel and opclass
80 * @hddctx: pointer to hdd context
81 * @adapter: pointer to adapter
82 * @curr_peer: pointer to current tdls peer
83 * @channel: pointer to channel
84 * @opclass: pointer to opclass
85 *
86 * Function determines the channel and operating class
87 *
88 * Return: None
89 */
90static void wlan_hdd_tdls_determine_channel_opclass(hdd_context_t *hddctx,
91 hdd_adapter_t *adapter, hddTdlsPeer_t *curr_peer,
92 uint32_t *channel, uint32_t *opclass)
93{
94 hdd_station_ctx_t *hdd_sta_ctx;
95
96 /*
97 * If tdls offchannel is not enabled then we provide base channel
98 * and in that case pass opclass as 0 since opclass is mainly needed
99 * for offchannel cases.
100 */
101 if (!(hddctx->config->fEnableTDLSOffChannel) ||
102 (hddctx->tdls_fw_off_chan_mode != ENABLE_CHANSWITCH)) {
103 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
104 *channel = hdd_sta_ctx->conn_info.operationChannel;
105 *opclass = 0;
106 } else {
107 *channel = curr_peer->pref_off_chan_num;
108 *opclass = curr_peer->op_class_for_pref_off_chan;
109 }
Nitesh Shah82c52812016-12-27 12:27:51 +0530110 hdd_info("channel:%d opclass:%d", *channel, *opclass);
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +0530111}
112
Abhishek Singh4ef5fe02016-04-27 12:21:24 +0530113#ifdef FEATURE_WLAN_DIAG_SUPPORT
114/**
115 * hdd_send_wlan_tdls_teardown_event()- send TDLS teardown event
116 * @reason: reason for tear down.
117 * @peer_mac: peer mac
118 *
119 * This Function sends TDLS teardown diag event
120 *
121 * Return: void.
122 */
123void hdd_send_wlan_tdls_teardown_event(uint32_t reason,
124 uint8_t *peer_mac)
125{
126 WLAN_HOST_DIAG_EVENT_DEF(tdls_tear_down,
127 struct host_event_tdls_teardown);
128 qdf_mem_zero(&tdls_tear_down,
129 sizeof(tdls_tear_down));
130
131 tdls_tear_down.reason = reason;
132 qdf_mem_copy(tdls_tear_down.peer_mac, peer_mac, MAC_ADDR_LEN);
133 WLAN_HOST_DIAG_EVENT_REPORT(&tdls_tear_down,
134 EVENT_WLAN_TDLS_TEARDOWN);
135}
Abhishek Singh74bcb0a2016-04-27 12:30:48 +0530136
137/**
138 * hdd_wlan_tdls_enable_link_event()- send TDLS enable link event
139 * @peer_mac: peer mac
140 * @is_off_chan_supported: Does peer supports off chan
141 * @is_off_chan_configured: If off channel is configured
142 * @is_off_chan_established: If off chan is established
143 *
144 * This Function send TDLS enable link diag event
145 *
146 * Return: void.
147 */
148
149void hdd_wlan_tdls_enable_link_event(const uint8_t *peer_mac,
150 uint8_t is_off_chan_supported,
151 uint8_t is_off_chan_configured,
152 uint8_t is_off_chan_established)
153{
154 WLAN_HOST_DIAG_EVENT_DEF(tdls_event,
155 struct host_event_tdls_enable_link);
156
157 qdf_mem_copy(tdls_event.peer_mac,
158 peer_mac, MAC_ADDR_LEN);
159
160 tdls_event.is_off_chan_supported =
161 is_off_chan_supported;
162 tdls_event.is_off_chan_configured =
163 is_off_chan_configured;
164 tdls_event.is_off_chan_established =
165 is_off_chan_established;
166
167 WLAN_HOST_DIAG_EVENT_REPORT(&tdls_event,
168 EVENT_WLAN_TDLS_ENABLE_LINK);
169}
170
Abhishek Singhaf1d0c92016-04-27 13:46:59 +0530171/**
172 * hdd_wlan_block_scan_by_tdls_event()- send event
173 * if scan is blocked by tdls
174 *
175 * This Function send send diag event if scan is
176 * blocked by tdls
177 *
178 * Return: void.
179 */
180void hdd_wlan_block_scan_by_tdls_event(void)
181{
182 WLAN_HOST_DIAG_EVENT_DEF(tdls_scan_block_status,
183 struct host_event_tdls_scan_rejected);
184
185 tdls_scan_block_status.status = true;
186 WLAN_HOST_DIAG_EVENT_REPORT(&tdls_scan_block_status,
187 EVENT_TDLS_SCAN_BLOCK);
188}
189
Abhishek Singh4ef5fe02016-04-27 12:21:24 +0530190#endif
191
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800192/**
193 * wlan_hdd_tdls_hash_key() - calculate tdls hash key given mac address
194 * @mac: mac address
195 *
196 * Return: hash key
197 */
198static u8 wlan_hdd_tdls_hash_key(const u8 *mac)
199{
200 int i;
201 u8 key = 0;
202
203 for (i = 0; i < 6; i++)
204 key ^= mac[i];
205
206 return key;
207}
208
209/**
210 * wlan_hdd_tdls_disable_offchan_and_teardown_links - Disable offchannel
211 * and teardown TDLS links
212 * @hddCtx : pointer to hdd context
213 *
214 * Return: None
215 */
216void wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx)
217{
218 u16 connected_tdls_peers = 0;
219 u8 staidx;
220 hddTdlsPeer_t *curr_peer = NULL;
221 hdd_adapter_t *adapter = NULL;
222
223 if (eTDLS_SUPPORT_NOT_ENABLED == hddctx->tdls_mode) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -0700224 hdd_notice("TDLS mode is disabled OR not enabled in FW");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800225 return ;
226 }
227
Krunal Sonif07bb382016-03-10 13:02:11 -0800228 adapter = hdd_get_adapter(hddctx, QDF_STA_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800229
230 if (adapter == NULL) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -0700231 hdd_err("Station Adapter Not Found");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800232 return;
233 }
234
235 connected_tdls_peers = wlan_hdd_tdls_connected_peers(adapter);
236
237 if (!connected_tdls_peers)
238 return ;
239
240 /* TDLS is not supported in case of concurrency.
241 * Disable TDLS Offchannel in FW to avoid more
242 * than two concurrent channels and generate TDLS
243 * teardown indication to supplicant.
244 * Below function Finds the first connected peer and
245 * disables TDLS offchannel for that peer.
246 * FW enables TDLS offchannel only when there is
247 * one TDLS peer. When there are more than one TDLS peer,
248 * there will not be TDLS offchannel in FW.
249 * So to avoid sending multiple request to FW, for now,
250 * just invoke offchannel mode functions only once
251 */
252 hdd_set_tdls_offchannel(hddctx, hddctx->config->fTDLSPrefOffChanNum);
253 hdd_set_tdls_secoffchanneloffset(hddctx,
254 TDLS_SEC_OFFCHAN_OFFSET_40PLUS);
255 hdd_set_tdls_offchannelmode(adapter, DISABLE_CHANSWITCH);
256
257 for (staidx = 0; staidx < hddctx->max_num_tdls_sta;
258 staidx++) {
259 if (!hddctx->tdlsConnInfo[staidx].staId)
260 continue;
261
262 curr_peer = wlan_hdd_tdls_find_all_peer(hddctx,
263 hddctx->tdlsConnInfo[staidx].peerMac.bytes);
264
265 if (!curr_peer)
266 continue;
267
Kabilan Kannan38ff9f32016-08-25 14:51:14 -0700268 hdd_notice("indicate TDLS teardown (staId %d)",
269 curr_peer->staId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800270
271 wlan_hdd_tdls_indicate_teardown(
272 curr_peer->pHddTdlsCtx->pAdapter,
273 curr_peer,
274 eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON);
Abhishek Singh4ef5fe02016-04-27 12:21:24 +0530275 hdd_send_wlan_tdls_teardown_event(eTDLS_TEARDOWN_CONCURRENCY,
276 curr_peer->peerMac);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800277 }
278}
279
280/**
281 * hdd_tdls_notify_mode_change - Notify mode change
282 * @adapter: pointer to hdd adapter
283 * @hddCtx : pointer to hdd context
284 *
285 * Return: None
286 */
287void hdd_tdls_notify_mode_change(hdd_adapter_t *adapter, hdd_context_t *hddctx)
288{
Kabilan Kannan5ce85b82017-01-23 19:53:30 -0800289 /*
290 * Disable tdls connection tracker, when interface
291 * change happens in the system.
292 */
293 mutex_lock(&hddctx->tdls_lock);
294 hddctx->enable_tdls_connection_tracker = false;
295 mutex_unlock(&hddctx->tdls_lock);
Kabilan Kannane7a00112016-07-09 09:13:35 -0700296 wlan_hdd_tdls_disable_offchan_and_teardown_links(hddctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800297}
298
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800299/**
Nitesh Shah983e8f52016-11-25 12:36:29 +0530300 * wlan_hdd_tdls_discovery_sent_cnt() - get value of discovery counter sent
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800301 * @pHddCtx: HDD context
302 *
303 * Return: the value of the transmitted TDLS discovery counter
304 */
305static uint32_t wlan_hdd_tdls_discovery_sent_cnt(hdd_context_t *pHddCtx)
306{
307 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
308 hdd_adapter_t *pAdapter = NULL;
309 tdlsCtx_t *pHddTdlsCtx = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530310 QDF_STATUS status = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800311 uint32_t count = 0;
312
313 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530314 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800315 pAdapter = pAdapterNode->pAdapter;
316
317 pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
318 if (NULL != pHddTdlsCtx) {
319 count = count + pHddTdlsCtx->discovery_sent_cnt;
320 }
321 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
322 pAdapterNode = pNext;
323 }
324 return count;
325}
326
327/**
328 * wlan_hdd_tdls_check_power_save_prohibited() - set/clear proper TDLS power
329 * save probihited bit
330 * @pAdapter: HDD adapter handle
331 *
332 * Ensure TDLS power save probihited bit is set/cleared properly
333 *
334 * Return: None
335 */
336static void wlan_hdd_tdls_check_power_save_prohibited(hdd_adapter_t *pAdapter)
337{
c_hpothud5009242016-08-18 12:10:36 +0530338 tdlsCtx_t *pHddTdlsCtx;
339 hdd_context_t *pHddCtx;
340
341 if ((NULL == pAdapter) ||
342 (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
343 hdd_err("invalid pAdapter: %p", pAdapter);
344 return;
345 }
346
347 pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
348 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800349
350 if ((NULL == pHddTdlsCtx) || (NULL == pHddCtx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530351 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800352 FL("pHddCtx or pHddTdlsCtx points to NULL"));
353 return;
354 }
355
356 if ((0 == pHddCtx->connected_peer_count) &&
357 (0 == wlan_hdd_tdls_discovery_sent_cnt(pHddCtx))) {
358 sme_set_tdls_power_save_prohibited(WLAN_HDD_GET_HAL_CTX
359 (pHddTdlsCtx->pAdapter),
360 pAdapter->sessionId, 0);
361 return;
362 }
363 sme_set_tdls_power_save_prohibited(WLAN_HDD_GET_HAL_CTX
364 (pHddTdlsCtx->pAdapter),
365 pAdapter->sessionId, 1);
366 return;
367}
368
369/**
370 * wlan_hdd_tdls_free_scan_request() - free tdls scan request
371 * @tdls_scan_ctx: tdls scan context
372 *
373 * Return: None
374 */
375static void wlan_hdd_tdls_free_scan_request(tdls_scan_context_t *tdls_scan_ctx)
376{
377 if (NULL == tdls_scan_ctx) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530378 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800379 FL("tdls_scan_ctx is NULL"));
380 return;
381 }
382
383 tdls_scan_ctx->attempt = 0;
384 tdls_scan_ctx->reject = 0;
385 tdls_scan_ctx->magic = 0;
386 tdls_scan_ctx->scan_request = NULL;
387 return;
388}
389
390/**
391 * wlan_hdd_tdls_discovery_timeout_peer_cb() - tdls discovery timeout callback
392 * @userData: tdls context
393 *
394 * Return: None
395 */
396static void wlan_hdd_tdls_discovery_timeout_peer_cb(void *userData)
397{
398 int i;
399 struct list_head *head;
400 hddTdlsPeer_t *tmp;
401 struct list_head *pos, *q;
402 tdlsCtx_t *pHddTdlsCtx;
403 hdd_context_t *pHddCtx;
404
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530405 ENTER();
406
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800407 pHddTdlsCtx = (tdlsCtx_t *) userData;
408
409 if ((NULL == pHddTdlsCtx) || (NULL == pHddTdlsCtx->pAdapter)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530410 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800411 FL("pHddTdlsCtx or pAdapter points to NULL"));
412 return;
413 }
414
415 if (WLAN_HDD_ADAPTER_MAGIC != pHddTdlsCtx->pAdapter->magic) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -0700416 hdd_err("pAdapter has invalid magic");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800417 return;
418 }
419
420 pHddCtx = WLAN_HDD_GET_CTX(pHddTdlsCtx->pAdapter);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530421 if (0 != (wlan_hdd_validate_context(pHddCtx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800422 return;
423
424 mutex_lock(&pHddCtx->tdls_lock);
425
426 for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
427 head = &pHddTdlsCtx->peer_list[i];
428 list_for_each_safe(pos, q, head) {
429 tmp = list_entry(pos, hddTdlsPeer_t, node);
430 if (eTDLS_LINK_DISCOVERING == tmp->link_status) {
431 mutex_unlock(&pHddCtx->tdls_lock);
Kabilan Kannan38ff9f32016-08-25 14:51:14 -0700432 hdd_notice(MAC_ADDRESS_STR " to idle state",
433 MAC_ADDR_ARRAY(tmp->peerMac));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800434 wlan_hdd_tdls_set_peer_link_status(tmp,
435 eTDLS_LINK_IDLE,
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700436 eTDLS_LINK_NOT_SUPPORTED,
437 true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800438 mutex_lock(&pHddCtx->tdls_lock);
439 }
440 }
441 }
442
443 pHddTdlsCtx->discovery_sent_cnt = 0;
444 wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter);
445
446 mutex_unlock(&pHddCtx->tdls_lock);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530447 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800448 return;
449}
450
451/**
452 * wlan_hdd_tdls_free_list() - free TDLS peer list
453 * @pHddTdlsCtx: TDLS context
454 *
455 * Return: None
456 */
457static void wlan_hdd_tdls_free_list(tdlsCtx_t *pHddTdlsCtx)
458{
459 int i;
460 struct list_head *head;
461 hddTdlsPeer_t *tmp;
462 struct list_head *pos, *q;
463
464 if (NULL == pHddTdlsCtx) {
Anurag Chouhan05d124f2016-09-03 16:21:50 +0530465 hdd_notice("pHddTdlsCtx is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800466 return;
467 }
468 for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
469 head = &pHddTdlsCtx->peer_list[i];
470 list_for_each_safe(pos, q, head) {
471 tmp = list_entry(pos, hddTdlsPeer_t, node);
472 list_del(pos);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530473 qdf_mem_free(tmp);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474 tmp = NULL;
475 }
476 }
477}
478
479/**
480 * wlan_hdd_tdls_schedule_scan() - schedule scan for tdls
481 * @work: work_struct used to find tdls scan context
482 *
483 * Return: None
484 */
485static void wlan_hdd_tdls_schedule_scan(struct work_struct *work)
486{
487 tdls_scan_context_t *scan_ctx =
488 container_of(work, tdls_scan_context_t, tdls_scan_work.work);
489
490 if (NULL == scan_ctx) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530491 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800492 FL("scan_ctx is NULL"));
493 return;
494 }
495
496 if (unlikely(TDLS_CTX_MAGIC != scan_ctx->magic))
497 return;
498
499 scan_ctx->attempt++;
500
Nitesh Shah9ed1a9f2017-01-05 18:55:05 +0530501 wlan_hdd_cfg80211_tdls_scan(scan_ctx->wiphy,
502 scan_ctx->scan_request, scan_ctx->source);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800503}
504
505/**
506 * dump_tdls_state_param_setting() - print tdls state & parameters to send to fw
507 * @info: tdls setting to be sent to fw
508 *
509 * Return: void
510 */
511static void dump_tdls_state_param_setting(tdlsInfo_t *info)
512{
513 if (!info)
514 return;
515
Kabilan Kannan38ff9f32016-08-25 14:51:14 -0700516 hdd_notice("Setting tdls state and param in fw: vdev_id: %d, tdls_state: %d, notification_interval_ms: %d, tx_discovery_threshold: %d, tx_teardown_threshold: %d, rssi_teardown_threshold: %d, rssi_delta: %d, tdls_options: 0x%x, peer_traffic_ind_window: %d, peer_traffic_response_timeout: %d, puapsd_mask: 0x%x, puapsd_inactivity_time: %d, puapsd_rx_frame_threshold: %d, teardown_notification_ms: %d, tdls_peer_kickout_threshold: %d",
517 info->vdev_id,
518 info->tdls_state,
519 info->notification_interval_ms,
520 info->tx_discovery_threshold,
521 info->tx_teardown_threshold,
522 info->rssi_teardown_threshold,
523 info->rssi_delta,
524 info->tdls_options,
525 info->peer_traffic_ind_window,
526 info->peer_traffic_response_timeout,
527 info->puapsd_mask,
528 info->puapsd_inactivity_time,
529 info->puapsd_rx_frame_threshold,
530 info->teardown_notification_ms,
531 info->tdls_peer_kickout_threshold);
532
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800533}
534
535
536/**
537 * wlan_hdd_tdls_monitor_timers_stop() - stop all monitoring timers
538 * @hdd_tdls_ctx: TDLS context
539 *
540 * Return: none
541 */
542static void wlan_hdd_tdls_monitor_timers_stop(tdlsCtx_t *hdd_tdls_ctx)
543{
Anurag Chouhan210db072016-02-22 18:42:15 +0530544 qdf_mc_timer_stop(&hdd_tdls_ctx->peerDiscoveryTimeoutTimer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800545}
546
547/**
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700548 * wlan_hdd_tdls_peer_idle_timers_stop() - stop peer idle timers
549 * @hdd_tdls_ctx: TDLS context
550 *
551 * Loop through the idle peer list and stop their timers
552 *
553 * Return: None
554 */
555static void wlan_hdd_tdls_peer_idle_timers_stop(tdlsCtx_t *hdd_tdls_ctx)
556{
557 int i;
558 struct list_head *head;
559 struct list_head *pos;
560 hddTdlsPeer_t *curr_peer;
561
562 for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
563 head = &hdd_tdls_ctx->peer_list[i];
564 list_for_each(pos, head) {
565 curr_peer = list_entry(pos, hddTdlsPeer_t, node);
Kabilan Kannan989f4572016-08-04 18:14:25 -0700566 if (curr_peer->is_peer_idle_timer_initialised)
567 qdf_mc_timer_stop(&curr_peer->peer_idle_timer);
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700568 }
569 }
570}
571
572/**
573 * wlan_hdd_tdls_ct_timers_stop() - stop tdls connection tracker timers
574 * @hdd_tdls_ctx: TDLS context
575 *
576 * Return: None
577 */
578static void wlan_hdd_tdls_ct_timers_stop(tdlsCtx_t *hdd_tdls_ctx)
579{
580 qdf_mc_timer_stop(&hdd_tdls_ctx->peer_update_timer);
581 wlan_hdd_tdls_peer_idle_timers_stop(hdd_tdls_ctx);
582}
583
584/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800585 * wlan_hdd_tdls_timers_stop() - stop all the tdls timers running
586 * @hdd_tdls_ctx: TDLS context
587 *
588 * Return: none
589 */
590static void wlan_hdd_tdls_timers_stop(tdlsCtx_t *hdd_tdls_ctx)
591{
592 wlan_hdd_tdls_monitor_timers_stop(hdd_tdls_ctx);
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700593 wlan_hdd_tdls_ct_timers_stop(hdd_tdls_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800594}
595
596/**
597 * wlan_hdd_tdls_del_non_forced_peers() - delete non forced tdls peers
598 * @hdd_tdls_ctx: TDLS context
599 *
600 * Return: none
601 */
602static void wlan_hdd_tdls_del_non_forced_peers(tdlsCtx_t *hdd_tdls_ctx)
603{
604 struct list_head *head, *pos, *q;
605 hddTdlsPeer_t *peer = NULL;
606 int i;
607
608 /* remove entries from peer list only if peer is not forced */
609 for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
610 head = &hdd_tdls_ctx->peer_list[i];
611 list_for_each_safe(pos, q, head) {
612 peer = list_entry(pos, hddTdlsPeer_t, node);
613 if (false == peer->isForcedPeer) {
614 list_del(pos);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530615 qdf_mem_free(peer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800616 } else {
617 peer->link_status = eTDLS_LINK_IDLE;
618 peer->reason = eTDLS_LINK_UNSPECIFIED;
619 peer->staId = 0;
620 peer->discovery_attempt = 0;
621 }
622 }
623 }
624}
625
626/**
Prashanth Bhatta527fd752016-04-28 12:35:23 -0700627 * hdd_tdls_context_init() - Init TDLS context
Prashanth Bhattac2a16f62015-12-03 15:06:15 -0800628 * @hdd_ctx: HDD context
Nitesh Shahd1266d72017-01-25 22:07:07 +0530629 * @ssr: SSR case
Prashanth Bhattac2a16f62015-12-03 15:06:15 -0800630 *
Prashanth Bhatta527fd752016-04-28 12:35:23 -0700631 * Initialize TDLS global context.
Prashanth Bhattac2a16f62015-12-03 15:06:15 -0800632 *
633 * Return: None
634 */
Nitesh Shahd1266d72017-01-25 22:07:07 +0530635void hdd_tdls_context_init(hdd_context_t *hdd_ctx, bool ssr)
Prashanth Bhattac2a16f62015-12-03 15:06:15 -0800636{
Kabilan Kannan4bd9f1e2016-11-14 01:49:50 -0800637 uint8_t sta_idx;
638
Nitesh Shahc9edcdd2017-02-01 17:58:12 +0530639 if (!ssr) {
640 mutex_init(&hdd_ctx->tdls_lock);
641 qdf_spinlock_create(&hdd_ctx->tdls_ct_spinlock);
642 }
Kabilan Kannan163fd0b2016-06-08 15:21:51 -0700643
644 /* initialize TDLS global context */
645 hdd_ctx->connected_peer_count = 0;
646 hdd_ctx->tdls_nss_switch_in_progress = false;
647 hdd_ctx->tdls_teardown_peers_cnt = 0;
648 hdd_ctx->tdls_scan_ctxt.magic = 0;
649 hdd_ctx->tdls_scan_ctxt.attempt = 0;
650 hdd_ctx->tdls_scan_ctxt.reject = 0;
Nitesh Shah9ed1a9f2017-01-05 18:55:05 +0530651 hdd_ctx->tdls_scan_ctxt.source = 0;
Kabilan Kannan163fd0b2016-06-08 15:21:51 -0700652 hdd_ctx->tdls_scan_ctxt.scan_request = NULL;
Kabilan Kannan163fd0b2016-06-08 15:21:51 -0700653 hdd_ctx->set_state_info.set_state_cnt = 0;
654 hdd_ctx->set_state_info.vdev_id = 0;
Kabilan Kannanff89f742016-08-15 18:14:10 -0700655 hdd_ctx->tdls_nss_teardown_complete = false;
656 hdd_ctx->tdls_nss_transition_mode = TDLS_NSS_TRANSITION_UNKNOWN;
Kabilan Kannan163fd0b2016-06-08 15:21:51 -0700657
Kabilan Kannan8657a7e2017-01-25 01:16:05 -0800658 if (false == hdd_ctx->config->fEnableTDLSImplicitTrigger) {
659 hdd_ctx->tdls_mode = eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY;
660 hdd_notice("TDLS Implicit trigger not enabled!");
661 } else if (true == hdd_ctx->config->fTDLSExternalControl) {
662 hdd_ctx->tdls_mode = eTDLS_SUPPORT_EXTERNAL_CONTROL;
663 } else {
664 hdd_ctx->tdls_mode = eTDLS_SUPPORT_ENABLED;
665 }
666
667 hdd_ctx->tdls_mode_last = hdd_ctx->tdls_mode;
668
Kabilan Kannan4bd9f1e2016-11-14 01:49:50 -0800669 if (hdd_ctx->config->fEnableTDLSSleepSta ||
670 hdd_ctx->config->fEnableTDLSBufferSta ||
671 hdd_ctx->config->fEnableTDLSOffChannel)
672 hdd_ctx->max_num_tdls_sta = HDD_MAX_NUM_TDLS_STA_P_UAPSD_OFFCHAN;
673 else
674 hdd_ctx->max_num_tdls_sta = HDD_MAX_NUM_TDLS_STA;
675
676 hdd_notice("max_num_tdls_sta: %d", hdd_ctx->max_num_tdls_sta);
677
678 for (sta_idx = 0; sta_idx < hdd_ctx->max_num_tdls_sta; sta_idx++) {
679 hdd_ctx->tdlsConnInfo[sta_idx].staId = 0;
680 hdd_ctx->tdlsConnInfo[sta_idx].sessionId = 255;
681 qdf_mem_zero(&hdd_ctx->tdlsConnInfo[sta_idx].peerMac,
682 QDF_MAC_ADDR_SIZE);
683 }
684
Nitesh Shahd1266d72017-01-25 22:07:07 +0530685 /* Don't reset TDLS external peer count for SSR case */
686 if (!ssr)
687 hdd_ctx->tdls_external_peer_count = 0;
688
Kabilan Kannan163fd0b2016-06-08 15:21:51 -0700689 /* This flag will set be true, only when device operates in
690 * standalone STA mode
691 */
692 hdd_ctx->enable_tdls_connection_tracker = false;
693 hdd_ctx->concurrency_marked = false;
Prashanth Bhattac2a16f62015-12-03 15:06:15 -0800694}
695
696/**
Prashanth Bhatta527fd752016-04-28 12:35:23 -0700697 * hdd_tdls_context_destroy() - Destroy TDLS context
698 * @hdd_ctx: HDD context
699 *
700 * Destroy TDLS global context.
701 *
702 * Return: None
703 */
704void hdd_tdls_context_destroy(hdd_context_t *hdd_ctx)
705{
Kabilan Kannan163fd0b2016-06-08 15:21:51 -0700706 hdd_ctx->tdls_external_peer_count = 0;
707 hdd_ctx->concurrency_marked = false;
708 hdd_ctx->enable_tdls_connection_tracker = false;
Prashanth Bhatta527fd752016-04-28 12:35:23 -0700709 mutex_destroy(&hdd_ctx->tdls_lock);
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700710 qdf_spinlock_destroy(&hdd_ctx->tdls_ct_spinlock);
Prashanth Bhatta527fd752016-04-28 12:35:23 -0700711}
712
713/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800714 * wlan_hdd_tdls_init() - tdls initializaiton
715 * @pAdapter: hdd adapter
716 *
717 * Return: 0 for success or negative errno otherwise
718 */
719int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter)
720{
721 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
722 tdlsCtx_t *pHddTdlsCtx;
723 int i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800724
725 if (NULL == pHddCtx)
726 return -EINVAL;
727
Kabilan Kannan163fd0b2016-06-08 15:21:51 -0700728 ENTER();
729
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800730 mutex_lock(&pHddCtx->tdls_lock);
731
732 if (false == pHddCtx->config->fEnableTDLSSupport) {
733 pHddCtx->tdls_mode = eTDLS_SUPPORT_NOT_ENABLED;
734 pAdapter->sessionCtx.station.pHddTdlsCtx = NULL;
735 mutex_unlock(&pHddCtx->tdls_lock);
Kabilan Kannan38ff9f32016-08-25 14:51:14 -0700736 hdd_err("TDLS not enabled (%d) or FW doesn't support",
737 pHddCtx->config->fEnableTDLSSupport);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800738 return 0;
739 }
740 /* TDLS is supported only in STA / P2P Client modes,
741 * hence the check for TDLS support in a specific Device mode.
742 * Do not return a failure rather do not continue further
743 * with the initialization as tdls_init would be called
744 * during the open adapter for a p2p interface at which point
745 * the device mode would be a P2P_DEVICE. The point here is to
746 * continue initialization for STA / P2P Client modes.
747 * TDLS exit also check for the device mode for clean up hence
748 * there is no issue even if success is returned.
749 */
750 if (0 == WLAN_HDD_IS_TDLS_SUPPORTED_ADAPTER(pAdapter)) {
751 mutex_unlock(&pHddCtx->tdls_lock);
Kabilan Kannan05da3682017-02-06 19:01:33 -0800752 /* Check whether connection tracker can be enabled in
753 * the system.
754 */
755 if (pAdapter->device_mode == QDF_P2P_DEVICE_MODE)
756 cds_set_tdls_ct_mode(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800757 return 0;
758 }
759 /* Check for the valid pHddTdlsCtx. If valid do not further
760 * allocate the memory, rather continue with the initialization.
761 * If tdls_initialization would get reinvoked without tdls_exit
762 * getting invoked (SSR) there is no point to further proceed
763 * with the memory allocations.
764 */
765 if (NULL == pAdapter->sessionCtx.station.pHddTdlsCtx) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530766 pHddTdlsCtx = qdf_mem_malloc(sizeof(tdlsCtx_t));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800767
768 if (NULL == pHddTdlsCtx) {
769 pAdapter->sessionCtx.station.pHddTdlsCtx = NULL;
770 mutex_unlock(&pHddCtx->tdls_lock);
Kabilan Kannan38ff9f32016-08-25 14:51:14 -0700771 hdd_err("malloc failed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800772 return -ENOMEM;
773 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800774
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700775 /* Initialize connection tracker timer */
776 qdf_mc_timer_init(&pHddTdlsCtx->peer_update_timer,
777 QDF_TIMER_TYPE_SW,
778 wlan_hdd_tdls_ct_handler,
779 pAdapter);
Anurag Chouhan210db072016-02-22 18:42:15 +0530780 qdf_mc_timer_init(&pHddTdlsCtx->peerDiscoveryTimeoutTimer,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530781 QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800782 wlan_hdd_tdls_discovery_timeout_peer_cb,
783 pHddTdlsCtx);
784
785 pAdapter->sessionCtx.station.pHddTdlsCtx = pHddTdlsCtx;
786 for (i = 0; i < TDLS_PEER_LIST_SIZE; i++)
787 INIT_LIST_HEAD(&pHddTdlsCtx->peer_list[i]);
788 } else {
789 pHddTdlsCtx = pAdapter->sessionCtx.station.pHddTdlsCtx;
790
791 wlan_hdd_tdls_timers_stop(pHddTdlsCtx);
792
793 wlan_hdd_tdls_del_non_forced_peers(pHddTdlsCtx);
794
Nitesh Shahd1266d72017-01-25 22:07:07 +0530795 hdd_tdls_context_init(pHddCtx, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800796 }
797
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800798 sme_set_tdls_power_save_prohibited(WLAN_HDD_GET_HAL_CTX(pAdapter),
799 pAdapter->sessionId, 0);
800
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800801 pHddTdlsCtx->pAdapter = pAdapter;
802
803 pHddTdlsCtx->curr_candidate = NULL;
804 pHddTdlsCtx->magic = 0;
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700805 pHddTdlsCtx->valid_mac_entries = 0;
Nitesh Shah98097b92016-12-28 17:16:58 +0530806 pHddTdlsCtx->last_flush_ts = 0;
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700807
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800808 /* remember configuration even if it is not used right now. it could be used later */
809 pHddTdlsCtx->threshold_config.tx_period_t =
810 pHddCtx->config->fTDLSTxStatsPeriod;
811 pHddTdlsCtx->threshold_config.tx_packet_n =
812 pHddCtx->config->fTDLSTxPacketThreshold;
813 pHddTdlsCtx->threshold_config.discovery_tries_n =
814 pHddCtx->config->fTDLSMaxDiscoveryAttempt;
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700815 pHddTdlsCtx->threshold_config.idle_timeout_t =
816 pHddCtx->config->tdls_idle_timeout;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800817 pHddTdlsCtx->threshold_config.idle_packet_n =
818 pHddCtx->config->fTDLSIdlePacketThreshold;
819 pHddTdlsCtx->threshold_config.rssi_trigger_threshold =
820 pHddCtx->config->fTDLSRSSITriggerThreshold;
821 pHddTdlsCtx->threshold_config.rssi_teardown_threshold =
822 pHddCtx->config->fTDLSRSSITeardownThreshold;
823 pHddTdlsCtx->threshold_config.rssi_delta =
824 pHddCtx->config->fTDLSRSSIDelta;
825
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800826 INIT_DELAYED_WORK(&pHddCtx->tdls_scan_ctxt.tdls_scan_work,
827 wlan_hdd_tdls_schedule_scan);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800828
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800829 mutex_unlock(&pHddCtx->tdls_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800830
Kabilan Kannan4446ddd2016-08-04 18:47:23 -0700831 if (pHddCtx->config->fEnableTDLSOffChannel)
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +0530832 pHddCtx->tdls_fw_off_chan_mode = ENABLE_CHANSWITCH;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800833
Kabilan Kannan163fd0b2016-06-08 15:21:51 -0700834 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800835 return 0;
836}
837
838/**
839 * wlan_hdd_tdls_exit() - TDLS de-initialization
840 * @pAdapter: HDD adapter
841 *
842 * Return: None
843 */
844void wlan_hdd_tdls_exit(hdd_adapter_t *pAdapter)
845{
846 tdlsCtx_t *pHddTdlsCtx;
847 hdd_context_t *pHddCtx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800848
Kabilan Kannan163fd0b2016-06-08 15:21:51 -0700849 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800850 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
851 if (!pHddCtx) {
Agrawal Ashish81f3cd42015-09-16 16:35:13 +0530852 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800853 FL("pHddCtx is NULL"));
854 return;
855 }
856
857 if (!test_bit(TDLS_INIT_DONE, &pAdapter->event_flags)) {
Anurag Chouhan05d124f2016-09-03 16:21:50 +0530858 hdd_info("TDLS init was not done, exit");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800859 return;
860 }
861
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800862 cds_flush_delayed_work(&pHddCtx->tdls_scan_ctxt.tdls_scan_work);
863
864 mutex_lock(&pHddCtx->tdls_lock);
865
Masti, Narayanraddi27fbec72016-09-14 16:36:37 +0530866 pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
867 if (NULL == pHddTdlsCtx) {
868 /*
869 * TDLS context can be null and might have been freed up during
870 * cleanup for STA adapter
871 */
872 mutex_unlock(&pHddCtx->tdls_lock);
873
874 hdd_info("pHddTdlsCtx is NULL, adapter device mode: %s(%d)",
875 hdd_device_mode_to_string(pAdapter->device_mode),
876 pAdapter->device_mode);
877 goto done;
878 }
879
Jeff Johnsonf1413bb2017-01-12 08:42:15 -0800880 /*
881 * must stop timer here before freeing peer list, because
882 * peerIdleTimer is part of peer list structure.
883 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800884 wlan_hdd_tdls_timers_destroy(pHddTdlsCtx);
885 wlan_hdd_tdls_free_list(pHddTdlsCtx);
886
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800887 wlan_hdd_tdls_free_scan_request(&pHddCtx->tdls_scan_ctxt);
888
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800889 pHddTdlsCtx->magic = 0;
890 pHddTdlsCtx->pAdapter = NULL;
Masti, Narayanraddi27fbec72016-09-14 16:36:37 +0530891 pAdapter->sessionCtx.station.pHddTdlsCtx = NULL;
892
893 mutex_unlock(&pHddCtx->tdls_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800894
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530895 qdf_mem_free(pHddTdlsCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800896done:
Kabilan Kannan163fd0b2016-06-08 15:21:51 -0700897 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800898 clear_bit(TDLS_INIT_DONE, &pAdapter->event_flags);
899}
900
901/**
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700902 * wlan_hdd_tdls_peer_idle_timers_destroy() - destroy peer idle timers
903 * @hdd_tdls_ctx: TDLS context
904 *
905 * Loop through the idle peer list and destroy their timers
906 *
907 * Return: None
908 */
909static void wlan_hdd_tdls_peer_idle_timers_destroy(tdlsCtx_t *hdd_tdls_ctx)
910{
911 int i;
912 struct list_head *head;
913 struct list_head *pos;
914 hddTdlsPeer_t *curr_peer;
915
916 for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
917 head = &hdd_tdls_ctx->peer_list[i];
918 list_for_each(pos, head) {
919 curr_peer = list_entry(pos, hddTdlsPeer_t, node);
Kabilan Kannan5aebaaa2017-01-23 19:40:57 -0800920 if (curr_peer != NULL &&
921 curr_peer->is_peer_idle_timer_initialised) {
922 hdd_info(MAC_ADDRESS_STR ": destroy idle timer",
923 MAC_ADDR_ARRAY(curr_peer->peerMac));
924 qdf_mc_timer_stop(&curr_peer->peer_idle_timer);
925 qdf_mc_timer_destroy(&curr_peer->peer_idle_timer);
926 }
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700927 }
928 }
929}
930
931/**
932 * wlan_hdd_tdls_ct_timers_destroy() - destroy tdls connection tracker timers
933 * @hdd_tdls_ctx: TDLS context
934 *
935 * Return: None
936 */
937static void wlan_hdd_tdls_ct_timers_destroy(tdlsCtx_t *hdd_tdls_ctx)
938{
939 qdf_mc_timer_stop(&hdd_tdls_ctx->peer_update_timer);
940 qdf_mc_timer_destroy(&hdd_tdls_ctx->peer_update_timer);
941 wlan_hdd_tdls_peer_idle_timers_destroy(hdd_tdls_ctx);
942}
943
944/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800945 * wlan_hdd_tdls_monitor_timers_destroy() - destroy all tdls monitoring timers
946 * @pHddTdlsCtx: TDLS context
947 *
948 * Return: Void
949 */
950static void wlan_hdd_tdls_monitor_timers_destroy(tdlsCtx_t *pHddTdlsCtx)
951{
Anurag Chouhan210db072016-02-22 18:42:15 +0530952 qdf_mc_timer_stop(&pHddTdlsCtx->peerDiscoveryTimeoutTimer);
953 qdf_mc_timer_destroy(&pHddTdlsCtx->peerDiscoveryTimeoutTimer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800954}
955
956/**
957 * wlan_hdd_tdls_timers_destroy() - Destroy all the tdls timers running
958 * @pHddTdlsCtx: TDLS Context
959 *
960 * Return: Void
961 */
962static void wlan_hdd_tdls_timers_destroy(tdlsCtx_t *pHddTdlsCtx)
963{
964 wlan_hdd_tdls_monitor_timers_destroy(pHddTdlsCtx);
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700965 wlan_hdd_tdls_ct_timers_destroy(pHddTdlsCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800966}
967
968/**
969 * wlan_hdd_tdls_get_peer() - find or add an peer given mac address
970 * @pAdapter: HDD adapter
971 * @mac: MAC address used to find or create peer
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700972 * @need_mutex_lock: flag identify whether mutex needed or not
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800973 *
974 * Search peer given an MAC address and create one if not found.
975 *
976 * Return: Pointer to peer if mac address exist or peer creation
977 * succeeds; NULL if peer creation fails
978 */
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700979hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, const u8 *mac,
980 bool need_mutex_lock)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800981{
982 struct list_head *head;
983 hddTdlsPeer_t *peer;
984 u8 key;
985 tdlsCtx_t *pHddTdlsCtx;
986 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
987
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530988 if (0 != (wlan_hdd_validate_context(pHddCtx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800989 return NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800990
991 /* if already there, just update */
Kabilan Kannan36090ce2016-05-03 19:28:44 -0700992 peer = wlan_hdd_tdls_find_peer(pAdapter, mac, need_mutex_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800993 if (peer != NULL) {
994 return peer;
995 }
996
997 /* not found, allocate and add the list */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530998 peer = qdf_mem_malloc(sizeof(hddTdlsPeer_t));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800999 if (NULL == peer) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001000 hdd_err("peer malloc failed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001001 return NULL;
1002 }
1003
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001004 if (need_mutex_lock)
1005 mutex_lock(&pHddCtx->tdls_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001006
1007 pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
1008
1009 if (NULL == pHddTdlsCtx) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301010 qdf_mem_free(peer);
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001011 if (need_mutex_lock)
1012 mutex_unlock(&pHddCtx->tdls_lock);
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001013 hdd_notice("pHddTdlsCtx is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001014 return NULL;
1015 }
1016
1017 key = wlan_hdd_tdls_hash_key(mac);
1018 head = &pHddTdlsCtx->peer_list[key];
1019
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301020 qdf_mem_copy(peer->peerMac, mac, sizeof(peer->peerMac));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001021 peer->pHddTdlsCtx = pHddTdlsCtx;
1022 peer->pref_off_chan_num = pHddCtx->config->fTDLSPrefOffChanNum;
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05301023 peer->op_class_for_pref_off_chan =
1024 wlan_hdd_find_opclass(pHddCtx->hHal, peer->pref_off_chan_num,
1025 pHddCtx->config->fTDLSPrefOffChanBandwidth);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001026
1027 list_add_tail(&peer->node, head);
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001028
1029 if (need_mutex_lock)
1030 mutex_unlock(&pHddCtx->tdls_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001031
1032 return peer;
1033}
1034
1035/**
1036 * wlan_hdd_tdls_set_cap() - set TDLS capability type
1037 * @pAdapter: HDD adapter
1038 * @mac: peer mac address
1039 * @cap: TDLS capability type
1040 *
1041 * Return: 0 if successful or negative errno otherwise
1042 */
1043int wlan_hdd_tdls_set_cap(hdd_adapter_t *pAdapter, const uint8_t *mac,
1044 tTDLSCapType cap)
1045{
1046 hddTdlsPeer_t *curr_peer;
1047
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001048 curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001049 if (curr_peer == NULL) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001050 hdd_err("curr_peer is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001051 return -EINVAL;
1052 }
1053
1054 curr_peer->tdls_support = cap;
1055
1056 return 0;
1057}
1058
1059/**
1060 * wlan_hdd_tdls_set_peer_link_status() - set TDLS peer link status
1061 * @curr_peer: peer
1062 * @status: status
1063 * @reason: reason
1064 *
1065 * Return: Void
1066 */
1067void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer,
1068 tTDLSLinkStatus status,
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001069 tTDLSLinkReason reason,
1070 bool lock_needed)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001071{
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05301072 uint32_t state = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001073 int32_t res = 0;
1074 hdd_context_t *pHddCtx;
1075 if (curr_peer == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301076 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001077 FL("curr_peer is NULL"));
1078 return;
1079 }
1080
1081 if (curr_peer->pHddTdlsCtx == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301082 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001083 FL("curr_peer->pHddTdlsCtx is NULL"));
1084 return;
1085 }
1086 pHddCtx = WLAN_HDD_GET_CTX(curr_peer->pHddTdlsCtx->pAdapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301087 if ((wlan_hdd_validate_context(pHddCtx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001088 return;
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001089 hdd_warn("tdls set peer " MAC_ADDRESS_STR " link status to %u",
1090 MAC_ADDR_ARRAY(curr_peer->peerMac), status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001091
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001092 if (lock_needed)
1093 mutex_lock(&pHddCtx->tdls_lock);
1094
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001095 curr_peer->link_status = status;
1096
1097 /* If TDLS link status is already passed the discovery state
1098 * then clear discovery attempt count
1099 */
1100 if (status >= eTDLS_LINK_DISCOVERED) {
1101 curr_peer->discovery_attempt = 0;
1102 }
1103
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001104 if (lock_needed)
1105 mutex_unlock(&pHddCtx->tdls_lock);
1106
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001107 if (curr_peer->isForcedPeer && curr_peer->state_change_notification) {
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05301108 uint32_t opclass;
1109 uint32_t channel;
1110
1111 hdd_adapter_t *adapter = curr_peer->pHddTdlsCtx->pAdapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001112 curr_peer->reason = reason;
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05301113
Nitesh Shah82c52812016-12-27 12:27:51 +05301114 hdd_info("Peer is forced and the reason:%d", reason);
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05301115 wlan_hdd_tdls_determine_channel_opclass(pHddCtx, adapter,
1116 curr_peer, &channel, &opclass);
1117
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001118 wlan_hdd_tdls_get_wifi_hal_state(curr_peer, &state, &res);
1119 (*curr_peer->state_change_notification)(curr_peer->peerMac,
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05301120 opclass, channel,
1121 state, res, adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001122 }
1123 return;
1124}
1125
1126/**
1127 * wlan_hdd_tdls_set_link_status() - set TDLS peer link status
1128 * @pAdapter: HDD adapter
1129 * @mac: mac address of TDLS peer
1130 * @linkStatus: status
1131 * @reason: reason
1132 *
1133 * Return: Void
1134 */
1135void wlan_hdd_tdls_set_link_status(hdd_adapter_t *pAdapter,
1136 const uint8_t *mac,
1137 tTDLSLinkStatus linkStatus,
1138 tTDLSLinkReason reason)
1139{
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05301140 uint32_t state = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001141 int32_t res = 0;
1142 hddTdlsPeer_t *curr_peer;
1143 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1144
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301145 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001146 return;
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301147
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001148 curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, true);
1149 if (curr_peer == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301150 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001151 FL("curr_peer is NULL"));
1152 return;
1153 }
1154
1155 mutex_lock(&pHddCtx->tdls_lock);
1156 curr_peer->link_status = linkStatus;
1157
1158 /* If TDLS link status is already passed the discovery state
1159 * then clear discovery attempt count
1160 */
1161 if (linkStatus >= eTDLS_LINK_DISCOVERED) {
1162 curr_peer->discovery_attempt = 0;
1163 }
1164 mutex_unlock(&pHddCtx->tdls_lock);
1165 if (curr_peer->isForcedPeer && curr_peer->state_change_notification) {
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05301166 uint32_t opclass;
1167 uint32_t channel;
1168 hdd_adapter_t *adapter = curr_peer->pHddTdlsCtx->pAdapter;
1169
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001170 curr_peer->reason = reason;
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05301171
1172 wlan_hdd_tdls_determine_channel_opclass(pHddCtx, adapter,
1173 curr_peer, &channel, &opclass);
1174
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001175 wlan_hdd_tdls_get_wifi_hal_state(curr_peer, &state, &res);
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05301176 (curr_peer->state_change_notification)(mac, opclass, channel,
1177 state, res, adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001178 }
1179
1180 return;
1181}
1182
1183/**
1184 * wlan_hdd_tdls_recv_discovery_resp() - handling of tdls discovery response
1185 * @pAdapter: HDD adapter
1186 * @mac: mac address of peer from which the response was received
1187 *
1188 * Return: 0 for success or negative errno otherwise
1189 */
1190int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter,
1191 const uint8_t *mac)
1192{
1193 hddTdlsPeer_t *curr_peer;
1194 tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
1195 hdd_context_t *pHddCtx;
1196
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301197 ENTER();
1198
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001199 if (NULL == pHddTdlsCtx) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001200 hdd_err("pHddTdlsCtx is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001201 return -EINVAL;
1202 }
1203
1204 pHddCtx = WLAN_HDD_GET_CTX(pHddTdlsCtx->pAdapter);
1205
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301206 if (0 != (wlan_hdd_validate_context(pHddCtx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001207 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001208
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001209 curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001210 if (NULL == curr_peer) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001211 hdd_err("curr_peer is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001212 return -EINVAL;
1213 }
1214
1215 if (pHddTdlsCtx->discovery_sent_cnt)
1216 pHddTdlsCtx->discovery_sent_cnt--;
1217
1218 mutex_lock(&pHddCtx->tdls_lock);
1219 wlan_hdd_tdls_check_power_save_prohibited(pAdapter);
1220
1221 mutex_unlock(&pHddCtx->tdls_lock);
1222 if (0 == pHddTdlsCtx->discovery_sent_cnt) {
Anurag Chouhan210db072016-02-22 18:42:15 +05301223 qdf_mc_timer_stop(&pHddTdlsCtx->peerDiscoveryTimeoutTimer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001224 }
1225
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001226 hdd_notice("Discovery(%u) Response from " MAC_ADDRESS_STR
1227 " link_status %d", pHddTdlsCtx->discovery_sent_cnt,
1228 MAC_ADDR_ARRAY(curr_peer->peerMac), curr_peer->link_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001229
1230 if (eTDLS_LINK_DISCOVERING == curr_peer->link_status) {
Jeff Johnsonf1413bb2017-01-12 08:42:15 -08001231 /* Since we are here, it means Throughput threshold is
1232 * already met. Make sure RSSI threshold is also met
1233 * before setting up TDLS link.
1234 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001235 if ((int32_t) curr_peer->rssi >
1236 (int32_t) pHddTdlsCtx->threshold_config.
1237 rssi_trigger_threshold) {
1238 wlan_hdd_tdls_set_peer_link_status(curr_peer,
1239 eTDLS_LINK_DISCOVERED,
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001240 eTDLS_LINK_SUCCESS,
1241 true);
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001242 hdd_notice("Rssi Threshold met: " MAC_ADDRESS_STR
1243 " rssi = %d threshold= %d",
1244 MAC_ADDR_ARRAY(curr_peer->peerMac),
1245 curr_peer->rssi,
1246 pHddTdlsCtx->threshold_config.rssi_trigger_threshold);
1247
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001248 cfg80211_tdls_oper_request(pAdapter->dev,
1249 curr_peer->peerMac,
1250 NL80211_TDLS_SETUP, false,
1251 GFP_KERNEL);
1252 } else {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001253 hdd_notice("Rssi Threshold not met: " MAC_ADDRESS_STR
1254 " rssi = %d threshold = %d ",
1255 MAC_ADDR_ARRAY(curr_peer->peerMac),
1256 curr_peer->rssi,
1257 pHddTdlsCtx->threshold_config.rssi_trigger_threshold);
1258
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001259 wlan_hdd_tdls_set_peer_link_status(curr_peer,
1260 eTDLS_LINK_IDLE,
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001261 eTDLS_LINK_UNSPECIFIED,
1262 true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001263
1264 /* if RSSI threshold is not met then allow further discovery
1265 * attempts by decrementing count for the last attempt
1266 */
1267 if (curr_peer->discovery_attempt)
1268 curr_peer->discovery_attempt--;
1269 }
1270 }
1271
1272 curr_peer->tdls_support = eTDLS_CAP_SUPPORTED;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301273 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001274 return 0;
1275}
1276
1277/**
1278 * wlan_hdd_tdls_set_peer_caps() - set TDLS peer capability
1279 * @pAdapter: HDD adapter
1280 * @mac: MAC address of the TDLS peer
1281 * @StaParams: CSR Station Parameter
1282 * @isBufSta: is peer buffer station
1283 * @isOffChannelSupported: Is off channel supported
Nitesh Shah99934ac2016-09-05 15:54:08 +05301284 * @is_qos_wmm_sta: Is QoS-WMM supported
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001285 *
1286 * Return: 0 for success or negative errno otherwise
1287 */
1288int wlan_hdd_tdls_set_peer_caps(hdd_adapter_t *pAdapter,
1289 const uint8_t *mac,
1290 tCsrStaParams *StaParams,
Nitesh Shah99934ac2016-09-05 15:54:08 +05301291 bool isBufSta, bool isOffChannelSupported,
1292 bool is_qos_wmm_sta)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001293{
1294 hddTdlsPeer_t *curr_peer;
1295
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001296 curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001297 if (curr_peer == NULL) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001298 hdd_err("curr_peer is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001299 return -EINVAL;
1300 }
1301
1302 curr_peer->uapsdQueues = StaParams->uapsd_queues;
1303 curr_peer->maxSp = StaParams->max_sp;
1304 curr_peer->isBufSta = isBufSta;
1305 curr_peer->isOffChannelSupported = isOffChannelSupported;
1306
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301307 qdf_mem_copy(curr_peer->supported_channels,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001308 StaParams->supported_channels,
1309 StaParams->supported_channels_len);
1310
1311 curr_peer->supported_channels_len = StaParams->supported_channels_len;
1312
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301313 qdf_mem_copy(curr_peer->supported_oper_classes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001314 StaParams->supported_oper_classes,
1315 StaParams->supported_oper_classes_len);
1316
1317 curr_peer->supported_oper_classes_len =
1318 StaParams->supported_oper_classes_len;
Nitesh Shah99934ac2016-09-05 15:54:08 +05301319 curr_peer->qos = is_qos_wmm_sta;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001320 return 0;
1321}
1322
1323/**
1324 * wlan_hdd_tdls_get_link_establish_params() - get TDLS link establish
1325 * parameter
1326 * @pAdapter: HDD adapter
1327 * @mac: mac address
1328 * @tdlsLinkEstablishParams: output parameter to store the result
1329 *
1330 * Return: 0 for success or negative errno otherwise
1331 */
1332int wlan_hdd_tdls_get_link_establish_params(hdd_adapter_t *pAdapter,
1333 const u8 *mac,
1334 tCsrTdlsLinkEstablishParams *
1335 tdlsLinkEstablishParams)
1336{
1337 hddTdlsPeer_t *curr_peer;
1338
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001339 curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001340 if (curr_peer == NULL) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001341 hdd_err("curr_peer is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001342 return -EINVAL;
1343 }
1344
1345 tdlsLinkEstablishParams->isResponder = curr_peer->is_responder;
1346 tdlsLinkEstablishParams->uapsdQueues = curr_peer->uapsdQueues;
1347 tdlsLinkEstablishParams->maxSp = curr_peer->maxSp;
1348 tdlsLinkEstablishParams->isBufSta = curr_peer->isBufSta;
1349 tdlsLinkEstablishParams->isOffChannelSupported =
1350 curr_peer->isOffChannelSupported;
1351
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301352 qdf_mem_copy(tdlsLinkEstablishParams->supportedChannels,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001353 curr_peer->supported_channels,
1354 curr_peer->supported_channels_len);
1355
1356 tdlsLinkEstablishParams->supportedChannelsLen =
1357 curr_peer->supported_channels_len;
1358
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301359 qdf_mem_copy(tdlsLinkEstablishParams->supportedOperClasses,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001360 curr_peer->supported_oper_classes,
1361 curr_peer->supported_oper_classes_len);
1362
1363 tdlsLinkEstablishParams->supportedOperClassesLen =
1364 curr_peer->supported_oper_classes_len;
Agrawal Ashishd3f22f62016-09-04 13:46:15 +05301365 tdlsLinkEstablishParams->qos = curr_peer->qos;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001366 return 0;
1367}
1368
1369/**
1370 * wlan_hdd_tdls_set_rssi() - Set TDLS RSSI on peer given by mac
1371 * @pAdapter: HDD adapter
1372 * @mac: MAC address of Peer
1373 * @rxRssi: rssi value
1374 *
1375 * Set RSSI on TDSL peer
1376 *
1377 * Return: 0 for success or -EINVAL otherwise
1378 */
1379int wlan_hdd_tdls_set_rssi(hdd_adapter_t *pAdapter, const uint8_t *mac,
1380 int8_t rxRssi)
1381{
1382 hddTdlsPeer_t *curr_peer;
1383
1384 curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, true);
1385 if (curr_peer == NULL) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001386 hdd_err("curr_peer is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001387 return -EINVAL;
1388 }
1389
1390 curr_peer->rssi = rxRssi;
1391
1392 return 0;
1393}
1394
1395/**
1396 * wlan_hdd_tdls_set_responder() - Set/clear TDLS peer's responder role
1397 * @pAdapter: HDD adapter
1398 * @mac: MAC address of Peer
1399 * @responder: flag that indicates if the TDLS peer should be responder or not
1400 *
1401 * Return: 0 for success or -EINVAL otherwise
1402 */
1403int wlan_hdd_tdls_set_responder(hdd_adapter_t *pAdapter, const uint8_t *mac,
1404 uint8_t responder)
1405{
1406 hddTdlsPeer_t *curr_peer;
1407
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001408 curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001409 if (curr_peer == NULL) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001410 hdd_err("curr_peer is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001411 return -EINVAL;
1412 }
1413
1414 curr_peer->is_responder = responder;
1415
1416 return 0;
1417}
1418
1419/**
1420 * wlan_hdd_tdls_set_signature() - Set TDLS peer's signature
1421 * @pAdapter: HDD adapter
1422 * @mac: MAC address of TDLS Peer
1423 * @uSignature: signature value
1424 *
1425 * Return: 0 for success or -EINVAL otherwise
1426 */
1427int wlan_hdd_tdls_set_signature(hdd_adapter_t *pAdapter, const uint8_t *mac,
1428 uint8_t uSignature)
1429{
1430 hddTdlsPeer_t *curr_peer;
1431
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001432 curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001433 if (curr_peer == NULL) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001434 hdd_err("curr_peer is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001435 return -EINVAL;
1436 }
1437
1438 curr_peer->signature = uSignature;
1439
1440 return 0;
1441}
1442
1443/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001444 * wlan_hdd_tdls_extract_sa() - Extract source address from socket buffer
1445 * @skb: socket buffer
1446 * @mac: output mac address buffer to store the source address
1447 *
1448 * Return: Void
1449 */
1450void wlan_hdd_tdls_extract_sa(struct sk_buff *skb, uint8_t *mac)
1451{
1452 memcpy(mac, skb->data + 6, 6);
1453}
1454
1455/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001456 * wlan_hdd_tdls_check_config() - validate tdls configuration parameters
1457 * @config: tdls configuration parameter structure
1458 *
1459 * Return: 0 if all parameters are valid; -EINVAL otherwise
1460 */
1461static int wlan_hdd_tdls_check_config(tdls_config_params_t *config)
1462{
1463 if (config->tdls > 2) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001464 hdd_err("Invalid 1st argument %d. <0...2>",
1465 config->tdls);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001466 return -EINVAL;
1467 }
1468 if (config->tx_period_t < CFG_TDLS_TX_STATS_PERIOD_MIN ||
1469 config->tx_period_t > CFG_TDLS_TX_STATS_PERIOD_MAX) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001470 hdd_err("Invalid 2nd argument %d. <%d...%ld>",
1471 config->tx_period_t, CFG_TDLS_TX_STATS_PERIOD_MIN,
1472 CFG_TDLS_TX_STATS_PERIOD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001473 return -EINVAL;
1474 }
1475 if (config->tx_packet_n < CFG_TDLS_TX_PACKET_THRESHOLD_MIN ||
1476 config->tx_packet_n > CFG_TDLS_TX_PACKET_THRESHOLD_MAX) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001477 hdd_err("Invalid 3rd argument %d. <%d...%ld>",
1478 config->tx_packet_n, CFG_TDLS_TX_PACKET_THRESHOLD_MIN,
1479 CFG_TDLS_TX_PACKET_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001480 return -EINVAL;
1481 }
1482 if (config->discovery_tries_n < CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MIN ||
1483 config->discovery_tries_n > CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MAX) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001484 hdd_err("Invalid 5th argument %d. <%d...%d>",
1485 config->discovery_tries_n,
1486 CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MIN,
1487 CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001488 return -EINVAL;
1489 }
1490 if (config->idle_packet_n < CFG_TDLS_IDLE_PACKET_THRESHOLD_MIN ||
1491 config->idle_packet_n > CFG_TDLS_IDLE_PACKET_THRESHOLD_MAX) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001492 hdd_err("Invalid 7th argument %d. <%d...%d>",
1493 config->idle_packet_n,
1494 CFG_TDLS_IDLE_PACKET_THRESHOLD_MIN,
1495 CFG_TDLS_IDLE_PACKET_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001496 return -EINVAL;
1497 }
1498 if (config->rssi_trigger_threshold < CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MIN
1499 || config->rssi_trigger_threshold >
1500 CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MAX) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001501 hdd_err("Invalid 9th argument %d. <%d...%d>",
1502 config->rssi_trigger_threshold,
1503 CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MIN,
1504 CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001505 return -EINVAL;
1506 }
1507 if (config->rssi_teardown_threshold <
1508 CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MIN
1509 || config->rssi_teardown_threshold >
1510 CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MAX) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001511 hdd_err("Invalid 10th argument %d. <%d...%d>",
1512 config->rssi_teardown_threshold,
1513 CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MIN,
1514 CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MAX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001515 return -EINVAL;
1516 }
Nitesh Shah757435e2016-12-19 18:28:33 +05301517 if (config->rssi_delta < CFG_TDLS_RSSI_DELTA_MIN
1518 || config->rssi_delta > CFG_TDLS_RSSI_DELTA_MAX) {
1519 hdd_err("Invalid 11th argument %d. <%d...%d>",
1520 config->rssi_delta,
1521 CFG_TDLS_RSSI_DELTA_MIN,
1522 CFG_TDLS_RSSI_DELTA_MAX);
1523 return -EINVAL;
1524 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001525 return 0;
1526}
1527
1528/**
1529 * wlan_tdd_tdls_reset_tx_rx() - reset tx/rx counters for all tdls peers
1530 * @pHddTdlsCtx: TDLS context
1531 *
1532 * Caller has to take the TDLS lock before calling this function
1533 *
1534 * Return: Void
1535 */
1536static void wlan_tdd_tdls_reset_tx_rx(tdlsCtx_t *pHddTdlsCtx)
1537{
1538 int i;
1539 struct list_head *head;
1540 hddTdlsPeer_t *tmp;
1541 struct list_head *pos, *q;
1542
1543 for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
1544 head = &pHddTdlsCtx->peer_list[i];
1545 list_for_each_safe(pos, q, head) {
1546 tmp = list_entry(pos, hddTdlsPeer_t, node);
1547 tmp->tx_pkt = 0;
1548 tmp->rx_pkt = 0;
1549 }
1550 }
1551
1552 return;
1553}
1554
1555/**
1556 * wlan_hdd_tdls_implicit_disable() - disable implicit tdls triggering
1557 * @pHddTdlsCtx: TDLS context
1558 *
1559 * Return: Void
1560 */
1561static void wlan_hdd_tdls_implicit_disable(tdlsCtx_t *pHddTdlsCtx)
1562{
Nitesh Shah82c52812016-12-27 12:27:51 +05301563 hdd_info("Disable Implicit TDLS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001564 wlan_hdd_tdls_timers_stop(pHddTdlsCtx);
1565}
1566
1567/**
1568 * wlan_hdd_tdls_implicit_enable() - enable implicit tdls triggering
1569 * @pHddTdlsCtx: TDLS context
1570 *
1571 * Return: Void
1572 */
1573static void wlan_hdd_tdls_implicit_enable(tdlsCtx_t *pHddTdlsCtx)
1574{
Nitesh Shah82c52812016-12-27 12:27:51 +05301575 hdd_info("Enable Implicit TDLS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001576 wlan_hdd_tdls_peer_reset_discovery_processed(pHddTdlsCtx);
1577 pHddTdlsCtx->discovery_sent_cnt = 0;
1578 wlan_tdd_tdls_reset_tx_rx(pHddTdlsCtx);
1579 wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter);
1580
Kabilan Kannan36090ce2016-05-03 19:28:44 -07001581 /* Restart the connection tracker timer */
1582 wlan_hdd_tdls_timer_restart(pHddTdlsCtx->pAdapter,
1583 &pHddTdlsCtx->peer_update_timer,
1584 pHddTdlsCtx->threshold_config.tx_period_t);
1585
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001586}
1587
1588/**
1589 * wlan_hdd_tdls_set_mode() - set TDLS mode
1590 * @pHddCtx: HDD context
1591 * @tdls_mode: TDLS mode
1592 * @bUpdateLast: Switch on if to set pHddCtx->tdls_mode_last to tdls_mode.
1593 * If 1, set pHddCtx->tdls_mode_last to tdls_mode, otherwise
1594 * set pHddCtx->tdls_mode_last to pHddCtx->tdls_mode
Nitesh Shah2b946fa2016-10-19 17:05:09 +05301595 * @source: TDLS disable source enum values
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001596 *
1597 * Return: Void
1598 */
Jeff Johnson414e9f32016-10-05 15:46:19 -07001599static void wlan_hdd_tdls_set_mode(hdd_context_t *pHddCtx,
Nitesh Shah2b946fa2016-10-19 17:05:09 +05301600 eTDLSSupportMode tdls_mode,
1601 bool bUpdateLast,
1602 enum tdls_disable_source source)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001603{
1604 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301605 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001606 hdd_adapter_t *pAdapter;
1607 tdlsCtx_t *pHddTdlsCtx;
1608
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301609 ENTER();
1610
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001611 hdd_notice("mode %d", (int)tdls_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001612
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301613 if (0 != (wlan_hdd_validate_context(pHddCtx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001614 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001615
1616 mutex_lock(&pHddCtx->tdls_lock);
1617
Nitesh Shah2b946fa2016-10-19 17:05:09 +05301618 if (bUpdateLast)
1619 pHddCtx->tdls_mode_last = tdls_mode;
1620
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001621 if (pHddCtx->tdls_mode == tdls_mode) {
1622 mutex_unlock(&pHddCtx->tdls_lock);
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001623 hdd_notice("already in mode %d", (int)tdls_mode);
Nitesh Shah2b946fa2016-10-19 17:05:09 +05301624
Kabilan Kannan3a5b9fc2017-01-27 18:17:51 -08001625 switch (tdls_mode) {
Nitesh Shah2b946fa2016-10-19 17:05:09 +05301626 /* TDLS is already enabled hence clear source mask, return */
Kabilan Kannan3a5b9fc2017-01-27 18:17:51 -08001627 case eTDLS_SUPPORT_ENABLED:
1628 case eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY:
1629 case eTDLS_SUPPORT_EXTERNAL_CONTROL:
Nitesh Shah2b946fa2016-10-19 17:05:09 +05301630 clear_bit((unsigned long)source,
1631 &pHddCtx->tdls_source_bitmap);
1632 hdd_notice("clear source mask:%d", source);
1633 return;
Kabilan Kannan3a5b9fc2017-01-27 18:17:51 -08001634 /* TDLS is already disabled hence set source mask, return */
1635 case eTDLS_SUPPORT_DISABLED:
1636 set_bit((unsigned long)source,
1637 &pHddCtx->tdls_source_bitmap);
1638 hdd_notice("set source mask:%d", source);
1639 return;
1640 default:
1641 return;
Nitesh Shah2b946fa2016-10-19 17:05:09 +05301642 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001643 }
1644
1645 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
1646
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301647 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001648 pAdapter = pAdapterNode->pAdapter;
1649 pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
1650 if (NULL != pHddTdlsCtx) {
Kabilan Kannan421714b2015-11-23 04:44:59 -08001651 if (eTDLS_SUPPORT_ENABLED == tdls_mode ||
Kabilan Kannand053aaf2016-10-26 02:06:14 -07001652 eTDLS_SUPPORT_EXTERNAL_CONTROL == tdls_mode) {
Nitesh Shah2b946fa2016-10-19 17:05:09 +05301653 clear_bit((unsigned long)source,
1654 &pHddCtx->tdls_source_bitmap);
Kabilan Kannand053aaf2016-10-26 02:06:14 -07001655
Nitesh Shah2b946fa2016-10-19 17:05:09 +05301656 /*
1657 * Check if any TDLS source bit is set and if
1658 * bitmap is not zero then we should not
1659 * enable TDLS
1660 */
1661 if (pHddCtx->tdls_source_bitmap) {
1662 mutex_unlock(&pHddCtx->tdls_lock);
1663 hdd_notice("Don't enable TDLS, source"
1664 "bitmap: %lu",
1665 pHddCtx->tdls_source_bitmap);
1666 return;
1667 }
1668 wlan_hdd_tdls_implicit_enable(pHddTdlsCtx);
1669 /* tdls implicit mode is enabled, so
1670 * enable the connection tracker
1671 */
1672 pHddCtx->enable_tdls_connection_tracker =
1673 true;
1674 } else if (eTDLS_SUPPORT_DISABLED == tdls_mode) {
1675 set_bit((unsigned long)source,
1676 &pHddCtx->tdls_source_bitmap);
1677 wlan_hdd_tdls_implicit_disable(pHddTdlsCtx);
Kabilan Kannand053aaf2016-10-26 02:06:14 -07001678 /* If tdls implicit mode is disabled, then
1679 * stop the connection tracker.
1680 */
1681 pHddCtx->enable_tdls_connection_tracker =
1682 false;
Nitesh Shah2b946fa2016-10-19 17:05:09 +05301683 } else if (eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY ==
1684 tdls_mode) {
1685 clear_bit((unsigned long)source,
1686 &pHddCtx->tdls_source_bitmap);
1687 wlan_hdd_tdls_implicit_disable(pHddTdlsCtx);
1688 /* If tdls implicit mode is disabled, then
1689 * stop the connection tracker.
1690 */
1691 pHddCtx->enable_tdls_connection_tracker =
1692 false;
1693
1694 /*
1695 * Check if any TDLS source bit is set and if
1696 * bitmap is not zero then we should not
1697 * enable TDLS
1698 */
1699 if (pHddCtx->tdls_source_bitmap) {
1700 mutex_unlock(&pHddCtx->tdls_lock);
1701 return;
1702 }
Kabilan Kannand053aaf2016-10-26 02:06:14 -07001703 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001704 }
1705 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1706 pAdapterNode = pNext;
1707 }
Nitesh Shah2b946fa2016-10-19 17:05:09 +05301708 if (!bUpdateLast)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709 pHddCtx->tdls_mode_last = pHddCtx->tdls_mode;
Nitesh Shah2b946fa2016-10-19 17:05:09 +05301710
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711 pHddCtx->tdls_mode = tdls_mode;
1712
1713 mutex_unlock(&pHddCtx->tdls_lock);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301714 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001715}
1716
1717/**
1718 * wlan_hdd_tdls_set_params() - set TDLS parameters
1719 * @dev: net device
1720 * @config: TDLS configuration parameters
1721 *
1722 * Return: 0 if success or negative errno otherwise
1723 */
1724int wlan_hdd_tdls_set_params(struct net_device *dev,
1725 tdls_config_params_t *config)
1726{
1727 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1728 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1729 tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
1730 eTDLSSupportMode req_tdls_mode;
1731 tdlsInfo_t *tdlsParams;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301732 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001733
1734 if (NULL == pHddTdlsCtx) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001735 hdd_err("TDLS not enabled!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736 return -EINVAL;
1737 }
1738
1739 if (wlan_hdd_tdls_check_config(config) != 0) {
1740 return -EINVAL;
1741 }
1742
1743 /* config->tdls is mapped to 0->1, 1->2, 2->3 */
1744 req_tdls_mode = config->tdls + 1;
1745 if (pHddCtx->tdls_mode == req_tdls_mode) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001746 hdd_err("Already in mode %d", config->tdls);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001747 return -EINVAL;
1748 }
1749
1750 /* copy the configuration only when given tdls mode is implicit trigger enable */
Kabilan Kannan421714b2015-11-23 04:44:59 -08001751 if (eTDLS_SUPPORT_ENABLED == req_tdls_mode ||
1752 eTDLS_SUPPORT_EXTERNAL_CONTROL == req_tdls_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001753 memcpy(&pHddTdlsCtx->threshold_config, config,
1754 sizeof(tdls_config_params_t));
1755 }
1756
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001757 hdd_err("iw set tdls params: %d %d %d %d %d %d %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001758 config->tdls,
1759 config->tx_period_t,
1760 config->tx_packet_n,
1761 config->discovery_tries_n,
1762 config->idle_packet_n,
1763 config->rssi_trigger_threshold,
1764 config->rssi_teardown_threshold);
1765
Nitesh Shah2b946fa2016-10-19 17:05:09 +05301766 wlan_hdd_tdls_set_mode(pHddCtx, req_tdls_mode, true,
1767 HDD_SET_TDLS_MODE_SOURCE_USER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001768
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301769 tdlsParams = qdf_mem_malloc(sizeof(tdlsInfo_t));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770 if (NULL == tdlsParams) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001771 hdd_err("qdf_mem_malloc failed for tdlsParams");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001772 return -ENOMEM;
1773 }
1774
1775 tdlsParams->vdev_id = pAdapter->sessionId;
1776 tdlsParams->tdls_state = config->tdls;
1777 tdlsParams->notification_interval_ms = config->tx_period_t;
1778 tdlsParams->tx_discovery_threshold = config->tx_packet_n;
1779 tdlsParams->tx_teardown_threshold = config->idle_packet_n;
1780 tdlsParams->rssi_teardown_threshold = config->rssi_teardown_threshold;
1781 tdlsParams->rssi_delta = config->rssi_delta;
1782 tdlsParams->tdls_options = 0;
1783 if (pHddCtx->config->fEnableTDLSOffChannel)
1784 tdlsParams->tdls_options |= ENA_TDLS_OFFCHAN;
1785 if (pHddCtx->config->fEnableTDLSBufferSta)
1786 tdlsParams->tdls_options |= ENA_TDLS_BUFFER_STA;
1787 if (pHddCtx->config->fEnableTDLSSleepSta)
1788 tdlsParams->tdls_options |= ENA_TDLS_SLEEP_STA;
1789 tdlsParams->peer_traffic_ind_window =
1790 pHddCtx->config->fTDLSPuapsdPTIWindow;
1791 tdlsParams->peer_traffic_response_timeout =
1792 pHddCtx->config->fTDLSPuapsdPTRTimeout;
1793 tdlsParams->puapsd_mask = pHddCtx->config->fTDLSUapsdMask;
1794 tdlsParams->puapsd_inactivity_time =
1795 pHddCtx->config->fTDLSPuapsdInactivityTimer;
1796 tdlsParams->puapsd_rx_frame_threshold =
1797 pHddCtx->config->fTDLSRxFrameThreshold;
Kabilan Kannanca670be2015-11-23 01:56:12 -08001798 tdlsParams->teardown_notification_ms =
1799 pHddCtx->config->tdls_idle_timeout;
Kabilan Kannan421714b2015-11-23 04:44:59 -08001800 tdlsParams->tdls_peer_kickout_threshold =
1801 pHddCtx->config->tdls_peer_kickout_threshold;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001802
Kabilan Kannanca670be2015-11-23 01:56:12 -08001803 dump_tdls_state_param_setting(tdlsParams);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001804
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301805 qdf_ret_status = sme_update_fw_tdls_state(pHddCtx->hHal, tdlsParams, true);
1806 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301807 qdf_mem_free(tdlsParams);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001808 return -EINVAL;
1809 }
1810
1811 return 0;
1812}
1813
1814/**
Kabilan Kannan32eb5022016-10-04 12:24:50 -07001815 * wlan_hdd_tdls_get_adapter() - check system state and return hdd adapter
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07001816 * @hdd_ctx: hdd context
1817 *
Kabilan Kannan32eb5022016-10-04 12:24:50 -07001818 * If TDLS possible, return the corresponding hdd adapter
1819 * to enable TDLS in the system.
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07001820 *
1821 * Return: hdd adapter pointer or NULL.
1822 */
Kabilan Kannan32eb5022016-10-04 12:24:50 -07001823static hdd_adapter_t *wlan_hdd_tdls_get_adapter(hdd_context_t *hdd_ctx)
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07001824{
1825 if (cds_get_connection_count() > 1)
1826 return NULL;
1827 if (cds_mode_specific_connection_count(QDF_STA_MODE,
1828 NULL) == 1)
1829 return hdd_get_adapter(hdd_ctx,
1830 QDF_STA_MODE);
1831 if (cds_mode_specific_connection_count(QDF_P2P_CLIENT_MODE,
1832 NULL) == 1)
1833 return hdd_get_adapter(hdd_ctx,
1834 QDF_P2P_CLIENT_MODE);
1835 return NULL;
1836}
1837
1838/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001839 * wlan_hdd_update_tdls_info - update tdls status info
1840 * @adapter: ptr to device adapter.
1841 * @tdls_prohibited: indicates whether tdls is prohibited.
1842 * @tdls_chan_swit_prohibited: indicates whether tdls channel switch
1843 * is prohibited.
1844 *
1845 * Normally an AP does not influence TDLS connection between STAs
1846 * associated to it. But AP may set bits for TDLS Prohibited or
1847 * TDLS Channel Switch Prohibited in Extended Capability IE in
1848 * Assoc/Re-assoc response to STA. So after STA is connected to
1849 * an AP, call this function to update TDLS status as per those
1850 * bits set in Ext Cap IE in received Assoc/Re-assoc response
1851 * from AP.
1852 *
1853 * Return: None.
1854 */
1855void wlan_hdd_update_tdls_info(hdd_adapter_t *adapter, bool tdls_prohibited,
1856 bool tdls_chan_swit_prohibited)
1857{
1858 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1859 tdlsCtx_t *hdd_tdls_ctx = WLAN_HDD_GET_TDLS_CTX_PTR(adapter);
1860 tdlsInfo_t *tdls_param;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301861 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001862
1863 if (!hdd_tdls_ctx) {
1864 /* may be TDLS is not applicable for this adapter */
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001865 hdd_err("HDD TDLS context is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001866 return;
1867 }
1868
1869 /* If TDLS support is disabled then no need to update target */
1870 if (false == hdd_ctx->config->fEnableTDLSSupport) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001871 hdd_err("TDLS not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001872 return;
1873 }
1874
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07001875 hdd_info("tdls_prohibited: %d, tdls_chan_swit_prohibited: %d",
1876 tdls_prohibited, tdls_chan_swit_prohibited);
1877
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001878 mutex_lock(&hdd_ctx->tdls_lock);
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07001879
1880 if (hdd_ctx->set_state_info.set_state_cnt == 0 &&
1881 tdls_prohibited) {
1882 mutex_unlock(&hdd_ctx->tdls_lock);
1883 return;
1884 }
1885
1886 /* If AP or caller indicated TDLS Prohibited then disable tdls mode */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001887 if (tdls_prohibited) {
1888 hdd_ctx->tdls_mode = eTDLS_SUPPORT_NOT_ENABLED;
1889 } else {
Kabilan Kannan421714b2015-11-23 04:44:59 -08001890 if (false == hdd_ctx->config->fEnableTDLSImplicitTrigger)
1891 hdd_ctx->tdls_mode = eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY;
1892 else if (true == hdd_ctx->config->fTDLSExternalControl)
1893 hdd_ctx->tdls_mode = eTDLS_SUPPORT_EXTERNAL_CONTROL;
1894 else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895 hdd_ctx->tdls_mode = eTDLS_SUPPORT_ENABLED;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001896 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301897 tdls_param = qdf_mem_malloc(sizeof(*tdls_param));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001898 if (!tdls_param) {
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07001899 mutex_unlock(&hdd_ctx->tdls_lock);
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07001900 hdd_err("memory allocation failed for tdlsParams");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001901 return;
1902 }
1903
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07001904 /* If any concurrency detected, teardown all TDLS links and disable
1905 * the tdls support
1906 */
1907 hdd_warn("Concurrency check in TDLS! set state cnt %d tdls_prohibited %d",
1908 hdd_ctx->set_state_info.set_state_cnt, tdls_prohibited);
1909
1910 if (hdd_ctx->set_state_info.set_state_cnt == 1 &&
1911 !tdls_prohibited) {
1912 hdd_warn("Concurrency not allowed in TDLS! set state cnt %d",
1913 hdd_ctx->set_state_info.set_state_cnt);
1914 if (hdd_ctx->connected_peer_count >= 1) {
1915 hdd_ctx->concurrency_marked = true;
1916 mutex_unlock(&hdd_ctx->tdls_lock);
1917 wlan_hdd_tdls_disable_offchan_and_teardown_links(
1918 hdd_ctx);
1919 qdf_mem_free(tdls_param);
1920 return;
1921 }
1922 tdls_prohibited = true;
1923 hdd_ctx->tdls_mode = eTDLS_SUPPORT_NOT_ENABLED;
1924 tdls_param->vdev_id = hdd_ctx->set_state_info.vdev_id;
1925 } else {
1926 tdls_param->vdev_id = adapter->sessionId;
1927 }
1928
1929 mutex_unlock(&hdd_ctx->tdls_lock);
1930
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001931 tdls_param->tdls_state = hdd_ctx->tdls_mode;
1932 tdls_param->notification_interval_ms =
1933 hdd_tdls_ctx->threshold_config.tx_period_t;
1934 tdls_param->tx_discovery_threshold =
1935 hdd_tdls_ctx->threshold_config.tx_packet_n;
1936 tdls_param->tx_teardown_threshold =
1937 hdd_tdls_ctx->threshold_config.idle_packet_n;
1938 tdls_param->rssi_teardown_threshold =
1939 hdd_tdls_ctx->threshold_config.rssi_teardown_threshold;
1940 tdls_param->rssi_delta = hdd_tdls_ctx->threshold_config.rssi_delta;
1941
1942 tdls_param->tdls_options = 0;
1943
1944 /* Do not enable TDLS offchannel, if AP prohibited TDLS channel switch */
1945 if ((hdd_ctx->config->fEnableTDLSOffChannel) &&
1946 (!tdls_chan_swit_prohibited)) {
1947 tdls_param->tdls_options |= ENA_TDLS_OFFCHAN;
1948 }
1949
1950 if (hdd_ctx->config->fEnableTDLSBufferSta)
1951 tdls_param->tdls_options |= ENA_TDLS_BUFFER_STA;
1952
1953 if (hdd_ctx->config->fEnableTDLSSleepSta)
1954 tdls_param->tdls_options |= ENA_TDLS_SLEEP_STA;
1955
1956 tdls_param->peer_traffic_ind_window =
1957 hdd_ctx->config->fTDLSPuapsdPTIWindow;
1958 tdls_param->peer_traffic_response_timeout =
1959 hdd_ctx->config->fTDLSPuapsdPTRTimeout;
1960 tdls_param->puapsd_mask =
1961 hdd_ctx->config->fTDLSUapsdMask;
1962 tdls_param->puapsd_inactivity_time =
1963 hdd_ctx->config->fTDLSPuapsdInactivityTimer;
1964 tdls_param->puapsd_rx_frame_threshold =
1965 hdd_ctx->config->fTDLSRxFrameThreshold;
Kabilan Kannanca670be2015-11-23 01:56:12 -08001966 tdls_param->teardown_notification_ms =
1967 hdd_ctx->config->tdls_idle_timeout;
Kabilan Kannan421714b2015-11-23 04:44:59 -08001968 tdls_param->tdls_peer_kickout_threshold =
1969 hdd_ctx->config->tdls_peer_kickout_threshold;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970
Kabilan Kannanca670be2015-11-23 01:56:12 -08001971 dump_tdls_state_param_setting(tdls_param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001972
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301973 qdf_ret_status = sme_update_fw_tdls_state(hdd_ctx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001974 tdls_param,
1975 true);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301976 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301977 qdf_mem_free(tdls_param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001978 return;
1979 }
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07001980
1981 mutex_lock(&hdd_ctx->tdls_lock);
1982
1983 if (!tdls_prohibited) {
1984 hdd_ctx->set_state_info.set_state_cnt++;
1985 hdd_ctx->set_state_info.vdev_id = adapter->sessionId;
1986 } else {
1987 hdd_ctx->set_state_info.set_state_cnt--;
1988 }
1989
1990 hdd_info("TDLS Set state cnt %d",
1991 hdd_ctx->set_state_info.set_state_cnt);
1992
1993 mutex_unlock(&hdd_ctx->tdls_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001994 return;
1995}
1996
1997/**
Kabilan Kannan32eb5022016-10-04 12:24:50 -07001998 * wlan_hdd_tdls_notify_connect() - Update tdls state for every
1999 * connect event.
2000 * @adapter: hdd adapter
2001 * @csr_roam_info: csr information
2002 *
2003 * After every connect event in the system, check whether TDLS
2004 * can be enabled in the system. If TDLS can be enabled, update the
2005 * TDLS state as needed.
2006 *
2007 * Return: None
2008 */
2009void wlan_hdd_tdls_notify_connect(hdd_adapter_t *adapter,
2010 tCsrRoamInfo *csr_roam_info)
2011{
2012 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2013
2014 hdd_info("Check and update TDLS state");
2015
2016 /* Association event */
2017 if ((adapter->device_mode == QDF_STA_MODE ||
2018 adapter->device_mode == QDF_P2P_CLIENT_MODE) &&
2019 !hdd_ctx->concurrency_marked) {
2020 wlan_hdd_update_tdls_info(adapter,
2021 csr_roam_info->tdls_prohibited,
2022 csr_roam_info->tdls_chan_swit_prohibited);
2023 }
2024}
2025
2026/**
2027 * wlan_hdd_tdls_notify_disconnect() - Update tdls state for every
2028 * disconnect event.
2029 * @adapter: hdd adapter
Nitesh Shahb9d3dbb2017-01-16 16:37:20 +05302030 * @lfr_roam: roaming case
Kabilan Kannan32eb5022016-10-04 12:24:50 -07002031 *
2032 * After every disconnect event in the system, check whether TDLS
2033 * can be disabled/enabled in the system and update the
2034 * TDLS state as needed.
2035 *
2036 * Return: None
2037 */
Nitesh Shahb9d3dbb2017-01-16 16:37:20 +05302038void wlan_hdd_tdls_notify_disconnect(hdd_adapter_t *adapter, bool lfr_roam)
Kabilan Kannan32eb5022016-10-04 12:24:50 -07002039{
2040 hdd_adapter_t *temp_adapter;
2041 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2042
2043 hdd_info("Check and update TDLS state");
2044
2045 /* Disassociation event */
2046 if ((adapter->device_mode == QDF_STA_MODE ||
2047 adapter->device_mode == QDF_P2P_CLIENT_MODE) &&
2048 !hdd_ctx->concurrency_marked) {
2049 wlan_hdd_update_tdls_info(adapter, true, true);
2050 }
2051
2052 /* If concurrency is not marked, then we have to
2053 * check, whether TDLS could be enabled in the
2054 * system after this disassoc event.
2055 */
Nitesh Shahb9d3dbb2017-01-16 16:37:20 +05302056 if (!lfr_roam && !hdd_ctx->concurrency_marked) {
Kabilan Kannan32eb5022016-10-04 12:24:50 -07002057 temp_adapter = wlan_hdd_tdls_get_adapter(
2058 hdd_ctx);
Kabilan Kannan05da3682017-02-06 19:01:33 -08002059 if (NULL != temp_adapter) {
Kabilan Kannan32eb5022016-10-04 12:24:50 -07002060 wlan_hdd_update_tdls_info(temp_adapter,
2061 false,
2062 false);
Kabilan Kannan05da3682017-02-06 19:01:33 -08002063 /* Enable connection tracker, if it is implicit and
2064 * external control mode.
2065 */
2066 cds_set_tdls_ct_mode(hdd_ctx);
2067 }
Kabilan Kannan32eb5022016-10-04 12:24:50 -07002068 }
2069}
2070
2071/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002072 * wlan_hdd_tdls_set_sta_id() - set station ID on a tdls peer
2073 * @pAdapter: HDD adapter
2074 * @mac: MAC address of a tdls peer
2075 * @staId: station ID
2076 *
2077 * Return: 0 if success; negative errno otherwise
2078 */
2079int wlan_hdd_tdls_set_sta_id(hdd_adapter_t *pAdapter, const uint8_t *mac,
2080 uint8_t staId)
2081{
2082 hddTdlsPeer_t *curr_peer;
2083
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002084 curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002085 if (curr_peer == NULL) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002086 hdd_err("curr_peer is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002087 return -EINVAL;
2088 }
2089
2090 curr_peer->staId = staId;
2091
2092 return 0;
2093}
2094
2095/**
2096 * wlan_hdd_tdls_set_extctrl_param() - set external control parameter on a peer
2097 * @pAdapter: HDD adapter
2098 * @mac: MAC address of the peer
2099 * @chan: Channel
2100 * @max_latency: Maximum latency
2101 * @op_class: Operation class
2102 * @min_bandwidth: Minimal bandwidth
2103 *
2104 * Return: 0 for success; negative errno otherwise
2105 */
2106int wlan_hdd_tdls_set_extctrl_param(hdd_adapter_t *pAdapter, const uint8_t *mac,
2107 uint32_t chan, uint32_t max_latency,
2108 uint32_t op_class, uint32_t min_bandwidth)
2109{
2110 hddTdlsPeer_t *curr_peer;
2111 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2112 if (!pHddCtx)
2113 return -EINVAL;
2114 mutex_lock(&pHddCtx->tdls_lock);
2115 curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, false);
2116 if (curr_peer == NULL) {
2117 mutex_unlock(&pHddCtx->tdls_lock);
2118 return -EINVAL;
2119 }
2120 curr_peer->op_class_for_pref_off_chan = (uint8_t) op_class;
2121 curr_peer->pref_off_chan_num = (uint8_t) chan;
2122
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002123 mutex_unlock(&pHddCtx->tdls_lock);
2124 return 0;
2125}
2126
2127/**
Kabilan Kannan421714b2015-11-23 04:44:59 -08002128 * wlan_hdd_tdls_update_peer_mac() - Update the peer mac information to firmware
2129 * @adapter: hdd adapter to interface
2130 * @mac: Mac address of the peer to be added
2131 * @peerState: Current state of the peer
2132 *
2133 * This function updates TDLS peer state to firmware. Firmware will update
2134 * connection table based on new peer state.
2135 *
2136 * Return:success (0) or failure (errno value)
2137 */
2138int wlan_hdd_tdls_update_peer_mac(hdd_adapter_t *adapter, const uint8_t *mac,
2139 uint32_t peer_state)
2140{
2141 tSmeTdlsPeerStateParams sme_tdls_peer_state_params = {0};
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302142 QDF_STATUS status = QDF_STATUS_E_FAILURE;
Kabilan Kannan421714b2015-11-23 04:44:59 -08002143 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2144
2145 sme_tdls_peer_state_params.vdevId = adapter->sessionId;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302146 qdf_mem_copy(&sme_tdls_peer_state_params.peerMacAddr, mac,
Kabilan Kannan421714b2015-11-23 04:44:59 -08002147 sizeof(sme_tdls_peer_state_params.peerMacAddr));
2148 sme_tdls_peer_state_params.peerState = peer_state;
2149 status = sme_update_tdls_peer_state(hdd_ctx->hHal,
2150 &sme_tdls_peer_state_params);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302151 if (QDF_STATUS_SUCCESS != status) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002152 hdd_err("sme_UpdateTdlsPeerState failed for "MAC_ADDRESS_STR,
2153 MAC_ADDR_ARRAY(mac));
Kabilan Kannan421714b2015-11-23 04:44:59 -08002154 return -EPERM;
2155 }
2156 return 0;
2157}
2158
2159/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002160 * wlan_hdd_tdls_set_force_peer() - set/clear isForcedPeer flag on a peer
2161 * @pAdapter: HDD adapter
2162 * @mac: MAC address of the tdls peer
2163 * @forcePeer: value used to set isForcedPeer flag on the peer
2164 *
2165 * Return: 0 for success; negative errno otherwise
2166 */
2167int wlan_hdd_tdls_set_force_peer(hdd_adapter_t *pAdapter, const uint8_t *mac,
2168 bool forcePeer)
2169{
2170 hddTdlsPeer_t *curr_peer;
2171 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2172
2173 if (!pHddCtx)
2174 return -EINVAL;
2175
2176 mutex_lock(&pHddCtx->tdls_lock);
2177
2178 curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, false);
2179 if (curr_peer == NULL) {
2180 mutex_unlock(&pHddCtx->tdls_lock);
2181 return -EINVAL;
2182 }
2183
2184 curr_peer->isForcedPeer = forcePeer;
2185 mutex_unlock(&pHddCtx->tdls_lock);
2186 return 0;
2187}
2188
2189/**
2190 * wlan_hdd_tdls_find_peer() - find TDLS peer given its MAC address
2191 * @pAdapter: HDD adapter
2192 * @mac: MAC address of peer
2193 * @mutexLock: Option to indicate if mutex locking is required for searching
2194 *
2195 * Return: If peerMac is found, then it returns pointer to hddTdlsPeer_t;
2196 * otherwise, it returns NULL
2197 */
2198hddTdlsPeer_t *wlan_hdd_tdls_find_peer(hdd_adapter_t *pAdapter,
2199 const uint8_t *mac, bool mutexLock)
2200{
2201 uint8_t key;
2202 struct list_head *pos;
2203 struct list_head *head;
2204 hddTdlsPeer_t *curr_peer;
2205 tdlsCtx_t *pHddTdlsCtx;
2206 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2207
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302208
2209 if (0 != (wlan_hdd_validate_context(pHddCtx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002210 return NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002211
2212 if (mutexLock) {
2213 mutex_lock(&pHddCtx->tdls_lock);
2214 }
2215 pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
2216 if (NULL == pHddTdlsCtx) {
2217 if (mutexLock)
2218 mutex_unlock(&pHddCtx->tdls_lock);
2219 return NULL;
2220 }
2221
2222 key = wlan_hdd_tdls_hash_key(mac);
2223
2224 head = &pHddTdlsCtx->peer_list[key];
2225
2226 list_for_each(pos, head) {
2227 curr_peer = list_entry(pos, hddTdlsPeer_t, node);
2228 if (!memcmp(mac, curr_peer->peerMac, 6)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302229 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002230 "findTdlsPeer: found staId %d",
2231 curr_peer->staId);
2232 if (mutexLock)
2233 mutex_unlock(&pHddCtx->tdls_lock);
2234 return curr_peer;
2235 }
2236 }
2237 if (mutexLock)
2238 mutex_unlock(&pHddCtx->tdls_lock);
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002239
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002240 return NULL;
2241}
2242
2243/**
2244 * wlan_hdd_tdls_find_all_peer() - find all peers matching the input MAC
2245 * @pHddCtx: HDD context
2246 * @mac: MAC address
2247 *
2248 * Return: TDLS peer if a matching is detected; NULL otherwise
2249 */
2250hddTdlsPeer_t *wlan_hdd_tdls_find_all_peer(hdd_context_t *pHddCtx,
2251 const u8 *mac)
2252{
2253 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2254 hdd_adapter_t *pAdapter = NULL;
2255 tdlsCtx_t *pHddTdlsCtx = NULL;
2256 hddTdlsPeer_t *curr_peer = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302257 QDF_STATUS status = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002258
2259 mutex_lock(&pHddCtx->tdls_lock);
2260
2261 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302262 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002263 pAdapter = pAdapterNode->pAdapter;
2264
2265 pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
2266 if (NULL != pHddTdlsCtx) {
2267 curr_peer =
2268 wlan_hdd_tdls_find_peer(pAdapter, mac, false);
2269 if (curr_peer) {
2270 mutex_unlock(&pHddCtx->tdls_lock);
2271 return curr_peer;
2272 }
2273 }
2274 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
2275 pAdapterNode = pNext;
2276 }
2277 mutex_unlock(&pHddCtx->tdls_lock);
2278 return curr_peer;
2279}
2280
2281/**
2282 * wlan_hdd_tdls_reset_peer() - reset TDLS peer identified by MAC address
2283 * @pAdapter: HDD adapter
2284 * @mac: MAC address of the peer
2285 *
2286 * Return: 0 for success; negative errno otherwise
2287 */
2288int wlan_hdd_tdls_reset_peer(hdd_adapter_t *pAdapter, const uint8_t *mac)
2289{
2290 hdd_context_t *pHddCtx;
2291 hddTdlsPeer_t *curr_peer;
2292
2293 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2294
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002295 curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002296 if (curr_peer == NULL) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002297 hdd_err("curr_peer is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002298 return -EINVAL;
2299 }
2300
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05302301 /*
2302 * Reset preferred offchannel and opclass for offchannel as
2303 * per INI configuration only if peer is not forced one. For
2304 * forced peer, offchannel and opclass is set in HAL API at the
2305 * time of enabling TDLS for that specific peer and so do not overwrite
2306 * those set by user space.
2307 */
2308 if (false == curr_peer->isForcedPeer) {
2309 curr_peer->pref_off_chan_num =
2310 pHddCtx->config->fTDLSPrefOffChanNum;
2311 curr_peer->op_class_for_pref_off_chan =
2312 wlan_hdd_find_opclass(WLAN_HDD_GET_HAL_CTX(pAdapter),
2313 curr_peer->pref_off_chan_num,
2314 pHddCtx->config->fTDLSPrefOffChanBandwidth);
2315 }
2316
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002317 wlan_hdd_tdls_set_peer_link_status(curr_peer,
2318 eTDLS_LINK_IDLE,
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002319 eTDLS_LINK_UNSPECIFIED,
2320 true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002321 curr_peer->staId = 0;
2322
2323 return 0;
2324}
2325
2326/**
2327 * wlan_hdd_tdls_peer_reset_discovery_processed() - reset discovery status
2328 * @pHddTdlsCtx: TDLS context
2329 *
2330 * This function resets discovery processing bit for all TDLS peers
2331 *
2332 * Caller has to take the lock before calling this function
2333 *
2334 * Return: 0
2335 */
2336static int32_t wlan_hdd_tdls_peer_reset_discovery_processed(tdlsCtx_t *
2337 pHddTdlsCtx)
2338{
2339 int i;
2340 struct list_head *head;
2341 hddTdlsPeer_t *tmp;
2342 struct list_head *pos, *q;
2343
2344 pHddTdlsCtx->discovery_peer_cnt = 0;
2345
2346 for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
2347 head = &pHddTdlsCtx->peer_list[i];
2348 list_for_each_safe(pos, q, head) {
2349 tmp = list_entry(pos, hddTdlsPeer_t, node);
2350 tmp->discovery_processed = 0;
2351 }
2352 }
2353
2354 return 0;
2355}
2356
2357/**
2358 * wlan_hdd_tdls_connected_peers() - Find the number of connected TDLS peers
2359 * @pAdapter: HDD adapter
2360 *
2361 * Return: The number of connected TDLS peers or 0 if error is detected
2362 */
2363uint16_t wlan_hdd_tdls_connected_peers(hdd_adapter_t *pAdapter)
2364{
c_hpothud5009242016-08-18 12:10:36 +05302365 hdd_context_t *pHddCtx;
2366
2367 if ((NULL == pAdapter) ||
2368 (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
2369 hdd_err("invalid pAdapter: %p", pAdapter);
2370 return 0;
2371 }
2372 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002373
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302374 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002375 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002376
2377 return pHddCtx->connected_peer_count;
2378}
2379
2380/**
2381 * wlan_hdd_tdls_get_all_peers() - dump all TDLS peer info into output string
2382 * @pAdapter: HDD adapter
2383 * @buf: output string buffer to hold the peer info
2384 * @buflen: the size of output string buffer
2385 *
2386 * Return: The size (in bytes) of the valid peer info in the output buffer
2387 */
2388int wlan_hdd_tdls_get_all_peers(hdd_adapter_t *pAdapter, char *buf, int buflen)
2389{
2390 int i;
2391 int len, init_len;
2392 struct list_head *head;
2393 struct list_head *pos;
2394 hddTdlsPeer_t *curr_peer;
2395 tdlsCtx_t *pHddTdlsCtx;
2396 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2397
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302398 ENTER();
2399
2400 if (0 != (wlan_hdd_validate_context(pHddCtx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002401 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002402
2403 init_len = buflen;
2404 len = scnprintf(buf, buflen, "\n%-18s%-3s%-4s%-3s%-5s\n",
2405 "MAC", "Id", "cap", "up", "RSSI");
2406 buf += len;
2407 buflen -= len;
2408 /* 1234567890123456789012345678901234567 */
2409 len = scnprintf(buf, buflen, "---------------------------------\n");
2410 buf += len;
2411 buflen -= len;
2412
2413 mutex_lock(&pHddCtx->tdls_lock);
2414
2415 pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
2416 if (NULL == pHddTdlsCtx) {
2417 mutex_unlock(&pHddCtx->tdls_lock);
2418 len = scnprintf(buf, buflen, "TDLS not enabled\n");
2419 return len;
2420 }
2421 for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
2422 head = &pHddTdlsCtx->peer_list[i];
2423
2424 list_for_each(pos, head) {
2425 curr_peer = list_entry(pos, hddTdlsPeer_t, node);
2426
2427 if (buflen < 32 + 1)
2428 break;
2429 len = scnprintf(buf, buflen,
2430 MAC_ADDRESS_STR "%3d%4s%3s%5d\n",
2431 MAC_ADDR_ARRAY(curr_peer->peerMac),
2432 curr_peer->staId,
2433 (curr_peer->tdls_support ==
2434 eTDLS_CAP_SUPPORTED) ? "Y" : "N",
2435 TDLS_IS_CONNECTED(curr_peer) ? "Y" :
2436 "N", curr_peer->rssi);
2437 buf += len;
2438 buflen -= len;
2439 }
2440 }
2441 mutex_unlock(&pHddCtx->tdls_lock);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302442 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002443 return init_len - buflen;
2444}
2445
2446/**
2447 * wlan_hdd_tdls_connection_callback() - callback after tdls connection
2448 * @pAdapter: HDD adapter
2449 *
2450 * Return: Void
2451 */
2452void wlan_hdd_tdls_connection_callback(hdd_adapter_t *pAdapter)
2453{
2454 tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
2455 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002456 uint32_t tx_period_t;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002457
2458 if ((NULL == pHddCtx) || (NULL == pHddTdlsCtx)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302459 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002460 FL("pHddCtx or pHddTdlsCtx points to NULL"));
2461 return;
2462 }
2463
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002464 tx_period_t = pHddTdlsCtx->threshold_config.tx_period_t;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002465
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002466 hdd_notice("update %d", pHddTdlsCtx->threshold_config.tx_period_t);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002467
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002468 mutex_lock(&pHddCtx->tdls_lock);
2469
Kabilan Kannan421714b2015-11-23 04:44:59 -08002470 if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode ||
2471 eTDLS_SUPPORT_EXTERNAL_CONTROL == pHddCtx->tdls_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002472 wlan_hdd_tdls_peer_reset_discovery_processed(pHddTdlsCtx);
2473 pHddTdlsCtx->discovery_sent_cnt = 0;
Kabilan Kannan421714b2015-11-23 04:44:59 -08002474 wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter);
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002475 /* Start the connection tracker timer */
2476 wlan_hdd_tdls_timer_restart(pHddTdlsCtx->pAdapter,
2477 &pHddTdlsCtx->peer_update_timer,
2478 tx_period_t);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002479 }
Kabilan Kannan421714b2015-11-23 04:44:59 -08002480
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002481 mutex_unlock(&pHddCtx->tdls_lock);
2482
2483}
2484
2485/**
2486 * wlan_hdd_tdls_disconnection_callback() - callback after tdls disconnection
2487 * @pAdapter: HDD adapter
2488 *
2489 * Return: Void
2490 */
2491void wlan_hdd_tdls_disconnection_callback(hdd_adapter_t *pAdapter)
2492{
Selvaraj, Sridharb5cce872016-07-31 14:58:59 +05302493 tdlsCtx_t *pHddTdlsCtx;
2494 hdd_context_t *pHddCtx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002495
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002496 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002497
Selvaraj, Sridharb5cce872016-07-31 14:58:59 +05302498 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2499 if (0 != wlan_hdd_validate_context(pHddCtx))
2500 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002501 mutex_lock(&pHddCtx->tdls_lock);
2502
Selvaraj, Sridharb5cce872016-07-31 14:58:59 +05302503 pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002504 if (NULL == pHddTdlsCtx) {
2505 mutex_unlock(&pHddCtx->tdls_lock);
Anurag Chouhan05d124f2016-09-03 16:21:50 +05302506 hdd_notice("pHddTdlsCtx is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002507 return;
2508 }
2509 pHddTdlsCtx->discovery_sent_cnt = 0;
2510 wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter);
2511
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002512 wlan_hdd_tdls_timers_stop(pHddTdlsCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002513
2514 pHddTdlsCtx->curr_candidate = NULL;
2515
2516 mutex_unlock(&pHddCtx->tdls_lock);
2517}
2518
2519/**
2520 * wlan_hdd_tdls_mgmt_completion_callback() - callback for TDLS management
2521 * TX completion
2522 * @pAdapter: HDD adapter
2523 * @statusCode: management TX completion status
2524 *
2525 * Return: Void
2526 */
2527void wlan_hdd_tdls_mgmt_completion_callback(hdd_adapter_t *pAdapter,
2528 uint32_t statusCode)
2529{
2530 pAdapter->mgmtTxCompletionStatus = statusCode;
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002531 hdd_notice("Mgmt TX Completion %d", statusCode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002532 complete(&pAdapter->tdls_mgmt_comp);
2533}
2534
2535/**
2536 * wlan_hdd_tdls_increment_peer_count() - increment connected TDLS peer counter
2537 * @pAdapter: HDD adapter
2538 *
2539 * Return: Void
2540 */
2541void wlan_hdd_tdls_increment_peer_count(hdd_adapter_t *pAdapter)
2542{
2543 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2544
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302545 ENTER();
2546
2547 if (0 != (wlan_hdd_validate_context(pHddCtx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002548 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002549
2550 mutex_lock(&pHddCtx->tdls_lock);
2551
2552 pHddCtx->connected_peer_count++;
2553 wlan_hdd_tdls_check_power_save_prohibited(pAdapter);
2554
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002555 hdd_notice("Connected peer count %d",
2556 pHddCtx->connected_peer_count);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002557
2558 mutex_unlock(&pHddCtx->tdls_lock);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302559 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002560}
2561
2562/**
2563 * wlan_hdd_tdls_decrement_peer_count() - decrement connected TDLS peer counter
2564 * @pAdapter: HDD adapter
2565 *
2566 * Return: Void
2567 */
2568void wlan_hdd_tdls_decrement_peer_count(hdd_adapter_t *pAdapter)
2569{
2570 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07002571 hdd_adapter_t *tdls_adapter;
2572 uint16_t connected_peer_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002573
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302574 ENTER();
2575
2576 if (0 != (wlan_hdd_validate_context(pHddCtx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002577 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002578
2579 mutex_lock(&pHddCtx->tdls_lock);
2580
2581 if (pHddCtx->connected_peer_count)
2582 pHddCtx->connected_peer_count--;
2583 wlan_hdd_tdls_check_power_save_prohibited(pAdapter);
2584
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07002585 connected_peer_count = pHddCtx->connected_peer_count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002586 mutex_unlock(&pHddCtx->tdls_lock);
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07002587
Nitesh Shah82c52812016-12-27 12:27:51 +05302588 hdd_notice("Connected peer count %d", connected_peer_count);
2589
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07002590 if (connected_peer_count == 0 &&
2591 pHddCtx->concurrency_marked) {
2592 tdls_adapter = hdd_get_adapter_by_vdev(pHddCtx,
2593 pHddCtx->set_state_info.vdev_id);
2594 if (tdls_adapter) {
2595 wlan_hdd_update_tdls_info(tdls_adapter, true, true);
2596 pHddCtx->concurrency_marked = false;
2597 } else {
2598 hdd_err("TDLS set state is not cleared correctly !!!");
2599 pHddCtx->concurrency_marked = false;
2600 }
Kabilan Kannan32eb5022016-10-04 12:24:50 -07002601 tdls_adapter = wlan_hdd_tdls_get_adapter(pHddCtx);
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07002602 if (tdls_adapter)
2603 wlan_hdd_update_tdls_info(tdls_adapter, false, false);
2604 }
2605
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302606 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002607}
2608
2609
2610/**
2611 * wlan_hdd_tdls_find_progress_peer() - find peer if TDLS is ongoing
2612 * @pAdapter: HDD adapter
2613 * @mac: If NULL check for all the peer list, otherwise, skip this mac when
2614 * skip_self is true
2615 * @skip_self: If true, skip this mac. otherwise, check all the peer list. if
2616 * mac is NULL, this argument is ignored, and check for all the peer
2617 * list.
2618 *
2619 * Return: Pointer to hddTdlsPeer_t if TDLS is ongoing. Otherwise return NULL.
2620 */
2621static hddTdlsPeer_t *wlan_hdd_tdls_find_progress_peer(hdd_adapter_t *pAdapter,
2622 const u8 *mac,
2623 u8 skip_self)
2624{
2625 int i;
2626 struct list_head *head;
2627 hddTdlsPeer_t *curr_peer;
2628 struct list_head *pos;
2629 tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);;
2630
2631 if (NULL == pHddTdlsCtx) {
Anurag Chouhan05d124f2016-09-03 16:21:50 +05302632 hdd_notice("pHddTdlsCtx is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002633 return NULL;
2634 }
2635
2636 for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
2637 head = &pHddTdlsCtx->peer_list[i];
2638 list_for_each(pos, head) {
2639 curr_peer = list_entry(pos, hddTdlsPeer_t, node);
2640 if (skip_self && mac
2641 && !memcmp(mac, curr_peer->peerMac, 6)) {
2642 continue;
2643 } else {
2644 if (eTDLS_LINK_CONNECTING ==
2645 curr_peer->link_status) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002646 hdd_notice(MAC_ADDRESS_STR
2647 " eTDLS_LINK_CONNECTING",
2648 MAC_ADDR_ARRAY(curr_peer->peerMac));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002649 return curr_peer;
2650 }
2651 }
2652 }
2653 }
2654 return NULL;
2655}
2656
2657/**
2658 * wlan_hdd_tdls_is_progress() - find the peer with ongoing TDLS progress
2659 * @pHddCtx: HDD context
2660 * @mac: mac address of the peer
2661 * @skip_self: if 1, skip checking self. If 0, search includes self
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002662 * @need_lock: flag to indicate, whether the caller acquired the mutex or not
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002663 *
2664 * Return: TDLS peer if found; NULL otherwise
2665 */
2666hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx,
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002667 const uint8_t *mac,
2668 uint8_t skip_self,
2669 bool need_lock)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002670{
2671 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2672 hdd_adapter_t *pAdapter = NULL;
2673 tdlsCtx_t *pHddTdlsCtx = NULL;
2674 hddTdlsPeer_t *curr_peer = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302675 QDF_STATUS status = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002676
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002677 if (need_lock)
2678 mutex_lock(&pHddCtx->tdls_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002679
2680 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302681 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002682 pAdapter = pAdapterNode->pAdapter;
2683
2684 pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
2685 if (NULL != pHddTdlsCtx) {
2686 curr_peer =
2687 wlan_hdd_tdls_find_progress_peer(pAdapter, mac,
2688 skip_self);
2689 if (curr_peer) {
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002690 if (need_lock)
2691 mutex_unlock(&pHddCtx->tdls_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002692 return curr_peer;
2693 }
2694 }
2695 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
2696 pAdapterNode = pNext;
2697 }
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002698
2699 if (need_lock)
2700 mutex_unlock(&pHddCtx->tdls_lock);
2701
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002702 return NULL;
2703}
2704
2705/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002706 * wlan_hdd_tdls_copy_scan_context() - Copy TDLS scan context
2707 * @pHddCtx: HDD context
2708 * @wiphy: wiphy pointer
2709 * @dev: net device
2710 * request: source scan context
2711 *
2712 * Copy the source scan context into the HDD context's TDLS scan context
2713 *
2714 * Return: 0 for success; negative errno otherwise
2715 */
2716int wlan_hdd_tdls_copy_scan_context(hdd_context_t *pHddCtx,
2717 struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002718 struct cfg80211_scan_request *request)
2719{
2720 tdls_scan_context_t *scan_ctx;
2721
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302722 ENTER();
2723
2724 if (0 != (wlan_hdd_validate_context(pHddCtx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002725 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002726
2727 scan_ctx = &pHddCtx->tdls_scan_ctxt;
2728
2729 scan_ctx->wiphy = wiphy;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002730
2731 scan_ctx->scan_request = request;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302732 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002733 return 0;
2734}
2735
2736/**
2737 * wlan_hdd_tdls_scan_init_work() - schedule tdls scan work
2738 * @pHddCtx: HDD context
2739 * @wiphy: wiphy pointer
2740 * @dev: net device
2741 * @request: scan request
2742 * @delay: delay value to pass to the work scheduling
Nitesh Shah9ed1a9f2017-01-05 18:55:05 +05302743 * @source: scan request source(NL/Vendor scan)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002744 *
2745 * Return: Void
2746 */
2747static void wlan_hdd_tdls_scan_init_work(hdd_context_t *pHddCtx,
2748 struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002749 struct cfg80211_scan_request *request,
Nitesh Shah9ed1a9f2017-01-05 18:55:05 +05302750 unsigned long delay, uint8_t source)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002751{
2752 if (TDLS_CTX_MAGIC != pHddCtx->tdls_scan_ctxt.magic) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002753 wlan_hdd_tdls_copy_scan_context(pHddCtx, wiphy, request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002754 pHddCtx->tdls_scan_ctxt.attempt = 0;
2755 pHddCtx->tdls_scan_ctxt.magic = TDLS_CTX_MAGIC;
Nitesh Shah9ed1a9f2017-01-05 18:55:05 +05302756 pHddCtx->tdls_scan_ctxt.source = source;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002757 }
2758 schedule_delayed_work(&pHddCtx->tdls_scan_ctxt.tdls_scan_work, delay);
2759}
2760
2761/**
2762 * wlan_hdd_tdls_scan_callback() - callback for TDLS scan operation
2763 * @pAdapter: HDD adapter
2764 * @wiphy: wiphy
2765 * @dev: net device
2766 * @request: scan request
2767 *
2768 * Return: negative = caller should stop and return error code immediately
2769 * 0 = caller should stop and return success immediately
2770 * 1 = caller can continue to scan
2771 */
2772int wlan_hdd_tdls_scan_callback(hdd_adapter_t *pAdapter, struct wiphy *wiphy,
Nitesh Shah9ed1a9f2017-01-05 18:55:05 +05302773 struct cfg80211_scan_request *request,
2774 uint8_t source)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002775{
2776 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2777 u16 connectedTdlsPeers;
2778 hddTdlsPeer_t *curr_peer;
2779 unsigned long delay;
2780 int ret;
2781
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302782 ENTER();
2783
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002784 ret = wlan_hdd_validate_context(pHddCtx);
2785 if (ret)
2786 return ret;
2787
2788 /* if tdls is not enabled, then continue scan */
2789 if (eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode)
2790 return 1;
2791
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002792 curr_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002793 if (NULL != curr_peer) {
2794 if (pHddCtx->tdls_scan_ctxt.reject++ >= TDLS_MAX_SCAN_REJECT) {
2795 pHddCtx->tdls_scan_ctxt.reject = 0;
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002796 hdd_notice(MAC_ADDRESS_STR
2797 ". scan rejected %d. force it to idle",
2798 MAC_ADDR_ARRAY(curr_peer->peerMac),
2799 pHddCtx->tdls_scan_ctxt.reject);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002800
2801 wlan_hdd_tdls_set_peer_link_status(curr_peer,
2802 eTDLS_LINK_IDLE,
Kabilan Kannan36090ce2016-05-03 19:28:44 -07002803 eTDLS_LINK_UNSPECIFIED,
2804 true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002805 return 1;
2806 }
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002807 hdd_warn("tdls in progress. scan rejected %d",
2808 pHddCtx->tdls_scan_ctxt.reject);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002809 return -EBUSY;
2810 }
2811
2812 /* tdls teardown is ongoing */
2813 if (eTDLS_SUPPORT_DISABLED == pHddCtx->tdls_mode) {
2814 connectedTdlsPeers = wlan_hdd_tdls_connected_peers(pAdapter);
2815 if (connectedTdlsPeers
2816 && (pHddCtx->tdls_scan_ctxt.attempt <
2817 TDLS_MAX_SCAN_SCHEDULE)) {
2818 delay =
2819 (unsigned long)(TDLS_DELAY_SCAN_PER_CONNECTION *
2820 connectedTdlsPeers);
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002821 hdd_notice("tdls disabled, but still connected_peers %d attempt %d. schedule scan %lu msec",
2822 connectedTdlsPeers,
2823 pHddCtx->tdls_scan_ctxt.attempt, delay);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002824
2825 wlan_hdd_tdls_scan_init_work(pHddCtx, wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002826 request,
Nitesh Shah9ed1a9f2017-01-05 18:55:05 +05302827 msecs_to_jiffies(delay),
2828 source);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002829 /* scan should not continue */
2830 return 0;
2831 }
2832 /* no connected peer or max retry reached, scan continue */
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002833 hdd_notice("tdls disabled. connected_peers %d attempt %d. scan allowed",
2834 connectedTdlsPeers,
2835 pHddCtx->tdls_scan_ctxt.attempt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002836 return 1;
2837 }
2838 /* while tdls is up, first time scan */
2839 else if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode ||
Kabilan Kannan421714b2015-11-23 04:44:59 -08002840 eTDLS_SUPPORT_EXTERNAL_CONTROL == pHddCtx->tdls_mode ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002841 eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == pHddCtx->tdls_mode) {
2842 /* disable implicit trigger logic & tdls operatoin */
Nitesh Shah2b946fa2016-10-19 17:05:09 +05302843 wlan_hdd_tdls_set_mode(pHddCtx, eTDLS_SUPPORT_DISABLED, false,
2844 HDD_SET_TDLS_MODE_SOURCE_SCAN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002845 /* indicate the teardown all connected to peer */
2846 connectedTdlsPeers = wlan_hdd_tdls_connected_peers(pAdapter);
2847 if (connectedTdlsPeers) {
2848 uint8_t staIdx;
2849 uint8_t num = 0;
2850 uint8_t i;
2851 bool allPeersBufStas = 1;
2852 hddTdlsPeer_t *curr_peer;
2853 hddTdlsPeer_t *connectedPeerList[HDD_MAX_NUM_TDLS_STA];
2854
2855 /* If TDLSScan is enabled then allow scan and
2856 * maintain tdls link regardless if peer is buffer
2857 * sta capable or not and if device is sleep sta
2858 * capable or not. If peer is not buffer sta
2859 * capable, then Tx would stop when device
2860 * initiates scan and there will be loss of Rx
2861 * packets since peer would not know when device
2862 * moves away from the tdls channel.
2863 */
2864 if (1 == pHddCtx->config->enable_tdls_scan) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002865 hdd_notice("TDLSScan enabled, keep tdls link and allow scan, connectedTdlsPeers: %d",
2866 connectedTdlsPeers);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002867 return 1;
2868 }
2869
2870 for (staIdx = 0; staIdx < pHddCtx->max_num_tdls_sta;
2871 staIdx++) {
2872 if (pHddCtx->tdlsConnInfo[staIdx].staId) {
2873 curr_peer =
2874 wlan_hdd_tdls_find_all_peer(pHddCtx,
2875 pHddCtx->
2876 tdlsConnInfo
2877 [staIdx].
2878 peerMac.
2879 bytes);
2880 if (curr_peer) {
2881 connectedPeerList[num++] =
2882 curr_peer;
2883 if (!(curr_peer->isBufSta))
2884 allPeersBufStas = 0;
2885 }
2886 }
2887 }
2888
2889 if ((TDLS_MAX_CONNECTED_PEERS_TO_ALLOW_SCAN ==
2890 connectedTdlsPeers) &&
2891 (pHddCtx->config->fEnableTDLSSleepSta) &&
2892 (allPeersBufStas)) {
2893 /* All connected peers bufStas and we can be sleepSta
2894 * so allow scan
2895 */
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002896 hdd_notice("All peers (num %d) bufSTAs, we can be sleep sta, so allow scan, tdls mode changed to %d",
2897 connectedTdlsPeers,
2898 pHddCtx->tdls_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002899 return 1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002900 }
Jeff Johnson68755312017-02-10 11:46:55 -08002901
2902 for (i = 0; i < num; i++) {
2903 hdd_notice("indicate TDLS teadown (staId %d)",
2904 connectedPeerList[i]->staId);
2905 wlan_hdd_tdls_indicate_teardown
2906 (connectedPeerList[i]->pHddTdlsCtx->
2907 pAdapter, connectedPeerList[i],
2908 eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON);
2909 hdd_send_wlan_tdls_teardown_event
2910 (eTDLS_TEARDOWN_SCAN,
2911 connectedPeerList[i]->peerMac);
2912 }
2913
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002914 /* schedule scan */
2915 delay =
2916 (unsigned long)(TDLS_DELAY_SCAN_PER_CONNECTION *
2917 connectedTdlsPeers);
2918
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002919 hdd_notice("tdls enabled (mode %d), connected_peers %d. schedule scan %lu msec",
2920 pHddCtx->tdls_mode,
2921 wlan_hdd_tdls_connected_peers(pAdapter), delay);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002922
2923 wlan_hdd_tdls_scan_init_work(pHddCtx, wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002924 request,
Nitesh Shah9ed1a9f2017-01-05 18:55:05 +05302925 msecs_to_jiffies(delay),
2926 source);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002927 /* scan should not continue */
2928 return 0;
2929 }
2930 /* no connected peer, scan continue */
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002931 hdd_notice("tdls_mode %d, and no tdls connection. scan allowed",
2932 pHddCtx->tdls_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002933 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302934 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002935 return 1;
2936}
2937
2938/**
2939 * wlan_hdd_tdls_scan_done_callback() - callback for tdls scan done event
2940 * @pAdapter: HDD adapter
2941 *
2942 * Return: Void
2943 */
2944void wlan_hdd_tdls_scan_done_callback(hdd_adapter_t *pAdapter)
2945{
2946 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2947
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302948 ENTER();
2949
2950 if (0 != (wlan_hdd_validate_context(pHddCtx)))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002951 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002952
Bhargav Shah1efa55c2015-11-04 11:58:27 +05302953 if (eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) {
2954 hdd_info("TDLS mode is disabled OR not enabled");
2955 return;
2956 }
2957
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002958 /* free allocated memory at scan time */
2959 wlan_hdd_tdls_free_scan_request(&pHddCtx->tdls_scan_ctxt);
2960
2961 /* if tdls was enabled before scan, re-enable tdls mode */
2962 if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode_last ||
Kabilan Kannan421714b2015-11-23 04:44:59 -08002963 eTDLS_SUPPORT_EXTERNAL_CONTROL == pHddCtx->tdls_mode_last ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002964 eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == pHddCtx->tdls_mode_last) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002965 hdd_notice("revert tdls mode %d",
2966 pHddCtx->tdls_mode_last);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002967
Nitesh Shah2b946fa2016-10-19 17:05:09 +05302968 wlan_hdd_tdls_set_mode(pHddCtx, pHddCtx->tdls_mode_last, false,
2969 HDD_SET_TDLS_MODE_SOURCE_SCAN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002970 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302971 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002972}
2973
2974/**
2975 * wlan_hdd_tdls_timer_restart() - restart TDLS timer
2976 * @pAdapter: HDD adapter
2977 * @timer: timer to restart
2978 * @expirationTime: new expiration time to set for the timer
2979 *
2980 * Return: Void
2981 */
2982void wlan_hdd_tdls_timer_restart(hdd_adapter_t *pAdapter,
Anurag Chouhan210db072016-02-22 18:42:15 +05302983 qdf_mc_timer_t *timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002984 uint32_t expirationTime)
2985{
Kai Liu55758e02016-10-28 16:39:54 +08002986 hdd_station_ctx_t *pHddStaCtx;
2987
2988 if (NULL == pAdapter || WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) {
2989 hdd_err("invalid pAdapter: %p", pAdapter);
2990 return;
2991 }
2992
2993 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002994
2995 /* Check whether driver load unload is in progress */
Rajeev Kumarfec3dbe2016-01-19 15:23:52 -08002996 if (cds_is_load_or_unload_in_progress()) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07002997 hdd_err("Driver load/unload is in progress.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002998 return;
2999 }
3000
3001 if (hdd_conn_is_connected(pHddStaCtx)) {
Anurag Chouhan210db072016-02-22 18:42:15 +05303002 qdf_mc_timer_stop(timer);
3003 qdf_mc_timer_start(timer, expirationTime);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003004 }
3005}
3006
3007/**
3008 * wlan_hdd_tdls_indicate_teardown() - indicate tdls teardown
3009 * @pAdapter: HDD adapter
3010 * @curr_peer: peer tdls teardown happened
3011 * @reason: teardown reason
3012 *
3013 * Return: Void
3014 */
3015void wlan_hdd_tdls_indicate_teardown(hdd_adapter_t *pAdapter,
3016 hddTdlsPeer_t *curr_peer, uint16_t reason)
3017{
c_hpothud5009242016-08-18 12:10:36 +05303018 if ((NULL == pAdapter || WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) ||
3019 (NULL == curr_peer)) {
3020 hdd_err("parameters passed are invalid");
3021 if (!curr_peer)
3022 hdd_err("curr_peer is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003023 return;
3024 }
3025
3026 if (eTDLS_LINK_CONNECTED != curr_peer->link_status)
3027 return;
3028
3029 wlan_hdd_tdls_set_peer_link_status(curr_peer,
3030 eTDLS_LINK_TEARING,
Kabilan Kannan36090ce2016-05-03 19:28:44 -07003031 eTDLS_LINK_UNSPECIFIED,
3032 true);
Agrawal Ashisha5c2bdc2015-09-16 16:58:41 +05303033 hdd_info("Teardown reason %d", reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003034 cfg80211_tdls_oper_request(pAdapter->dev,
3035 curr_peer->peerMac,
3036 NL80211_TDLS_TEARDOWN, reason, GFP_KERNEL);
3037}
3038
3039/**
3040 * wlan_hdd_set_callback() - set state change callback on current TDLS peer
3041 * @curr_peer: current TDLS peer
3042 * @callback: state change callback
3043 *
3044 * Return: 0 if success; negative errno otherwise
3045 */
3046int wlan_hdd_set_callback(hddTdlsPeer_t *curr_peer,
3047 cfg80211_exttdls_callback callback)
3048{
3049 hdd_context_t *pHddCtx;
3050 hdd_adapter_t *pAdapter;
3051 if (!curr_peer)
3052 return -EINVAL;
3053 pAdapter = curr_peer->pHddTdlsCtx->pAdapter;
3054 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
3055 if ((NULL == pHddCtx))
3056 return -EINVAL;
3057 mutex_lock(&pHddCtx->tdls_lock);
3058 curr_peer->state_change_notification = callback;
3059 mutex_unlock(&pHddCtx->tdls_lock);
3060 return 0;
3061}
3062
3063/**
3064 * wlan_hdd_tdls_get_wifi_hal_state() - get tdls wifi hal state on current peer
3065 * @curr_peer: current TDLS peer
3066 * @state: output parameter to store the tdls wifi hal state
3067 * @reason: output parameter to store the reason of the current peer
3068 *
3069 * Return: Void
3070 */
3071void wlan_hdd_tdls_get_wifi_hal_state(hddTdlsPeer_t *curr_peer,
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303072 uint32_t *state, int32_t *reason)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003073{
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303074 hdd_context_t *hddctx;
3075 hdd_adapter_t *adapter;
3076
3077 if (!curr_peer) {
3078 hdd_err("curr_peer is NULL");
3079 return;
3080 }
3081
3082 adapter = curr_peer->pHddTdlsCtx->pAdapter;
3083 hddctx = WLAN_HDD_GET_CTX(adapter);
3084
3085 if (0 != (wlan_hdd_validate_context(hddctx)))
3086 return;
3087
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003088 *reason = curr_peer->reason;
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303089
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003090 switch (curr_peer->link_status) {
3091 case eTDLS_LINK_IDLE:
3092 case eTDLS_LINK_DISCOVERED:
3093 *state = QCA_WIFI_HAL_TDLS_ENABLED;
3094 break;
3095 case eTDLS_LINK_DISCOVERING:
3096 case eTDLS_LINK_CONNECTING:
3097 *state = QCA_WIFI_HAL_TDLS_ENABLED;
3098 break;
3099 case eTDLS_LINK_CONNECTED:
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303100 if ((hddctx->config->fEnableTDLSOffChannel) &&
3101 (hddctx->tdls_fw_off_chan_mode == ENABLE_CHANSWITCH))
3102 *state = QCA_WIFI_HAL_TDLS_ESTABLISHED_OFF_CHANNEL;
3103 else
3104 *state = QCA_WIFI_HAL_TDLS_ESTABLISHED;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003105 break;
3106 case eTDLS_LINK_TEARING:
3107 *state = QCA_WIFI_HAL_TDLS_DROPPED;
3108 break;
3109 }
3110}
3111
3112/**
3113 * wlan_hdd_tdls_get_status() - get tdls status on current tdls peer
3114 * @pAdapter: HDD adapter
3115 * @mac: MAC address of current TDLS peer
3116 * @state: output parameter to store the tdls wifi hal state
3117 * @reason: output parameter to store the reason of the current peer
3118 *
3119 * Return: 0 if success; negative errno otherwise
3120 */
3121int wlan_hdd_tdls_get_status(hdd_adapter_t *pAdapter,
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303122 const uint8_t *mac, uint32_t *opclass,
3123 uint32_t *channel, uint32_t *state,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003124 int32_t *reason)
3125{
3126 hddTdlsPeer_t *curr_peer;
3127 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
3128
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303129 if (0 != (wlan_hdd_validate_context(pHddCtx)))
3130 return -EINVAL;
3131
3132 mutex_lock(&pHddCtx->tdls_lock);
3133 curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003134 if (curr_peer == NULL) {
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303135 mutex_unlock(&pHddCtx->tdls_lock);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303136 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003137 FL("curr_peer is NULL"));
3138 *state = QCA_WIFI_HAL_TDLS_DISABLED;
3139 *reason = eTDLS_LINK_UNSPECIFIED;
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303140 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003141 }
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303142 if (pHddCtx->config->fTDLSExternalControl &&
3143 (false == curr_peer->isForcedPeer)) {
3144 hdd_err("curr_peer is not Forced");
3145 *state = QCA_WIFI_HAL_TDLS_DISABLED;
3146 *reason = eTDLS_LINK_UNSPECIFIED;
3147 } else {
3148 wlan_hdd_tdls_determine_channel_opclass(pHddCtx, pAdapter,
3149 curr_peer, channel, opclass);
3150 wlan_hdd_tdls_get_wifi_hal_state(curr_peer, state, reason);
3151 }
3152 mutex_unlock(&pHddCtx->tdls_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003153
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003154 return 0;
3155}
3156
3157#ifdef FEATURE_WLAN_TDLS
3158static const struct nla_policy
3159 wlan_hdd_tdls_config_enable_policy[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX +
3160 1] = {
3161 [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR] = {.type = NLA_UNSPEC},
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303162 [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL] = {.type = NLA_U32},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003163 [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS] = {.type =
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303164 NLA_U32},
3165 [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS] = {.type = NLA_U32},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003166 [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS] = {.type =
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303167 NLA_U32},
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003168};
3169static const struct nla_policy
3170 wlan_hdd_tdls_config_disable_policy[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX +
3171 1] = {
3172 [QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR] = {.type = NLA_UNSPEC},
3173};
3174static const struct nla_policy
3175 wlan_hdd_tdls_config_state_change_policy[QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX
3176 + 1] = {
3177 [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAC_ADDR] = {.type = NLA_UNSPEC},
3178 [QCA_WLAN_VENDOR_ATTR_TDLS_NEW_STATE] = {.type = NLA_U32},
3179 [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_REASON] = {.type = NLA_S32},
3180 [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CHANNEL] = {.type = NLA_U32},
3181 [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_GLOBAL_OPERATING_CLASS] = {.type =
3182 NLA_U32},
3183};
3184static const struct nla_policy
3185 wlan_hdd_tdls_config_get_status_policy
3186[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX + 1] = {
3187 [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR] = {.type = NLA_UNSPEC},
3188 [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE] = {.type = NLA_U32},
3189 [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON] = {.type = NLA_S32},
3190 [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL] = {.type = NLA_U32},
3191 [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS] = {
3192 .type = NLA_U32},
3193};
3194
Kabilan Kannand053aaf2016-10-26 02:06:14 -07003195static const struct nla_policy
3196 wlan_hdd_tdls_mode_configuration_policy
3197 [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX + 1] = {
3198 [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE] = {
3199 .type = NLA_U32},
3200 [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD] = {
3201 .type = NLA_U32},
3202 [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD] = {
3203 .type = NLA_U32},
3204 [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_DISCOVERY_PERIOD] = {
3205 .type = NLA_U32},
3206 [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT] = {
3207 .type = NLA_U32},
3208 [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT] = {
3209 .type = NLA_U32},
3210 [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD] = {
3211 .type = NLA_U32},
3212 [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD] = {
3213 .type = NLA_S32},
3214 [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD] = {
3215 .type = NLA_S32},
3216};
3217
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003218/**
3219 * __wlan_hdd_cfg80211_exttdls_get_status() - handle get status cfg80211 command
3220 * @wiphy: wiphy
3221 * @wdev: wireless dev
3222 * @data: netlink buffer with the mac address of the peer to get the status for
3223 * @data_len: length of data in bytes
3224 */
3225static int
3226__wlan_hdd_cfg80211_exttdls_get_status(struct wiphy *wiphy,
3227 struct wireless_dev *wdev,
3228 const void *data,
3229 int data_len)
3230{
3231 uint8_t peer[ETH_ALEN] = { 0 };
3232 struct net_device *dev = wdev->netdev;
3233 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3234 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3235 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX + 1];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303236 QDF_STATUS ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003237 uint32_t state;
3238 int32_t reason;
3239 uint32_t global_operating_class = 0;
3240 uint32_t channel = 0;
3241 struct sk_buff *skb = NULL;
3242
Jeff Johnson1f61b612016-02-12 16:28:33 -08003243 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303244
Anurag Chouhan6d760662016-02-20 16:05:43 +05303245 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003246 hdd_err("Command not allowed in FTM mode");
3247 return -EPERM;
3248 }
3249
3250 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303251 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003252 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003253 if (pHddCtx->config->fTDLSExternalControl == false) {
3254 return -ENOTSUPP;
3255 }
3256 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX,
3257 data, data_len, wlan_hdd_tdls_config_get_status_policy)) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003258 hdd_err("Invalid attribute");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003259 return -EINVAL;
3260 }
3261 if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR]) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003262 hdd_err("attr mac addr failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003263 return -EINVAL;
3264 }
3265 memcpy(peer,
3266 nla_data(tb[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR]),
3267 sizeof(peer));
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003268 hdd_notice(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(peer));
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303269 ret = wlan_hdd_tdls_get_status(pAdapter, peer, &global_operating_class,
3270 &channel, &state, &reason);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003271 if (0 != ret) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003272 hdd_err("get status Failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003273 return -EINVAL;
3274 }
3275 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
3276 4 * sizeof(int32_t) +
3277 NLMSG_HDRLEN);
3278 if (!skb) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003279 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003280 return -EINVAL;
3281 }
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003282 hdd_notice("Reason %d Status %d class %d channel %d peer " MAC_ADDRESS_STR,
3283 reason, state, global_operating_class, channel,
3284 MAC_ADDR_ARRAY(peer));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003285 if (nla_put_u32(skb,
3286 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE,
3287 state) ||
3288 nla_put_s32(skb,
3289 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON,
3290 reason) ||
3291 nla_put_u32(skb,
3292 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS,
3293 global_operating_class) ||
3294 nla_put_u32(skb,
3295 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL,
3296 channel)) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003297 hdd_err("nla put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003298 goto nla_put_failure;
3299 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303300 ret = cfg80211_vendor_cmd_reply(skb);
3301 EXIT();
3302 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003303nla_put_failure:
3304 kfree_skb(skb);
3305 return -EINVAL;
3306}
3307
3308/**
Kabilan Kannand053aaf2016-10-26 02:06:14 -07003309 * __wlan_hdd_cfg80211_configure_tdls_mode() - configure the tdls mode
3310 * @wiphy: wiphy
3311 * @wdev: wireless dev
3312 * @data: netlink buffer
3313 * @data_len: length of data in bytes
3314 *
3315 * Return 0 for success and error code for failure
3316 */
3317static int
3318__wlan_hdd_cfg80211_configure_tdls_mode(struct wiphy *wiphy,
3319 struct wireless_dev *wdev,
3320 const void *data,
3321 int data_len)
3322{
3323 struct net_device *dev = wdev->netdev;
3324 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
3325 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3326 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX + 1];
3327 int ret;
3328 eTDLSSupportMode tdls_mode;
3329 uint32_t trigger_mode;
3330 tdlsCtx_t *hdd_tdls_ctx;
3331
3332 ENTER_DEV(dev);
3333
3334 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3335 hdd_err("Command not allowed in FTM mode");
3336 return -EPERM;
3337 }
3338
3339 ret = wlan_hdd_validate_context(hdd_ctx);
3340 if (0 != ret)
3341 return -EINVAL;
3342
3343 if (NULL == adapter)
3344 return -EINVAL;
3345
3346 hdd_tdls_ctx = adapter->sessionCtx.station.pHddTdlsCtx;
3347 if (NULL == hdd_tdls_ctx)
3348 return -EINVAL;
3349
3350 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX,
3351 data, data_len,
3352 wlan_hdd_tdls_mode_configuration_policy)) {
3353 hdd_err("Invalid attribute");
3354 return -EINVAL;
3355 }
3356
3357 if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE]) {
3358 hdd_err("attr tdls trigger mode failed");
3359 return -EINVAL;
3360 }
3361 trigger_mode = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE]);
3362 hdd_notice("TDLS trigger mode %d", trigger_mode);
3363
3364 switch (trigger_mode) {
3365 case WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT:
3366 tdls_mode = eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY;
3367 break;
3368 case WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL:
3369 tdls_mode = eTDLS_SUPPORT_EXTERNAL_CONTROL;
3370 break;
3371 case WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT:
3372 tdls_mode = eTDLS_SUPPORT_ENABLED;
3373 break;
3374 default:
3375 hdd_err("Invalid TDLS trigger mode");
3376 return -EINVAL;
3377 }
Nitesh Shah2b946fa2016-10-19 17:05:09 +05303378 wlan_hdd_tdls_set_mode(hdd_ctx, tdls_mode, false,
3379 HDD_SET_TDLS_MODE_SOURCE_USER);
Kabilan Kannand053aaf2016-10-26 02:06:14 -07003380
3381 mutex_lock(&hdd_ctx->tdls_lock);
3382
3383 if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD]) {
3384 hdd_tdls_ctx->threshold_config.tx_period_t = nla_get_u32(
3385 tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD]);
3386 hdd_info("attr tdls tx stats period %d",
3387 hdd_tdls_ctx->threshold_config.tx_period_t);
3388 }
3389
3390 if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD]) {
3391 hdd_tdls_ctx->threshold_config.tx_packet_n = nla_get_u32(
3392 tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD]);
3393 hdd_info("attr tdls tx packet period %d",
3394 hdd_tdls_ctx->threshold_config.tx_packet_n);
3395 }
3396
3397 if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT]) {
3398 hdd_tdls_ctx->threshold_config.discovery_tries_n = nla_get_u32(
3399 tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT]);
3400 hdd_info("attr tdls max discovery attempt %d",
3401 hdd_tdls_ctx->threshold_config.discovery_tries_n);
3402 }
3403
3404 if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT]) {
3405 hdd_tdls_ctx->threshold_config.idle_timeout_t = nla_get_u32(
3406 tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT]);
3407 hdd_info("attr tdls idle time out period %d",
3408 hdd_tdls_ctx->threshold_config.idle_timeout_t);
3409 }
3410
3411 if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD]) {
3412 hdd_tdls_ctx->threshold_config.idle_packet_n = nla_get_u32(
3413 tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD]);
3414 hdd_info("attr tdls idle pkt threshold %d",
3415 hdd_tdls_ctx->threshold_config.idle_packet_n);
3416 }
3417
3418 if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD]) {
3419 hdd_tdls_ctx->threshold_config.rssi_trigger_threshold = nla_get_s32(
3420 tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD]);
3421 hdd_info("attr tdls rssi trigger threshold %d",
3422 hdd_tdls_ctx->threshold_config.rssi_trigger_threshold);
3423 }
3424
3425 if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD]) {
3426 hdd_tdls_ctx->threshold_config.rssi_teardown_threshold = nla_get_s32(
3427 tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD]);
3428 hdd_info("attr tdls tx stats period %d",
3429 hdd_tdls_ctx->threshold_config.rssi_teardown_threshold);
3430 }
3431
3432 mutex_unlock(&hdd_ctx->tdls_lock);
3433
3434 EXIT();
3435 return ret;
3436}
3437
3438/**
3439 * wlan_hdd_cfg80211_configure_tdls_mode() - configure tdls mode
3440 * @wiphy: pointer to wireless wiphy structure.
3441 * @wdev: pointer to wireless_dev structure.
3442 * @data: Pointer to the data to be passed via vendor interface
3443 * @data_len:Length of the data to be passed
3444 *
3445 * Return: Return the Success or Failure code.
3446 */
3447int wlan_hdd_cfg80211_configure_tdls_mode(struct wiphy *wiphy,
3448 struct wireless_dev *wdev,
3449 const void *data,
3450 int data_len)
3451{
3452 int ret;
3453
3454 cds_ssr_protect(__func__);
3455 ret = __wlan_hdd_cfg80211_configure_tdls_mode(wiphy, wdev, data,
3456 data_len);
3457 cds_ssr_unprotect(__func__);
3458
3459 return ret;
3460}
3461
3462/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003463 * wlan_hdd_cfg80211_exttdls_get_status() - get ext tdls status
3464 * @wiphy: pointer to wireless wiphy structure.
3465 * @wdev: pointer to wireless_dev structure.
3466 * @data: Pointer to the data to be passed via vendor interface
3467 * @data_len:Length of the data to be passed
3468 *
3469 * Return: Return the Success or Failure code.
3470 */
3471int wlan_hdd_cfg80211_exttdls_get_status(struct wiphy *wiphy,
3472 struct wireless_dev *wdev,
3473 const void *data,
3474 int data_len)
3475{
3476 int ret = 0;
3477
3478 cds_ssr_protect(__func__);
3479 ret = __wlan_hdd_cfg80211_exttdls_get_status(wiphy, wdev, data,
3480 data_len);
3481 cds_ssr_unprotect(__func__);
3482
3483 return ret;
3484}
3485
3486/**
3487 * wlan_hdd_cfg80211_exttdls_callback() - notify cfg80211 state change
3488 * @mac: MAC address of the peer with state change
3489 * @state: New state
3490 * @reason: Reason to enter new state
3491 * @ctx: HDD adapter
3492 *
3493 * Return: 0 for success; negative errno otherwise
3494 */
3495static int wlan_hdd_cfg80211_exttdls_callback(const uint8_t *mac,
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05303496 uint32_t global_operating_class,
3497 uint32_t channel,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003498 uint32_t state,
3499 int32_t reason, void *ctx)
3500{
3501 hdd_adapter_t *pAdapter = (hdd_adapter_t *) ctx;
3502 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
3503 struct sk_buff *skb = NULL;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303504
3505 ENTER();
3506
3507 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003508 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003509 if (pHddCtx->config->fTDLSExternalControl == false) {
3510 return -ENOTSUPP;
3511 }
3512 skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
3513 NULL,
3514 EXTTDLS_EVENT_BUF_SIZE + NLMSG_HDRLEN,
3515 QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX,
3516 GFP_KERNEL);
3517 if (!skb) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003518 hdd_err("cfg80211_vendor_event_alloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003519 return -EINVAL;
3520 }
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003521 hdd_notice("Reason: %d Status: %d Class: %d Channel: %d tdls peer " MAC_ADDRESS_STR,
3522 reason, state, global_operating_class, channel,
3523 MAC_ADDR_ARRAY(mac));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003524 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAC_ADDR,
Anurag Chouhan6d760662016-02-20 16:05:43 +05303525 QDF_MAC_ADDR_SIZE, mac) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003526 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TDLS_NEW_STATE,
3527 state) ||
3528 nla_put_s32(skb, QCA_WLAN_VENDOR_ATTR_TDLS_STATE_REASON,
3529 reason) ||
3530 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CHANNEL,
3531 channel) ||
3532 nla_put_u32(skb,
3533 QCA_WLAN_VENDOR_ATTR_TDLS_STATE_GLOBAL_OPERATING_CLASS,
3534 global_operating_class)) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003535 hdd_err("nla put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003536 goto nla_put_failure;
3537 }
3538 cfg80211_vendor_event(skb, GFP_KERNEL);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303539 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003540 return 0;
3541nla_put_failure:
3542 kfree_skb(skb);
3543 return -EINVAL;
3544}
3545
3546/**
3547 * __wlan_hdd_cfg80211_exttdls_enable() - enable an externally controllable
3548 * TDLS peer and set parameters
3549 * wiphy: wiphy
3550 * @wdev: wireless dev pointer
3551 * @data: netlink buffer with peer MAC address and configuration parameters
3552 * @data_len: size of data in bytes
3553 *
3554 * This function sets channel, operation class, maximum latency and minimal
3555 * bandwidth parameters on a TDLS peer that's externally controllable.
3556 *
3557 * Return: 0 for success; negative errno otherwise
3558 */
3559static int
3560__wlan_hdd_cfg80211_exttdls_enable(struct wiphy *wiphy,
3561 struct wireless_dev *wdev,
3562 const void *data,
3563 int data_len)
3564{
3565 uint8_t peer[ETH_ALEN] = { 0 };
3566 struct net_device *dev = wdev->netdev;
3567 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3568 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3569 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX + 1];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303570 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003571 tdls_req_params_t pReqMsg = { 0 };
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303572 int ret;
3573
Jeff Johnson1f61b612016-02-12 16:28:33 -08003574 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003575
Anurag Chouhan6d760662016-02-20 16:05:43 +05303576 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003577 hdd_err("Command not allowed in FTM mode");
3578 return -EPERM;
3579 }
3580
3581 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303582 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003583 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003584 if (pHddCtx->config->fTDLSExternalControl == false) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003585 hdd_err("TDLS External Control is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003586 return -ENOTSUPP;
3587 }
3588 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX,
3589 data, data_len, wlan_hdd_tdls_config_enable_policy)) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003590 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003591 return -EINVAL;
3592 }
3593 if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR]) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003594 hdd_err("attr mac addr failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003595 return -EINVAL;
3596 }
3597 memcpy(peer, nla_data(tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR]),
3598 sizeof(peer));
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003599 hdd_notice(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(peer));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003600 if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL]) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003601 hdd_err("attr channel failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003602 return -EINVAL;
3603 }
3604 pReqMsg.channel =
3605 nla_get_s32(tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL]);
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003606 hdd_notice("Channel Num (%d)", pReqMsg.channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003607 if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS]) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003608 hdd_err("attr operating class failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003609 return -EINVAL;
3610 }
3611 pReqMsg.global_operating_class =
3612 nla_get_s32(tb
3613 [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS]);
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003614 hdd_notice("Operating class (%d)",
3615 pReqMsg.global_operating_class);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003616 if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS]) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003617 hdd_err("attr latency failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003618 return -EINVAL;
3619 }
3620 pReqMsg.max_latency_ms =
3621 nla_get_s32(tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS]);
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003622
3623 hdd_notice("Latency (%d)", pReqMsg.max_latency_ms);
3624
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003625 if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS]) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003626 hdd_err("attr bandwidth failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003627 return -EINVAL;
3628 }
3629 pReqMsg.min_bandwidth_kbps =
3630 nla_get_s32(tb
3631 [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS]);
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003632
3633 hdd_notice("Bandwidth (%d)", pReqMsg.min_bandwidth_kbps);
3634
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303635 ret = wlan_hdd_tdls_extctrl_config_peer(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003636 pAdapter,
3637 peer,
3638 wlan_hdd_cfg80211_exttdls_callback,
3639 pReqMsg.channel,
3640 pReqMsg.max_latency_ms,
3641 pReqMsg.
3642 global_operating_class,
3643 pReqMsg.min_bandwidth_kbps);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303644 EXIT();
3645 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003646}
3647
3648/**
3649 * wlan_hdd_cfg80211_exttdls_enable() - enable ext tdls
3650 * @wiphy: pointer to wireless wiphy structure.
3651 * @wdev: pointer to wireless_dev structure.
3652 * @data: Pointer to the data to be passed via vendor interface
3653 * @data_len:Length of the data to be passed
3654 *
3655 * Return: Return the Success or Failure code.
3656 */
3657int wlan_hdd_cfg80211_exttdls_enable(struct wiphy *wiphy,
3658 struct wireless_dev *wdev,
3659 const void *data,
3660 int data_len)
3661{
3662 int ret = 0;
3663
3664 cds_ssr_protect(__func__);
3665 ret = __wlan_hdd_cfg80211_exttdls_enable(wiphy, wdev, data, data_len);
3666 cds_ssr_unprotect(__func__);
3667
3668 return ret;
3669}
3670
3671/**
3672 * __wlan_hdd_cfg80211_exttdls_disable() - disable an externally controllable
3673 * TDLS peer
3674 * wiphy: wiphy
3675 * @wdev: wireless dev pointer
3676 * @data: netlink buffer with peer MAC address
3677 * @data_len: size of data in bytes
3678 *
3679 * This function disables an externally controllable TDLS peer
3680 *
3681 * Return: 0 for success; negative errno otherwise
3682 */
3683static int __wlan_hdd_cfg80211_exttdls_disable(struct wiphy *wiphy,
3684 struct wireless_dev *wdev,
3685 const void *data,
3686 int data_len)
3687{
3688 u8 peer[ETH_ALEN] = {0};
3689 struct net_device *dev = wdev->netdev;
3690 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3691 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
3692 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX + 1];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303693 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003694
Jeff Johnson1f61b612016-02-12 16:28:33 -08003695 ENTER_DEV(dev);
3696
Anurag Chouhan6d760662016-02-20 16:05:43 +05303697 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003698 hdd_err("Command not allowed in FTM mode");
3699 return -EPERM;
3700 }
3701
3702 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303703 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003704 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003705 if (pHddCtx->config->fTDLSExternalControl == false) {
3706 return -ENOTSUPP;
3707 }
3708 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX,
3709 data, data_len, wlan_hdd_tdls_config_disable_policy)) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003710 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003711 return -EINVAL;
3712 }
3713 if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR]) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003714 hdd_err("attr mac addr failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003715 return -EINVAL;
3716 }
3717 memcpy(peer, nla_data(tb[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR]),
3718 sizeof(peer));
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003719 hdd_notice(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(peer));
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303720 status = wlan_hdd_tdls_extctrl_deconfig_peer(pAdapter, peer);
3721 EXIT();
3722 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003723}
3724
3725/**
3726 * wlan_hdd_cfg80211_exttdls_disable() - disable ext tdls
3727 * @wiphy: pointer to wireless wiphy structure.
3728 * @wdev: pointer to wireless_dev structure.
3729 * @data: Pointer to the data to be passed via vendor interface
3730 * @data_len:Length of the data to be passed
3731 *
3732 * Return: Return the Success or Failure code.
3733 */
3734int wlan_hdd_cfg80211_exttdls_disable(struct wiphy *wiphy,
3735 struct wireless_dev *wdev,
3736 const void *data,
3737 int data_len)
3738{
3739 int ret = 0;
3740
3741 cds_ssr_protect(__func__);
3742 ret = __wlan_hdd_cfg80211_exttdls_disable(wiphy, wdev, data, data_len);
3743 cds_ssr_unprotect(__func__);
3744
3745 return ret;
3746}
3747
3748/**
3749 * wlan_hdd_tdls_add_station() - add or change a TDLS peer station
3750 * @wiphy: wiphy
3751 * @dev: net device
3752 * @mac: MAC address of the TDLS peer
3753 * @update: if non-0, modify the peer with StaParams; if 0, add new peer
3754 * @StaParams: station parameters for the TDLS to change
3755 *
3756 * Return: 0 if success; negative errno otherwise
3757 */
3758int wlan_hdd_tdls_add_station(struct wiphy *wiphy,
3759 struct net_device *dev, const uint8_t *mac,
3760 bool update, tCsrStaParams *StaParams)
3761{
3762 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3763 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303764 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003765 hddTdlsPeer_t *pTdlsPeer;
3766 uint16_t numCurrTdlsPeers;
3767 unsigned long rc;
Selvaraj, Sridhar5d95e632016-09-14 17:00:38 +05303768 int ret;
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003769 int rate_idx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003770
3771 ENTER();
3772
3773 ret = wlan_hdd_validate_context(pHddCtx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05303774 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003775 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003776
3777 if ((eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) ||
3778 (eTDLS_SUPPORT_DISABLED == pHddCtx->tdls_mode)) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003779 hdd_notice("TDLS mode is disabled OR not enabled in FW " MAC_ADDRESS_STR "Request declined.",
3780 MAC_ADDR_ARRAY(mac));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003781 return -ENOTSUPP;
3782 }
3783
Kabilan Kannan36090ce2016-05-03 19:28:44 -07003784 pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003785
3786 if (NULL == pTdlsPeer) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003787 hdd_err(MAC_ADDRESS_STR " update %d not exist. return invalid",
3788 MAC_ADDR_ARRAY(mac), update);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003789 return -EINVAL;
3790 }
3791
3792 /* in add station, we accept existing valid staId if there is */
3793 if ((0 == update) &&
3794 ((pTdlsPeer->link_status >= eTDLS_LINK_CONNECTING) ||
3795 (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)))) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003796 hdd_notice(MAC_ADDRESS_STR " link_status %d. staId %d. add station ignored.",
3797 MAC_ADDR_ARRAY(mac), pTdlsPeer->link_status,
3798 pTdlsPeer->staId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003799 return 0;
3800 }
3801 /* in change station, we accept only when staId is valid */
3802 if ((1 == update) &&
3803 ((pTdlsPeer->link_status > eTDLS_LINK_CONNECTING) ||
3804 (!TDLS_STA_INDEX_VALID(pTdlsPeer->staId)))) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003805 hdd_err(MAC_ADDRESS_STR " link status %d. staId %d. change station %s.",
3806 MAC_ADDR_ARRAY(mac), pTdlsPeer->link_status,
3807 pTdlsPeer->staId,
3808 (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) ? "ignored" :
3809 "declined");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003810 return (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) ? 0 : -EPERM;
3811 }
3812
3813 /* when others are on-going, we want to change link_status to idle */
Kabilan Kannan36090ce2016-05-03 19:28:44 -07003814 if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, mac, true, true)) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003815 hdd_notice(MAC_ADDRESS_STR " TDLS setup is ongoing. Request declined.",
3816 MAC_ADDR_ARRAY(mac));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003817 goto error;
3818 }
3819
3820 /* first to check if we reached to maximum supported TDLS peer.
Jeff Johnsonf1413bb2017-01-12 08:42:15 -08003821 * TODO: for now, return -EPERM looks working fine,
3822 * but need to check if any other errno fit into this category.
3823 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003824 numCurrTdlsPeers = wlan_hdd_tdls_connected_peers(pAdapter);
3825 if (pHddCtx->max_num_tdls_sta <= numCurrTdlsPeers) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303826 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003827 "%s: " MAC_ADDRESS_STR
3828 " TDLS Max peer already connected. Request declined."
3829 " Num of peers (%d), Max allowed (%d).",
3830 __func__, MAC_ADDR_ARRAY(mac), numCurrTdlsPeers,
3831 pHddCtx->max_num_tdls_sta);
3832 goto error;
3833 } else {
3834 hddTdlsPeer_t *pTdlsPeer;
3835 pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, mac, true);
3836 if (pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303837 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003838 "%s: " MAC_ADDRESS_STR
3839 " already connected. Request declined.",
3840 __func__, MAC_ADDR_ARRAY(mac));
3841 return -EPERM;
3842 }
3843 }
3844 if (0 == update)
3845 wlan_hdd_tdls_set_link_status(pAdapter,
3846 mac,
3847 eTDLS_LINK_CONNECTING,
3848 eTDLS_LINK_SUCCESS);
3849
3850 /* debug code */
3851 if (NULL != StaParams) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003852 hdd_notice("TDLS Peer Parameters.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003853 if (StaParams->htcap_present) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003854 hdd_notice("ht_capa->cap_info: %0x",
3855 StaParams->HTCap.capInfo);
3856 hdd_notice("ht_capa->extended_capabilities: %0x",
3857 StaParams->HTCap.extendedHtCapInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003858 }
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003859 hdd_notice("params->capability: %0x", StaParams->capability);
3860 hdd_notice("params->ext_capab_len: %0x",
3861 StaParams->extn_capability[0]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003862 if (StaParams->vhtcap_present) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003863 hdd_notice("rxMcsMap %x rxHighest %x txMcsMap %x txHighest %x",
3864 StaParams->VHTCap.suppMcs.rxMcsMap,
3865 StaParams->VHTCap.suppMcs.rxHighest,
3866 StaParams->VHTCap.suppMcs.txMcsMap,
3867 StaParams->VHTCap.suppMcs.txHighest);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003868 }
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003869 hdd_notice("Supported rates:");
3870 for (rate_idx = 0;
3871 rate_idx < sizeof(StaParams->supported_rates);
3872 rate_idx++)
3873 hdd_notice("rate_idx [%d]: supported_rates %x ",
3874 rate_idx,
3875 StaParams->supported_rates[rate_idx]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003876 } /* end debug code */
3877 else if ((1 == update) && (NULL == StaParams)) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07003878 hdd_err("update is true, but staParams is NULL. Error!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003879 return -EPERM;
3880 }
3881
3882 INIT_COMPLETION(pAdapter->tdls_add_station_comp);
3883
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07003884 /* Update the number of stream for each peer */
3885 if ((NULL != StaParams) && (StaParams->htcap_present)) {
3886 hddTdlsPeer_t *tdls_peer;
3887
3888 tdls_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, true);
3889 if (NULL != tdls_peer)
3890 tdls_peer->spatial_streams =
3891 StaParams->HTCap.suppMcsSet[1];
3892 }
3893
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003894 if (!update) {
3895 status = sme_add_tdls_peer_sta(WLAN_HDD_GET_HAL_CTX(pAdapter),
3896 pAdapter->sessionId, mac);
3897 } else {
3898 status = sme_change_tdls_peer_sta(WLAN_HDD_GET_HAL_CTX(pAdapter),
3899 pAdapter->sessionId, mac,
3900 StaParams);
3901 }
3902
3903 rc = wait_for_completion_timeout(&pAdapter->tdls_add_station_comp,
3904 msecs_to_jiffies
3905 (WAIT_TIME_TDLS_ADD_STA));
3906
3907 if (!rc) {
Selvaraj, Sridhar5d95e632016-09-14 17:00:38 +05303908 hdd_err("timeout waiting for tdls add station indication %ld peer link status %u",
3909 rc, pTdlsPeer->link_status);
3910 goto error;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003911 }
3912
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303913 if (QDF_STATUS_SUCCESS != pAdapter->tdlsAddStaStatus) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303914 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003915 "%s: Add Station is unsuccessful", __func__);
Selvaraj, Sridhar5d95e632016-09-14 17:00:38 +05303916 goto error;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003917 }
3918
3919 return 0;
3920
3921error:
3922 wlan_hdd_tdls_set_link_status(pAdapter,
3923 mac,
3924 eTDLS_LINK_IDLE, eTDLS_LINK_UNSPECIFIED);
3925 return -EPERM;
3926
3927}
3928
3929#if TDLS_MGMT_VERSION2
3930/**
3931 * __wlan_hdd_cfg80211_tdls_mgmt() - handle management actions on a given peer
3932 * @wiphy: wiphy
3933 * @dev: net device
3934 * @peer: MAC address of the TDLS peer
3935 * @action_code: action code
3936 * @dialog_token: dialog token
3937 * @status_code: status code
3938 * @peer_capability: peer capability
3939 * @buf: additional IE to include
3940 * @len: length of buf in bytes
3941 *
3942 * Return: 0 if success; negative errno otherwise
3943 */
3944static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
3945 struct net_device *dev, u8 *peer,
3946 u8 action_code, u8 dialog_token,
3947 u16 status_code, u32 peer_capability,
3948 const u8 *buf, size_t len)
3949#else
3950/**
3951 * __wlan_hdd_cfg80211_tdls_mgmt() - handle management actions on a given peer
3952 * @wiphy: wiphy
3953 * @dev: net device
3954 * @peer: MAC address of the TDLS peer
3955 * @action_code: action code
3956 * @dialog_token: dialog token
3957 * @status_code: status code
3958 * @buf: additional IE to include
3959 * @len: length of buf in bytes
3960 *
3961 * Return: 0 if success; negative errno otherwise
3962 */
3963#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
3964static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
3965 struct net_device *dev, const uint8_t *peer,
3966 uint8_t action_code, uint8_t dialog_token,
3967 uint16_t status_code, uint32_t peer_capability,
3968 bool initiator, const uint8_t *buf,
3969 size_t len)
3970#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
3971static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
3972 struct net_device *dev, const uint8_t *peer,
3973 uint8_t action_code, uint8_t dialog_token,
3974 uint16_t status_code, uint32_t peer_capability,
3975 const uint8_t *buf, size_t len)
3976#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
3977static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
3978 struct net_device *dev, uint8_t *peer,
3979 uint8_t action_code, uint8_t dialog_token,
3980 uint16_t status_code, uint32_t peer_capability,
3981 const uint8_t *buf, size_t len)
3982#else
3983static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
3984 struct net_device *dev, uint8_t *peer,
3985 uint8_t action_code, uint8_t dialog_token,
3986 uint16_t status_code, const uint8_t *buf,
3987 size_t len)
3988#endif
3989#endif
3990{
3991
3992 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3993 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
Ganesh Kondabattinid6641d82015-12-11 19:58:35 +05303994 hdd_station_ctx_t *hdd_sta_ctx;
Nitesh Shah98097b92016-12-28 17:16:58 +05303995 tdlsCtx_t *hdd_tdls_ctx;
Anurag Chouhan6d760662016-02-20 16:05:43 +05303996 u8 peerMac[QDF_MAC_ADDR_SIZE];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303997 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003998 int max_sta_failed = 0;
3999 int responder;
4000 unsigned long rc;
4001 uint16_t numCurrTdlsPeers;
4002#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0))
4003#if !(TDLS_MGMT_VERSION2)
4004 u32 peer_capability;
4005 peer_capability = 0;
4006#endif
4007#endif
4008
Anurag Chouhan6d760662016-02-20 16:05:43 +05304009 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07004010 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004011 return -EINVAL;
4012 }
4013
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05304014 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
4015 hdd_err("invalid session id: %d", pAdapter->sessionId);
4016 return -EINVAL;
4017 }
4018
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304019 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004020 TRACE_CODE_HDD_CFG80211_TDLS_MGMT,
4021 pAdapter->sessionId, action_code));
4022
Abhishek Singh23edd1c2016-05-05 11:56:06 +05304023 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004024 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004025
4026 if (eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07004027 hdd_notice("TDLS mode is disabled OR not enabled in FW." MAC_ADDRESS_STR " action %d declined.",
4028 MAC_ADDR_ARRAY(peer), action_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004029 return -ENOTSUPP;
4030 }
4031
Ganesh Kondabattinid6641d82015-12-11 19:58:35 +05304032 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
4033
4034 /*
Kabilan Kannan163fd0b2016-06-08 15:21:51 -07004035 * STA or P2P client should be connected and authenticated before
4036 * sending any TDLS frames
Ganesh Kondabattinid6641d82015-12-11 19:58:35 +05304037 */
4038 if ((eConnectionState_Associated !=
4039 hdd_sta_ctx->conn_info.connState) ||
4040 (false == hdd_sta_ctx->conn_info.uIsAuthenticated)) {
4041 hdd_err("STA is not connected or not authenticated. connState %u, uIsAuthenticated %u",
4042 hdd_sta_ctx->conn_info.connState,
4043 hdd_sta_ctx->conn_info.uIsAuthenticated);
4044 return -EAGAIN;
4045 }
4046
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004047 /* other than teardown frame, mgmt frames are not sent if disabled */
4048 if (SIR_MAC_TDLS_TEARDOWN != action_code) {
Kabilan Kannan79c15932016-11-14 01:17:04 -08004049 if (!cds_check_is_tdls_allowed(pAdapter->device_mode)) {
4050 hdd_err("TDLS not allowed, reject TDLS MGMT, action_code=%d",
4051 action_code);
4052 return -EPERM;
4053 }
4054 /* if tdls_mode is disabled, then decline the peer's request */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004055 if (eTDLS_SUPPORT_DISABLED == pHddCtx->tdls_mode) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07004056 hdd_notice(MAC_ADDRESS_STR " TDLS mode is disabled. action %d declined.",
4057 MAC_ADDR_ARRAY(peer), action_code);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004058 return -ENOTSUPP;
Kabilan Kannan79c15932016-11-14 01:17:04 -08004059 }
4060 if (pHddCtx->tdls_nss_switch_in_progress) {
Archana Ramachandran7ba24ff2016-04-26 12:29:04 -07004061 hdd_err("TDLS antenna switch in progress, action %d declined for "
4062 MAC_ADDRESS_STR, action_code, MAC_ADDR_ARRAY(peer));
4063 return -EAGAIN;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004064 }
4065 }
4066
4067 if (WLAN_IS_TDLS_SETUP_ACTION(action_code)) {
Kabilan Kannan36090ce2016-05-03 19:28:44 -07004068 if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, peer,
4069 true, true)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304070 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004071 "%s: " MAC_ADDRESS_STR
4072 " TDLS setup is ongoing. action %d declined.",
4073 __func__, MAC_ADDR_ARRAY(peer), action_code);
4074 return -EPERM;
4075 }
4076 }
4077
4078 if (SIR_MAC_TDLS_SETUP_REQ == action_code ||
4079 SIR_MAC_TDLS_SETUP_RSP == action_code) {
4080 numCurrTdlsPeers = wlan_hdd_tdls_connected_peers(pAdapter);
4081 if (pHddCtx->max_num_tdls_sta <= numCurrTdlsPeers) {
Jeff Johnsonf1413bb2017-01-12 08:42:15 -08004082 /* supplicant still sends tdls_mgmt(SETUP_REQ)
4083 * even after we return error code at
4084 * 'add_station()'. Hence we have this check
Jeff Johnson68755312017-02-10 11:46:55 -08004085 * again in addition to add_station(). Anyway,
Jeff Johnsonf1413bb2017-01-12 08:42:15 -08004086 * there is no harm to double-check.
4087 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004088 if (SIR_MAC_TDLS_SETUP_REQ == action_code) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304089 QDF_TRACE(QDF_MODULE_ID_HDD,
4090 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004091 "%s: " MAC_ADDRESS_STR
4092 " TDLS Max peer already connected. action (%d) declined. Num of peers (%d), Max allowed (%d).",
4093 __func__, MAC_ADDR_ARRAY(peer),
4094 action_code, numCurrTdlsPeers,
4095 pHddCtx->max_num_tdls_sta);
4096 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004097 }
Jeff Johnson68755312017-02-10 11:46:55 -08004098 /* maximum reached. tweak to send
4099 * error code to peer and return error
4100 * code to supplicant
4101 */
4102 status_code = eSIR_MAC_UNSPEC_FAILURE_STATUS;
4103 QDF_TRACE(QDF_MODULE_ID_HDD,
4104 QDF_TRACE_LEVEL_ERROR,
4105 "%s: " MAC_ADDRESS_STR
4106 " TDLS Max peer already connected, send response status (%d). Num of peers (%d), Max allowed (%d).",
4107 __func__, MAC_ADDR_ARRAY(peer),
4108 status_code, numCurrTdlsPeers,
4109 pHddCtx->max_num_tdls_sta);
4110 max_sta_failed = -EPERM;
4111 /* fall through to send setup resp
4112 * with failure status code
4113 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004114 } else {
4115 hddTdlsPeer_t *pTdlsPeer;
4116 pTdlsPeer =
4117 wlan_hdd_tdls_find_peer(pAdapter, peer, true);
4118 if (pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304119 QDF_TRACE(QDF_MODULE_ID_HDD,
4120 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004121 "%s:" MAC_ADDRESS_STR
4122 " already connected. action %d declined.",
4123 __func__, MAC_ADDR_ARRAY(peer),
4124 action_code);
4125 return -EPERM;
4126 }
4127 }
4128 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304129 qdf_mem_copy(peerMac, peer, 6);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004130
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07004131 hdd_notice("tdls_mgmt" MAC_ADDRESS_STR " action %d, dialog_token %d status %d, len = %zu",
4132 MAC_ADDR_ARRAY(peer), action_code, dialog_token,
4133 status_code, len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004134
4135 /*Except teardown responder will not be used so just make 0 */
4136 responder = 0;
4137 if (SIR_MAC_TDLS_TEARDOWN == action_code) {
4138
4139 hddTdlsPeer_t *pTdlsPeer;
4140 pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peerMac, true);
4141
4142 if (pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer))
4143 responder = pTdlsPeer->is_responder;
4144 else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304145 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004146 "%s: " MAC_ADDRESS_STR
4147 " peer doesn't exist or not connected %d dialog_token %d status %d, len = %zu",
4148 __func__, MAC_ADDR_ARRAY(peer),
4149 (NULL ==
4150 pTdlsPeer) ? -1 : pTdlsPeer->link_status,
4151 dialog_token, status_code, len);
4152 return -EPERM;
4153 }
4154 }
4155
4156 /* For explicit trigger of DIS_REQ come out of BMPS for
Jeff Johnsonf1413bb2017-01-12 08:42:15 -08004157 * successfully receiving DIS_RSP from peer.
4158 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004159 if ((SIR_MAC_TDLS_SETUP_RSP == action_code) ||
Deepthi Gowri993ec182016-09-01 13:52:25 +05304160 (SIR_MAC_TDLS_SETUP_CNF == action_code) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004161 (SIR_MAC_TDLS_DIS_RSP == action_code) ||
4162 (SIR_MAC_TDLS_DIS_REQ == action_code)) {
4163 /* Fw will take care if PS offload is enabled. */
4164 if (SIR_MAC_TDLS_DIS_REQ != action_code)
4165 wlan_hdd_tdls_set_cap(pAdapter, peerMac,
4166 eTDLS_CAP_SUPPORTED);
4167 }
4168
4169 /* make sure doesn't call send_mgmt() while it is pending */
4170 if (TDLS_CTX_MAGIC == pAdapter->mgmtTxCompletionStatus) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304171 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004172 "%s: " MAC_ADDRESS_STR
4173 " action %d couldn't sent, as one is pending. return EBUSY",
4174 __func__, MAC_ADDR_ARRAY(peer), action_code);
4175 return -EBUSY;
4176 }
4177
4178 pAdapter->mgmtTxCompletionStatus = TDLS_CTX_MAGIC;
4179 INIT_COMPLETION(pAdapter->tdls_mgmt_comp);
4180
4181 status = sme_send_tdls_mgmt_frame(WLAN_HDD_GET_HAL_CTX(pAdapter),
4182 pAdapter->sessionId, peerMac,
4183 action_code, dialog_token, status_code,
4184 peer_capability, (uint8_t *) buf, len,
4185 !responder);
4186
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304187 if (QDF_STATUS_SUCCESS != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304188 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004189 "%s: sme_send_tdls_mgmt_frame failed!", __func__);
4190 pAdapter->mgmtTxCompletionStatus = false;
4191 return -EINVAL;
4192 }
4193
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07004194 if (SIR_MAC_TDLS_TEARDOWN == action_code &&
4195 pHddCtx->tdls_nss_switch_in_progress) {
4196 mutex_lock(&pHddCtx->tdls_lock);
4197 if (pHddCtx->tdls_teardown_peers_cnt != 0)
4198 pHddCtx->tdls_teardown_peers_cnt--;
Kabilan Kannanff89f742016-08-15 18:14:10 -07004199 if (pHddCtx->tdls_teardown_peers_cnt == 0) {
4200 if (pHddCtx->tdls_nss_transition_mode ==
4201 TDLS_NSS_TRANSITION_1x1_to_2x2) {
4202 /* TDLS NSS switch is fully completed, so
4203 * reset the flags.
4204 */
4205 hdd_info("TDLS NSS switch is fully completed");
4206 pHddCtx->tdls_nss_switch_in_progress = false;
4207 pHddCtx->tdls_nss_teardown_complete = false;
4208 } else {
4209 /* TDLS NSS switch is not yet completed, but
4210 * tdls teardown is completed for all the
4211 * peers.
4212 */
4213 hdd_info("TDLS teardown is completed and NSS switch still in progress");
4214 pHddCtx->tdls_nss_teardown_complete = true;
4215 }
4216 }
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07004217 mutex_unlock(&pHddCtx->tdls_lock);
4218 }
Ganesh Kondabattinid6641d82015-12-11 19:58:35 +05304219 hdd_info("Wait for tdls_mgmt_comp. Timeout %u ms",
4220 WAIT_TIME_TDLS_MGMT);
4221
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004222 rc = wait_for_completion_timeout(&pAdapter->tdls_mgmt_comp,
4223 msecs_to_jiffies(WAIT_TIME_TDLS_MGMT));
4224
4225 if ((0 == rc) || (true != pAdapter->mgmtTxCompletionStatus)) {
Masti, Narayanraddi6319f062016-09-03 18:49:22 +05304226 hdd_err("%s rc %ld mgmtTxCompletionStatus %u",
4227 !rc ? "Mgmt Tx Completion timed out" : "Mgmt Tx Completion failed",
4228 rc, pAdapter->mgmtTxCompletionStatus);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004229
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004230 if (cds_is_driver_recovering()) {
4231 hdd_err("Recovery in Progress. State: 0x%x Ignore!!!",
4232 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004233 return -EAGAIN;
4234 }
4235
Prashanth Bhatta9e143052015-12-04 11:56:47 -08004236 if (cds_is_driver_unloading()) {
4237 hdd_err("Unload in progress. State: 0x%x Ignore!!!",
4238 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004239 return -EAGAIN;
4240 }
Nitesh Shah98097b92016-12-28 17:16:58 +05304241
4242 mutex_lock(&pHddCtx->tdls_lock);
4243 hdd_tdls_ctx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
4244 if (hdd_tdls_ctx) {
4245 if (rc <= 0 &&
4246 (((qdf_get_monotonic_boottime() -
4247 hdd_tdls_ctx->last_flush_ts) >
4248 TDLS_ENABLE_CDS_FLUSH_INTERVAL)
4249 || !(hdd_tdls_ctx->last_flush_ts))) {
4250 hdd_tdls_ctx->last_flush_ts =
4251 qdf_get_monotonic_boottime();
4252 mutex_unlock(&pHddCtx->tdls_lock);
4253 cds_flush_logs(WLAN_LOG_TYPE_FATAL,
4254 WLAN_LOG_INDICATOR_HOST_DRIVER,
4255 WLAN_LOG_REASON_HDD_TIME_OUT,
4256 true, false);
4257 } else
4258 mutex_unlock(&pHddCtx->tdls_lock);
4259 } else
4260 mutex_unlock(&pHddCtx->tdls_lock);
4261
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004262 pAdapter->mgmtTxCompletionStatus = false;
4263 return -EINVAL;
4264 }
Ganesh Kondabattinid6641d82015-12-11 19:58:35 +05304265 hdd_info("Mgmt Tx Completion status %ld TxCompletion %u",
4266 rc, pAdapter->mgmtTxCompletionStatus);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004267
4268 if (max_sta_failed) {
4269 return max_sta_failed;
4270 }
4271
4272 if (SIR_MAC_TDLS_SETUP_RSP == action_code) {
4273 return wlan_hdd_tdls_set_responder(pAdapter, peerMac, false);
4274 } else if (SIR_MAC_TDLS_SETUP_CNF == action_code) {
4275 return wlan_hdd_tdls_set_responder(pAdapter, peerMac, true);
4276 }
4277
4278 return 0;
4279}
4280
4281/**
4282 * wlan_hdd_cfg80211_tdls_mgmt() - cfg80211 tdls mgmt handler function
4283 * @wiphy: Pointer to wiphy structure.
4284 * @dev: Pointer to net_device structure.
4285 * @peer: peer address
4286 * @action_code: action code
4287 * @dialog_token: dialog token
4288 * @status_code: status code
4289 * @peer_capability: peer capability
4290 * @buf: buffer
4291 * @len: Length of @buf
4292 *
4293 * This is the cfg80211 tdls mgmt handler function which invokes
4294 * the internal function @__wlan_hdd_cfg80211_tdls_mgmt with
4295 * SSR protection.
4296 *
4297 * Return: 0 for success, error number on failure.
4298 */
4299#if TDLS_MGMT_VERSION2
4300int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
4301 struct net_device *dev,
4302 u8 *peer, u8 action_code,
4303 u8 dialog_token,
4304 u16 status_code, u32 peer_capability,
4305 const u8 *buf, size_t len)
4306#else /* TDLS_MGMT_VERSION2 */
4307#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS)
4308int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
4309 struct net_device *dev,
4310 const u8 *peer, u8 action_code,
4311 u8 dialog_token, u16 status_code,
4312 u32 peer_capability, bool initiator,
4313 const u8 *buf, size_t len)
4314#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
4315int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
4316 struct net_device *dev,
4317 const u8 *peer, u8 action_code,
4318 u8 dialog_token, u16 status_code,
4319 u32 peer_capability, const u8 *buf,
4320 size_t len)
4321#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
4322int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
4323 struct net_device *dev,
4324 u8 *peer, u8 action_code,
4325 u8 dialog_token,
4326 u16 status_code, u32 peer_capability,
4327 const u8 *buf, size_t len)
4328#else
4329int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
4330 struct net_device *dev,
4331 u8 *peer, u8 action_code,
4332 u8 dialog_token,
4333 u16 status_code, const u8 *buf,
4334 size_t len)
4335#endif
4336#endif
4337{
4338 int ret;
4339
4340 cds_ssr_protect(__func__);
4341#if TDLS_MGMT_VERSION2
4342 ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code,
4343 dialog_token, status_code,
4344 peer_capability, buf, len);
4345#else /* TDLS_MGMT_VERSION2 */
4346#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS)
4347 ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code,
4348 dialog_token, status_code,
4349 peer_capability, initiator,
4350 buf, len);
4351#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
4352 ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code,
4353 dialog_token, status_code,
4354 peer_capability, buf, len);
4355#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
4356 ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code,
4357 dialog_token, status_code,
4358 peer_capability, buf, len);
4359#else
4360 ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code,
4361 dialog_token, status_code, buf, len);
4362#endif
4363#endif
4364
4365 cds_ssr_unprotect(__func__);
4366
4367 return ret;
4368}
4369
4370/**
4371 * wlan_hdd_tdls_extctrl_config_peer() - configure an externally controllable
4372 * TDLS peer
4373 * @pAdapter: HDD adapter
4374 * @peer: MAC address of the TDLS peer
4375 * @callback: Callback to set on the peer
4376 * @chan: Channel
4377 * @max_latency: Maximum latency
4378 * @op_class: Operation class
4379 * @min_bandwidth: Minimal bandwidth
4380 *
4381 * Return: 0 on success; negative otherwise
4382 */
4383int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter,
4384 const uint8_t *peer,
4385 cfg80211_exttdls_callback callback,
4386 u32 chan,
4387 u32 max_latency,
4388 u32 op_class, u32 min_bandwidth)
4389{
4390 hddTdlsPeer_t *pTdlsPeer;
4391 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304392 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004393 "%s : NL80211_TDLS_SETUP for " MAC_ADDRESS_STR,
4394 __func__, MAC_ADDR_ARRAY(peer));
4395 if ((false == pHddCtx->config->fTDLSExternalControl) ||
4396 (false == pHddCtx->config->fEnableTDLSImplicitTrigger)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304397 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004398 "%s TDLS External control or Implicit Trigger not enabled ",
4399 __func__);
4400 return -ENOTSUPP;
4401 }
Kabilan Kannan36090ce2016-05-03 19:28:44 -07004402 pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, peer, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004403 if (pTdlsPeer == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304404 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004405 "%s: peer " MAC_ADDRESS_STR " does not exist",
4406 __func__, MAC_ADDR_ARRAY(peer));
4407 return -EINVAL;
4408 }
4409 if (0 != wlan_hdd_tdls_set_force_peer(pAdapter, peer, true)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304410 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004411 "%s TDLS Add Force Peer Failed", __func__);
4412 return -EINVAL;
4413 }
Kabilan Kannan421714b2015-11-23 04:44:59 -08004414 /* Update the peer mac to firmware, so firmware
4415 * could update the connection table
4416 */
4417 if (0 != wlan_hdd_tdls_update_peer_mac(pAdapter, peer,
4418 eSME_TDLS_PEER_ADD_MAC_ADDR)) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07004419 hdd_err("TDLS Peer mac update Failed " MAC_ADDRESS_STR,
4420 MAC_ADDR_ARRAY(peer));
Kabilan Kannan421714b2015-11-23 04:44:59 -08004421 return -EINVAL;
4422 }
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07004423
Kabilan Kannan36090ce2016-05-03 19:28:44 -07004424 pHddCtx->tdls_external_peer_count++;
4425
4426 /* set tdls connection tracker state */
4427 cds_set_tdls_ct_mode(pHddCtx);
4428
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07004429 /* validate if off channel is DFS channel */
4430 if (CDS_IS_DFS_CH(chan)) {
4431 hdd_err("Resetting TDLS off-channel from %d to %d",
4432 chan, CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT);
4433 chan = CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT;
4434 }
4435
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004436 if (0 != wlan_hdd_tdls_set_extctrl_param(pAdapter, peer,
4437 chan, max_latency,
4438 op_class, min_bandwidth)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304439 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004440 "%s TDLS Set Peer's External Ctrl Parameter Failed",
4441 __func__);
4442 return -EINVAL;
4443 }
4444 if (0 != wlan_hdd_set_callback(pTdlsPeer, callback)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304445 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004446 "%s TDLS set callback Failed", __func__);
4447 return -EINVAL;
4448 }
4449 return 0;
4450}
4451
4452/**
4453 * wlan_hdd_tdls_extctrl_deconfig_peer() - de-configure an externally
4454 * controllable TDLS peer
4455 * @pAdapter: HDD adapter
4456 * @peer: MAC address of the tdls peer
4457 *
4458 * Return: 0 if success; negative errno otherwisw
4459 */
4460int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter,
4461 const uint8_t *peer)
4462{
4463 hddTdlsPeer_t *pTdlsPeer;
4464 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304465 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004466 "%s : NL80211_TDLS_TEARDOWN for " MAC_ADDRESS_STR,
4467 __func__, MAC_ADDR_ARRAY(peer));
4468 if ((false == pHddCtx->config->fTDLSExternalControl) ||
4469 (false == pHddCtx->config->fEnableTDLSImplicitTrigger)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304470 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004471 "%s TDLS External control or Implicit Trigger not enabled ",
4472 __func__);
4473 return -ENOTSUPP;
4474 }
4475 pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, true);
4476 if (NULL == pTdlsPeer) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07004477 hdd_notice("peer matching" MAC_ADDRESS_STR "not found",
4478 MAC_ADDR_ARRAY(peer));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004479 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004480 }
Jeff Johnson68755312017-02-10 11:46:55 -08004481
4482 wlan_hdd_tdls_indicate_teardown(pAdapter, pTdlsPeer,
4483 eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON);
4484 hdd_send_wlan_tdls_teardown_event(eTDLS_TEARDOWN_EXT_CTRL,
4485 pTdlsPeer->peerMac);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004486 if (0 != wlan_hdd_tdls_set_force_peer(pAdapter, peer, false)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304487 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004488 "%s Failed", __func__);
4489 return -EINVAL;
4490 }
Kabilan Kannan36090ce2016-05-03 19:28:44 -07004491
Kabilan Kannan421714b2015-11-23 04:44:59 -08004492 /* Update the peer mac to firmware, so firmware
4493 * could update the connection table
4494 */
4495 if (0 != wlan_hdd_tdls_update_peer_mac(pAdapter, peer,
4496 eSME_TDLS_PEER_REMOVE_MAC_ADDR)) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07004497 hdd_err("TDLS Peer mac update Failed " MAC_ADDRESS_STR,
4498 MAC_ADDR_ARRAY(peer));
Kabilan Kannan421714b2015-11-23 04:44:59 -08004499 return -EINVAL;
4500 }
Kabilan Kannan36090ce2016-05-03 19:28:44 -07004501
4502 if (pHddCtx->tdls_external_peer_count)
4503 pHddCtx->tdls_external_peer_count--;
4504
4505 /* set tdls connection tracker state */
4506 cds_set_tdls_ct_mode(pHddCtx);
4507
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004508 if (0 != wlan_hdd_set_callback(pTdlsPeer, NULL)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304509 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004510 "%s TDLS set callback Failed", __func__);
4511 return -EINVAL;
4512 }
4513 return 0;
4514}
4515
4516/**
4517 * __wlan_hdd_cfg80211_tdls_oper() - helper function to handle cfg80211 operation
4518 * on an TDLS peer
4519 * @wiphy: wiphy
4520 * @dev: net device
4521 * @peer: MAC address of the TDLS peer
4522 * @oper: cfg80211 TDLS operation
4523 *
4524 * Return: 0 on success; negative errno otherwise
4525 */
4526static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy,
4527 struct net_device *dev,
4528 const uint8_t *peer,
4529 enum nl80211_tdls_operation oper)
4530{
4531 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
4532 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
4533 int status;
4534 tSmeTdlsPeerStateParams smeTdlsPeerStateParams;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05304535 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004536 hddTdlsPeer_t *pTdlsPeer;
4537
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05304538 ENTER();
4539
Anurag Chouhan6d760662016-02-20 16:05:43 +05304540 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07004541 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004542 return -EINVAL;
4543 }
4544
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05304545 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
4546 hdd_err("invalid session id: %d", pAdapter->sessionId);
4547 return -EINVAL;
4548 }
4549
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304550 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004551 TRACE_CODE_HDD_CFG80211_TDLS_OPER,
4552 pAdapter->sessionId, oper));
4553 if (NULL == peer) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304554 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004555 "%s: Invalid arguments", __func__);
4556 return -EINVAL;
4557 }
4558
4559 status = wlan_hdd_validate_context(pHddCtx);
4560
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05304561 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004562 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004563
4564 /* QCA 2.0 Discrete ANDs feature capability in HDD config with that
4565 * received from target, so HDD config gives combined intersected result
4566 */
4567 if (false == pHddCtx->config->fEnableTDLSSupport) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304568 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004569 "TDLS Disabled in INI OR not enabled in FW. "
4570 "Cannot process TDLS commands");
4571 return -ENOTSUPP;
4572 }
4573
4574 switch (oper) {
4575 case NL80211_TDLS_ENABLE_LINK:
4576 {
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304577 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004578 unsigned long rc;
Hanumanth Reddy Pothula1891fe42016-09-08 14:10:33 +05304579 tCsrTdlsLinkEstablishParams tdlsLinkEstablishParams = { {0}, 0,
4580 0, 0, 0, 0, 0, {0}, 0, {0} };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004581
4582 pTdlsPeer =
4583 wlan_hdd_tdls_find_peer(pAdapter, peer, true);
4584
4585 if (NULL == pTdlsPeer) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304586 QDF_TRACE(QDF_MODULE_ID_HDD,
4587 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004588 "%s: peer matching " MAC_ADDRESS_STR
4589 " not found, ignore NL80211_TDLS_ENABLE_LINK",
4590 __func__, MAC_ADDR_ARRAY(peer));
4591 return -EINVAL;
4592 }
4593
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304594 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004595 "%s: NL80211_TDLS_ENABLE_LINK for peer "
4596 MAC_ADDRESS_STR " link_status: %d",
4597 __func__, MAC_ADDR_ARRAY(peer),
4598 pTdlsPeer->link_status);
4599
4600 if (!TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304601 QDF_TRACE(QDF_MODULE_ID_HDD,
4602 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004603 "%s: invalid sta index %u for "
4604 MAC_ADDRESS_STR
4605 " TDLS_ENABLE_LINK failed", __func__,
4606 pTdlsPeer->staId,
4607 MAC_ADDR_ARRAY(peer));
4608 return -EINVAL;
4609 }
Deepthi Gowri993ec182016-09-01 13:52:25 +05304610 wlan_hdd_tdls_set_cap(pAdapter, peer, eTDLS_CAP_SUPPORTED);
Nitesh Shah99934ac2016-09-05 15:54:08 +05304611
4612 qdf_mem_set(&tdlsLinkEstablishParams,
4613 sizeof(tdlsLinkEstablishParams), 0);
4614
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004615 if (eTDLS_LINK_CONNECTED != pTdlsPeer->link_status) {
4616 if (IS_ADVANCE_TDLS_ENABLE) {
4617
Nitesh Shah82c52812016-12-27 12:27:51 +05304618 hdd_info("Advance TDLS is enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004619 if (0 !=
4620 wlan_hdd_tdls_get_link_establish_params
4621 (pAdapter, peer,
4622 &tdlsLinkEstablishParams)) {
4623 return -EINVAL;
4624 }
4625 INIT_COMPLETION(pAdapter->
4626 tdls_link_establish_req_comp);
4627
4628 sme_send_tdls_link_establish_params
4629 (WLAN_HDD_GET_HAL_CTX(pAdapter),
4630 pAdapter->sessionId, peer,
4631 &tdlsLinkEstablishParams);
4632 /* Send TDLS peer UAPSD capabilities to the firmware and
4633 * register with the TL on after the response for this operation
4634 * is received .
4635 */
4636 rc = wait_for_completion_timeout
4637 (&pAdapter->
4638 tdls_link_establish_req_comp,
4639 msecs_to_jiffies
4640 (WAIT_TIME_TDLS_LINK_ESTABLISH_REQ));
4641 if (!rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304642 QDF_TRACE(QDF_MODULE_ID_HDD,
4643 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004644 "%s: Link Establish Request timed out",
4645 __func__);
4646 return -EINVAL;
4647 }
4648 }
4649 wlan_hdd_tdls_set_peer_link_status(pTdlsPeer,
4650 eTDLS_LINK_CONNECTED,
Kabilan Kannan36090ce2016-05-03 19:28:44 -07004651 eTDLS_LINK_SUCCESS,
4652 true);
Nitesh Shah99934ac2016-09-05 15:54:08 +05304653
4654 hdd_notice("%s: tdlsLinkEstablishParams of peer "
4655 MAC_ADDRESS_STR "uapsdQueues: %d"
4656 " qos: %d maxSp: %d isBufSta: %d"
4657 " isOffChannelSupported: %d"
4658 " isResponder: %d peerstaId: %d",
4659 __func__,
4660 MAC_ADDR_ARRAY(
4661 tdlsLinkEstablishParams.peerMac),
4662 tdlsLinkEstablishParams.uapsdQueues,
4663 tdlsLinkEstablishParams.qos,
4664 tdlsLinkEstablishParams.maxSp,
4665 tdlsLinkEstablishParams.isBufSta,
4666 tdlsLinkEstablishParams.isOffChannelSupported,
4667 tdlsLinkEstablishParams.isResponder,
4668 pTdlsPeer->staId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004669 /* start TDLS client registration with TL */
4670 status =
Agrawal Ashishd3f22f62016-09-04 13:46:15 +05304671 hdd_roam_register_tdlssta(
4672 pAdapter, peer,
4673 pTdlsPeer->staId,
4674 pTdlsPeer->signature,
Sen, Devendra4bbf40a2016-09-29 17:42:25 +05304675 pTdlsPeer->qos);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304676 if (QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004677 uint8_t i;
4678
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304679 qdf_mem_zero(&smeTdlsPeerStateParams,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004680 sizeof
4681 (tSmeTdlsPeerStateParams));
4682
4683 smeTdlsPeerStateParams.vdevId =
4684 pAdapter->sessionId;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304685 qdf_mem_copy(&smeTdlsPeerStateParams.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004686 peerMacAddr,
4687 &pTdlsPeer->peerMac,
4688 sizeof(tSirMacAddr));
4689 smeTdlsPeerStateParams.peerState =
4690 eSME_TDLS_PEER_STATE_CONNECTED;
4691 smeTdlsPeerStateParams.peerCap.
4692 isPeerResponder =
4693 pTdlsPeer->is_responder;
4694 smeTdlsPeerStateParams.peerCap.
4695 peerUapsdQueue =
4696 pTdlsPeer->uapsdQueues;
4697 smeTdlsPeerStateParams.peerCap.
4698 peerMaxSp = pTdlsPeer->maxSp;
4699 smeTdlsPeerStateParams.peerCap.
4700 peerBuffStaSupport =
4701 pTdlsPeer->isBufSta;
4702 smeTdlsPeerStateParams.peerCap.
4703 peerOffChanSupport =
4704 pTdlsPeer->isOffChannelSupported;
4705 smeTdlsPeerStateParams.peerCap.
4706 peerCurrOperClass = 0;
4707 smeTdlsPeerStateParams.peerCap.
4708 selfCurrOperClass = 0;
4709 smeTdlsPeerStateParams.peerCap.
4710 peerChanLen =
4711 pTdlsPeer->supported_channels_len;
4712 smeTdlsPeerStateParams.peerCap.
4713 prefOffChanNum =
4714 pTdlsPeer->pref_off_chan_num;
4715 smeTdlsPeerStateParams.peerCap.
4716 prefOffChanBandwidth =
4717 pHddCtx->config->
4718 fTDLSPrefOffChanBandwidth;
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05304719 smeTdlsPeerStateParams.peerCap.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004720 opClassForPrefOffChan =
4721 pTdlsPeer->
4722 op_class_for_pref_off_chan;
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05304723
Krishna Kumaar Natarajan4d090352015-10-26 18:30:53 -07004724 if (CDS_IS_DFS_CH(smeTdlsPeerStateParams.
4725 peerCap.prefOffChanNum)) {
4726 hdd_err("Resetting TDLS off-channel from %d to %d",
4727 smeTdlsPeerStateParams.peerCap.
4728 prefOffChanNum,
4729 CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT);
4730 smeTdlsPeerStateParams.peerCap.prefOffChanNum =
4731 CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT;
4732 }
4733
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304734 QDF_TRACE(QDF_MODULE_ID_HDD,
4735 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004736 "%s: Peer " MAC_ADDRESS_STR
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05304737 "vdevId: %d, peerState: %d, isPeerResponder: %d, uapsdQueues: 0x%x, maxSp: 0x%x, peerBuffStaSupport: %d, peerOffChanSupport: %d, peerCurrOperClass: %d, selfCurrOperClass: %d, peerChanLen: %d, peerOperClassLen: %d, prefOffChanNum: %d, prefOffChanBandwidth: %d, op_class_for_pref_off_chan: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004738 __func__,
4739 MAC_ADDR_ARRAY(peer),
4740 smeTdlsPeerStateParams.vdevId,
4741 smeTdlsPeerStateParams.
4742 peerState,
4743 smeTdlsPeerStateParams.
4744 peerCap.isPeerResponder,
4745 smeTdlsPeerStateParams.
4746 peerCap.peerUapsdQueue,
4747 smeTdlsPeerStateParams.
4748 peerCap.peerMaxSp,
4749 smeTdlsPeerStateParams.
4750 peerCap.peerBuffStaSupport,
4751 smeTdlsPeerStateParams.
4752 peerCap.peerOffChanSupport,
4753 smeTdlsPeerStateParams.
4754 peerCap.peerCurrOperClass,
4755 smeTdlsPeerStateParams.
4756 peerCap.selfCurrOperClass,
4757 smeTdlsPeerStateParams.
4758 peerCap.peerChanLen,
4759 smeTdlsPeerStateParams.
4760 peerCap.peerOperClassLen,
4761 smeTdlsPeerStateParams.
4762 peerCap.prefOffChanNum,
4763 smeTdlsPeerStateParams.
4764 peerCap.prefOffChanBandwidth,
4765 pTdlsPeer->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004766 op_class_for_pref_off_chan);
4767
4768 for (i = 0;
4769 i <
4770 pTdlsPeer->supported_channels_len;
4771 i++) {
4772 smeTdlsPeerStateParams.peerCap.
4773 peerChan[i] =
4774 pTdlsPeer->
4775 supported_channels[i];
4776 }
4777 smeTdlsPeerStateParams.peerCap.
4778 peerOperClassLen =
4779 pTdlsPeer->
4780 supported_oper_classes_len;
4781 for (i = 0;
4782 i <
4783 pTdlsPeer->
4784 supported_oper_classes_len; i++) {
4785 smeTdlsPeerStateParams.peerCap.
4786 peerOperClass[i] =
4787 pTdlsPeer->
4788 supported_oper_classes[i];
4789 }
4790
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05304791 qdf_ret_status =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004792 sme_update_tdls_peer_state(pHddCtx->
4793 hHal,
4794 &smeTdlsPeerStateParams);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304795 if (QDF_STATUS_SUCCESS !=
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05304796 qdf_ret_status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304797 QDF_TRACE(QDF_MODULE_ID_HDD,
4798 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004799 "%s: sme_update_tdls_peer_state failed for "
4800 MAC_ADDRESS_STR,
4801 __func__,
4802 MAC_ADDR_ARRAY(peer));
4803 return -EPERM;
4804 }
4805 wlan_hdd_tdls_increment_peer_count
4806 (pAdapter);
4807 }
4808
4809 /* Update TL about the UAPSD masks , to route the packets to firmware */
4810 if ((true ==
4811 pHddCtx->config->fEnableTDLSBufferSta)
4812 || pHddCtx->config->fTDLSUapsdMask) {
4813 int ac;
4814 uint8_t ucAc[4] = { SME_AC_VO,
4815 SME_AC_VI,
4816 SME_AC_BK,
4817 SME_AC_BE};
4818 uint8_t tlTid[4] = { 7, 5, 2, 3 };
Nitesh Shah82c52812016-12-27 12:27:51 +05304819 hdd_info("Update TL about UAPSD masks");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004820 for (ac = 0; ac < 4; ac++) {
4821 status = sme_enable_uapsd_for_ac(
4822 (WLAN_HDD_GET_CTX(pAdapter))->pcds_context,
4823 pTdlsPeer->staId, ucAc[ac],
4824 tlTid[ac], tlTid[ac], 0, 0,
4825 SME_BI_DIR, 1,
4826 pAdapter->sessionId,
4827 pHddCtx->config->DelayedTriggerFrmInt);
4828 }
4829 }
4830 }
Abhishek Singh74bcb0a2016-04-27 12:30:48 +05304831 hdd_wlan_tdls_enable_link_event(peer,
4832 pTdlsPeer->isOffChannelSupported,
4833 0, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004834 }
4835 break;
4836 case NL80211_TDLS_DISABLE_LINK:
4837 {
4838 pTdlsPeer =
4839 wlan_hdd_tdls_find_peer(pAdapter, peer, true);
4840
4841 if (NULL == pTdlsPeer) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304842 QDF_TRACE(QDF_MODULE_ID_HDD,
4843 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004844 "%s: peer matching " MAC_ADDRESS_STR
4845 " not found, ignore NL80211_TDLS_DISABLE_LINK",
4846 __func__, MAC_ADDR_ARRAY(peer));
4847 return -EINVAL;
4848 }
4849
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304850 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004851 "%s: NL80211_TDLS_DISABLE_LINK for peer "
4852 MAC_ADDRESS_STR " link_status: %d",
4853 __func__, MAC_ADDR_ARRAY(peer),
4854 pTdlsPeer->link_status);
4855
4856 if (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) {
4857 unsigned long rc;
4858
4859 INIT_COMPLETION(pAdapter->
4860 tdls_del_station_comp);
4861
4862 sme_delete_tdls_peer_sta(WLAN_HDD_GET_HAL_CTX
4863 (pAdapter),
4864 pAdapter->sessionId,
4865 peer);
4866
4867 rc = wait_for_completion_timeout(&pAdapter->
4868 tdls_del_station_comp,
4869 msecs_to_jiffies
4870 (WAIT_TIME_TDLS_DEL_STA));
4871 if (!rc) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304872 QDF_TRACE(QDF_MODULE_ID_HDD,
4873 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004874 "%s: Del station timed out",
4875 __func__);
4876 return -EPERM;
4877 }
4878 wlan_hdd_tdls_set_peer_link_status(pTdlsPeer,
4879 eTDLS_LINK_IDLE,
4880 (pTdlsPeer->link_status ==
4881 eTDLS_LINK_TEARING) ?
4882 eTDLS_LINK_UNSPECIFIED :
Kabilan Kannan36090ce2016-05-03 19:28:44 -07004883 eTDLS_LINK_DROPPED_BY_REMOTE,
4884 true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004885 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304886 QDF_TRACE(QDF_MODULE_ID_HDD,
4887 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004888 "%s: TDLS Peer Station doesn't exist.",
4889 __func__);
4890 }
4891 }
4892 break;
4893 case NL80211_TDLS_TEARDOWN:
4894 {
4895 status =
4896 wlan_hdd_tdls_extctrl_deconfig_peer(pAdapter, peer);
4897
4898 if (0 != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304899 QDF_TRACE(QDF_MODULE_ID_HDD,
4900 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004901 "%s: Error in TDLS Teardown",
4902 __func__);
4903 return status;
4904 }
4905 }
4906 break;
4907 case NL80211_TDLS_SETUP:
4908 {
4909 status = wlan_hdd_tdls_extctrl_config_peer(pAdapter,
4910 peer, NULL,
4911 pHddCtx->config->fTDLSPrefOffChanNum, 0, 0, 0);
4912 if (0 != status) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304913 QDF_TRACE(QDF_MODULE_ID_HDD,
4914 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004915 "%s: Error in TDLS Setup", __func__);
4916 return status;
4917 }
4918 }
4919 break;
4920 case NL80211_TDLS_DISCOVERY_REQ:
4921 /* We don't support in-driver setup/teardown/discovery */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304922 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004923 "%s: We don't support in-driver setup/teardown/discovery",
4924 __func__);
4925 return -ENOTSUPP;
4926 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304927 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Agrawal Ashisha5c2bdc2015-09-16 16:58:41 +05304928 "%s: unsupported event %d", __func__, oper);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004929 return -ENOTSUPP;
4930 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05304931 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004932 return 0;
4933}
4934
4935/**
4936 * wlan_hdd_cfg80211_tdls_oper() - handle cfg80211 operation on an TDLS peer
4937 * @wiphy: wiphy
4938 * @dev: net device
4939 * @peer: MAC address of the TDLS peer
4940 * @oper: cfg80211 TDLS operation
4941 *
4942 * Return: 0 on success; negative errno otherwise
4943 */
4944#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
4945int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy,
4946 struct net_device *dev,
4947 const uint8_t *peer,
4948 enum nl80211_tdls_operation oper)
4949#else
4950int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy,
4951 struct net_device *dev,
4952 uint8_t *peer,
4953 enum nl80211_tdls_operation oper)
4954#endif
4955{
4956 int ret;
4957
4958 cds_ssr_protect(__func__);
4959 ret = __wlan_hdd_cfg80211_tdls_oper(wiphy, dev, peer, oper);
4960 cds_ssr_unprotect(__func__);
4961
4962 return ret;
4963}
4964
4965/**
4966 * wlan_hdd_cfg80211_send_tdls_discover_req() - send out TDLS discovery for
4967 * a TDLS peer
4968 * @wiphy: wiphy
4969 * @dev: net device
4970 * @peer: MAC address of the peer
4971 *
4972 * Return: 0 if success; negative errno otherwise
4973 */
4974int wlan_hdd_cfg80211_send_tdls_discover_req(struct wiphy *wiphy,
4975 struct net_device *dev, u8 *peer)
4976{
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07004977 hdd_notice("tdls send discover req: " MAC_ADDRESS_STR,
4978 MAC_ADDR_ARRAY(peer));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004979#if TDLS_MGMT_VERSION2
4980 return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer,
4981 WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, 0,
4982 NULL, 0);
4983#else
4984#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
4985 return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer,
4986 WLAN_TDLS_DISCOVERY_REQUEST, 1, 0,
4987 0, 0, NULL, 0);
4988#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
4989 return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer,
4990 WLAN_TDLS_DISCOVERY_REQUEST, 1, 0,
4991 0, NULL, 0);
4992#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
4993 return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer,
4994 WLAN_TDLS_DISCOVERY_REQUEST, 1, 0,
4995 0, NULL, 0);
4996#else
4997 return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer,
4998 WLAN_TDLS_DISCOVERY_REQUEST, 1, 0,
4999 NULL, 0);
5000#endif
5001#endif
5002}
5003
5004#endif /* End of FEATURE_WLAN_TDLS */
5005
5006/**
5007 * wlan_hdd_tdls_find_first_connected_peer() - find the 1st connected tdls peer
5008 * @adapter: Pointer to the HDD adapter
5009 *
5010 * This function searchs for the 1st connected TDLS peer
5011 *
5012 * Return: The first connected TDLS peer if found; NULL otherwise
5013 */
5014hddTdlsPeer_t *wlan_hdd_tdls_find_first_connected_peer(hdd_adapter_t *adapter)
5015{
5016 int i;
5017 struct list_head *head;
5018 struct list_head *pos;
5019 hddTdlsPeer_t *curr_peer = NULL;
5020 tdlsCtx_t *hdd_tdls_ctx;
5021 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5022
Abhishek Singh23edd1c2016-05-05 11:56:06 +05305023 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005024 return NULL;
Abhishek Singh23edd1c2016-05-05 11:56:06 +05305025
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005026 mutex_lock(&hdd_ctx->tdls_lock);
5027 hdd_tdls_ctx = WLAN_HDD_GET_TDLS_CTX_PTR(adapter);
5028 if (NULL == hdd_tdls_ctx) {
5029 mutex_unlock(&hdd_ctx->tdls_lock);
5030 return NULL;
5031 }
5032 for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
5033 head = &hdd_tdls_ctx->peer_list[i];
5034 list_for_each(pos, head) {
5035 curr_peer = list_entry(pos, hddTdlsPeer_t, node);
5036 if (curr_peer && (curr_peer->link_status ==
5037 eTDLS_LINK_CONNECTED)) {
5038 mutex_unlock(&hdd_ctx->tdls_lock);
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005039 hdd_notice(MAC_ADDRESS_STR" eTDLS_LINK_CONNECTED",
5040 MAC_ADDR_ARRAY(curr_peer->peerMac));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005041 return curr_peer;
5042 }
5043 }
5044 }
5045 mutex_unlock(&hdd_ctx->tdls_lock);
5046 return NULL;
5047}
5048
5049/**
5050 * hdd_set_tdls_offchannel() - set tdls off-channel number
5051 * @adapter: Pointer to the HDD adapter
5052 * @offchanmode: tdls off-channel number
5053 *
5054 * This function sets tdls off-channel number
5055 *
5056 * Return: 0 on success; negative errno otherwise
5057 */
5058int hdd_set_tdls_offchannel(hdd_context_t *hdd_ctx, int offchannel)
5059{
5060 if ((true == hdd_ctx->config->fEnableTDLSOffChannel) &&
Kabilan Kannan421714b2015-11-23 04:44:59 -08005061 (eTDLS_SUPPORT_ENABLED == hdd_ctx->tdls_mode ||
5062 eTDLS_SUPPORT_EXTERNAL_CONTROL == hdd_ctx->tdls_mode ||
5063 eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == hdd_ctx->tdls_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005064 if (offchannel < CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN ||
5065 offchannel > CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005066 hdd_err("Invalid tdls off channel %u", offchannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005067 return -EINVAL;
5068 }
5069 } else {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005070 hdd_err("Either TDLS or TDLS Off-channel is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005071 return -ENOTSUPP;
5072 }
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005073 hdd_notice("change tdls off channel from %d to %d",
5074 hdd_ctx->tdls_off_channel, offchannel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005075 hdd_ctx->tdls_off_channel = offchannel;
5076 return 0;
5077}
5078
5079/**
5080 * hdd_set_tdls_secoffchanneloffset() - set secondary tdls off-channel offset
5081 * @adapter: Pointer to the HDD adapter
5082 * @offchanmode: tdls off-channel offset
5083 *
5084 * This function sets 2nd tdls off-channel offset
5085 *
5086 * Return: 0 on success; negative errno otherwise
5087 */
5088int hdd_set_tdls_secoffchanneloffset(hdd_context_t *hdd_ctx, int offchanoffset)
5089{
5090 if ((true == hdd_ctx->config->fEnableTDLSOffChannel) &&
Kabilan Kannan421714b2015-11-23 04:44:59 -08005091 (eTDLS_SUPPORT_ENABLED == hdd_ctx->tdls_mode ||
5092 eTDLS_SUPPORT_EXTERNAL_CONTROL == hdd_ctx->tdls_mode ||
5093 eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == hdd_ctx->tdls_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005094 hdd_ctx->tdls_channel_offset = 0;
5095
5096 switch (offchanoffset) {
5097 case TDLS_SEC_OFFCHAN_OFFSET_0:
5098 hdd_ctx->tdls_channel_offset = (1 << BW_20_OFFSET_BIT);
5099 break;
5100 case TDLS_SEC_OFFCHAN_OFFSET_40PLUS:
5101 case TDLS_SEC_OFFCHAN_OFFSET_40MINUS:
5102 hdd_ctx->tdls_channel_offset = (1 << BW_40_OFFSET_BIT);
5103 break;
5104 case TDLS_SEC_OFFCHAN_OFFSET_80:
5105 hdd_ctx->tdls_channel_offset = (1 << BW_80_OFFSET_BIT);
5106 break;
5107 case TDLS_SEC_OFFCHAN_OFFSET_160:
5108 hdd_ctx->tdls_channel_offset = (1 << BW_160_OFFSET_BIT);
5109 break;
5110 default:
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005111 hdd_err("Invalid tdls secondary off channel offset %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005112 offchanoffset);
5113 return -EINVAL;
5114 } /* end switch */
5115 } else {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005116 hdd_err("Either TDLS or TDLS Off-channel is not enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005117 return -ENOTSUPP;
5118 }
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005119 hdd_notice("change tdls secondary off channel offset to 0x%x",
5120 hdd_ctx->tdls_channel_offset);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005121 return 0;
5122}
5123
5124/**
5125 * hdd_set_tdls_offchannelmode() - set tdls off-channel mode
5126 * @adapter: Pointer to the HDD adapter
5127 * @offchanmode: tdls off-channel mode
5128 *
5129 * This function sets tdls off-channel mode
5130 *
5131 * Return: 0 on success; negative errno otherwise
5132 */
5133int hdd_set_tdls_offchannelmode(hdd_adapter_t *adapter, int offchanmode)
5134{
5135 hddTdlsPeer_t *conn_peer = NULL;
5136 hdd_station_ctx_t *hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5137 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5138 sme_tdls_chan_switch_params chan_switch_params;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305139 QDF_STATUS status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005140
5141 if (offchanmode < ENABLE_CHANSWITCH ||
5142 offchanmode > DISABLE_CHANSWITCH) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005143 hdd_err("Invalid tdls off channel mode %d", offchanmode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005144 return -EINVAL;
5145 }
5146 if (eConnectionState_Associated != hdd_sta_ctx->conn_info.connState) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005147 hdd_err("tdls off channel mode req in not associated state %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005148 offchanmode);
5149 return -EPERM;
5150 }
5151 if ((true == hdd_ctx->config->fEnableTDLSOffChannel) &&
5152 (eTDLS_SUPPORT_ENABLED == hdd_ctx->tdls_mode ||
Kabilan Kannan421714b2015-11-23 04:44:59 -08005153 eTDLS_SUPPORT_EXTERNAL_CONTROL == hdd_ctx->tdls_mode ||
5154 eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == hdd_ctx->tdls_mode)) {
5155 conn_peer = wlan_hdd_tdls_find_first_connected_peer(adapter);
5156 if (NULL == conn_peer) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005157 hdd_err("No TDLS Connected Peer");
Kabilan Kannan421714b2015-11-23 04:44:59 -08005158 return -EPERM;
5159 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005160 } else {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005161 hdd_err("TDLS Connection not supported");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005162 return -ENOTSUPP;
5163 }
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05305164
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005165 hdd_notice("TDLS Channel Switch in swmode=%d tdls_off_channel %d offchanoffset %d",
5166 offchanmode, hdd_ctx->tdls_off_channel,
5167 hdd_ctx->tdls_channel_offset);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005168
5169 switch (offchanmode) {
5170 case ENABLE_CHANSWITCH:
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05305171 if (hdd_ctx->tdls_off_channel &&
5172 hdd_ctx->tdls_channel_offset) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005173 chan_switch_params.tdls_off_channel =
5174 hdd_ctx->tdls_off_channel;
5175 chan_switch_params.tdls_off_ch_bw_offset =
5176 hdd_ctx->tdls_channel_offset;
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05305177 chan_switch_params.opclass =
5178 wlan_hdd_find_opclass(WLAN_HDD_GET_HAL_CTX(adapter),
5179 chan_switch_params.tdls_off_channel,
5180 chan_switch_params.tdls_off_ch_bw_offset);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005181 } else {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005182 hdd_err("TDLS off-channel parameters are not set yet!!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005183 return -EINVAL;
5184 }
5185 break;
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05305186 case DISABLE_CHANSWITCH:
5187 chan_switch_params.tdls_off_channel = 0;
5188 chan_switch_params.tdls_off_ch_bw_offset = 0;
5189 chan_switch_params.opclass = 0;
5190 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005191 default:
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005192 hdd_err("Incorrect Parameters mode: %d tdls_off_channel: %d offchanoffset: %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005193 offchanmode, hdd_ctx->tdls_off_channel,
5194 hdd_ctx->tdls_channel_offset);
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05305195 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005196 } /* end switch */
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05305197
5198 chan_switch_params.vdev_id = adapter->sessionId;
5199 chan_switch_params.tdls_off_ch_mode = offchanmode;
5200 chan_switch_params.is_responder =
5201 conn_peer->is_responder;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05305202 qdf_mem_copy(&chan_switch_params.peer_mac_addr,
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05305203 &conn_peer->peerMac,
5204 sizeof(tSirMacAddr));
Jeff Johnsone1c143e2016-08-23 13:09:03 -07005205 hdd_info("Peer " MAC_ADDRESS_STR
5206 " vdevId: %d, off channel: %d, offset: %d, mode: %d, is_responder: %d",
5207 MAC_ADDR_ARRAY(chan_switch_params.peer_mac_addr),
5208 chan_switch_params.vdev_id,
5209 chan_switch_params.tdls_off_channel,
5210 chan_switch_params.tdls_off_ch_bw_offset,
5211 chan_switch_params.tdls_off_ch_mode,
5212 chan_switch_params.is_responder);
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05305213
5214 status = sme_send_tdls_chan_switch_req(WLAN_HDD_GET_HAL_CTX(adapter),
5215 &chan_switch_params);
5216
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05305217 if (status != QDF_STATUS_SUCCESS) {
Jeff Johnsone1c143e2016-08-23 13:09:03 -07005218 hdd_err("Failed to send channel switch request to sme");
Masti, Narayanraddic4a7ab82015-11-25 15:41:10 +05305219 return -EINVAL;
5220 }
5221
5222 hdd_ctx->tdls_fw_off_chan_mode = offchanmode;
5223
5224 if (ENABLE_CHANSWITCH == offchanmode) {
5225 conn_peer->pref_off_chan_num =
5226 chan_switch_params.tdls_off_channel;
5227 conn_peer->op_class_for_pref_off_chan =
5228 chan_switch_params.opclass;
5229 }
5230
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005231 return 0;
5232}
5233
5234/**
Kabilan Kannan36090ce2016-05-03 19:28:44 -07005235 * wlan_hdd_tdls_ct_sampling_tx_rx() - collect tx/rx traffic sample
5236 * @adapter: pointer to hdd adapter
5237 * @hdd_ctx: hdd context
5238 * @tdls_ctx: tdls context
5239 *
5240 * Function to update data traffic information in tdls connection
5241 * tracker data structure for connection tracker operation
5242 *
5243 * Return: None
5244 */
5245static void wlan_hdd_tdls_ct_sampling_tx_rx(hdd_adapter_t *adapter,
5246 hdd_context_t *hdd_ctx,
5247 tdlsCtx_t *tdls_ctx)
5248{
5249 hddTdlsPeer_t *curr_peer;
5250 uint8_t mac[QDF_MAC_ADDR_SIZE];
5251 uint8_t mac_cnt;
5252 uint8_t valid_mac_entries;
5253 struct tdls_ct_mac_table ct_peer_mac_table[TDLS_CT_MAC_MAX_TABLE_SIZE];
5254
Kabilan Kannan24389de2016-08-10 18:15:59 -07005255 qdf_spin_lock_bh(&hdd_ctx->tdls_ct_spinlock);
Kabilan Kannan36090ce2016-05-03 19:28:44 -07005256
5257 if (0 == tdls_ctx->valid_mac_entries) {
Kabilan Kannan24389de2016-08-10 18:15:59 -07005258 qdf_spin_unlock_bh(&hdd_ctx->tdls_ct_spinlock);
Kabilan Kannan36090ce2016-05-03 19:28:44 -07005259 return;
5260 }
5261
5262 valid_mac_entries = tdls_ctx->valid_mac_entries;
5263
5264 memcpy(ct_peer_mac_table, tdls_ctx->ct_peer_mac_table,
5265 (sizeof(struct tdls_ct_mac_table)) * valid_mac_entries);
5266
5267 memset(tdls_ctx->ct_peer_mac_table, 0,
5268 (sizeof(struct tdls_ct_mac_table)) * valid_mac_entries);
5269
5270 tdls_ctx->valid_mac_entries = 0;
5271
Kabilan Kannan24389de2016-08-10 18:15:59 -07005272 qdf_spin_unlock_bh(&hdd_ctx->tdls_ct_spinlock);
Kabilan Kannan36090ce2016-05-03 19:28:44 -07005273
5274 for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) {
5275 memcpy(mac, ct_peer_mac_table[mac_cnt].mac_address.bytes,
5276 QDF_MAC_ADDR_SIZE);
5277 curr_peer = wlan_hdd_tdls_get_peer(adapter, mac, false);
5278 if (NULL != curr_peer) {
5279 curr_peer->tx_pkt =
5280 ct_peer_mac_table[mac_cnt].tx_packet_cnt;
5281 curr_peer->rx_pkt =
5282 ct_peer_mac_table[mac_cnt].rx_packet_cnt;
5283 }
5284 }
5285}
5286
5287/**
5288 * wlan_hdd_tdls_update_rx_pkt_cnt() - Update rx packet count
5289 * @adapter: pointer to hdd adapter
5290 * @skb: pointer to sk_buff
5291 *
5292 * Increase the rx packet count, if the sender is not bssid and the packet is
5293 * not broadcast and muticast packet
5294 *
5295 * This sampling information will be used in TDLS connection tracker
5296 *
5297 * This function expected to be called in an atomic context so blocking APIs
5298 * not allowed
5299 *
5300 * Return: None
5301 */
5302void wlan_hdd_tdls_update_rx_pkt_cnt(hdd_adapter_t *adapter,
5303 struct sk_buff *skb)
5304{
5305 hdd_context_t *hdd_ctx;
5306 hdd_station_ctx_t *hdd_sta_ctx;
5307 tdlsCtx_t *tdls_ctx;
5308 uint8_t mac_cnt;
5309 uint8_t valid_mac_entries;
5310 struct qdf_mac_addr *mac_addr;
5311
Kabilan Kannan32eb5022016-10-04 12:24:50 -07005312 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5313
5314 if (!hdd_ctx->enable_tdls_connection_tracker)
5315 return;
5316
Kabilan Kannan36090ce2016-05-03 19:28:44 -07005317 mac_addr = (struct qdf_mac_addr *)(skb->data+QDF_MAC_ADDR_SIZE);
5318 if (qdf_is_macaddr_group(mac_addr))
5319 return;
5320
5321 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5322 if (memcmp(hdd_sta_ctx->conn_info.bssId.bytes,
5323 mac_addr, QDF_MAC_ADDR_SIZE) == 0)
5324 return;
5325
Kabilan Kannan36090ce2016-05-03 19:28:44 -07005326 tdls_ctx = adapter->sessionCtx.station.pHddTdlsCtx;
5327
Kabilan Kannan24389de2016-08-10 18:15:59 -07005328 qdf_spin_lock_bh(&hdd_ctx->tdls_ct_spinlock);
Kabilan Kannan36090ce2016-05-03 19:28:44 -07005329 valid_mac_entries = tdls_ctx->valid_mac_entries;
5330
5331 for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) {
5332 if (memcmp(tdls_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes,
5333 mac_addr, QDF_MAC_ADDR_SIZE) == 0) {
5334 tdls_ctx->ct_peer_mac_table[mac_cnt].rx_packet_cnt++;
5335 goto rx_cnt_return;
5336 }
5337 }
5338
5339 /* If we have more than 8 peers within 30 mins. we will
5340 * stop tracking till the old entries are removed
5341 */
5342 if (mac_cnt < TDLS_CT_MAC_MAX_TABLE_SIZE) {
5343 memcpy(tdls_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes,
5344 mac_addr, QDF_MAC_ADDR_SIZE);
5345 tdls_ctx->valid_mac_entries = mac_cnt+1;
5346 tdls_ctx->ct_peer_mac_table[mac_cnt].rx_packet_cnt = 1;
5347 }
5348
5349rx_cnt_return:
Kabilan Kannan24389de2016-08-10 18:15:59 -07005350 qdf_spin_unlock_bh(&hdd_ctx->tdls_ct_spinlock);
Kabilan Kannan36090ce2016-05-03 19:28:44 -07005351 return;
5352}
5353
5354/**
5355 * wlan_hdd_tdls_update_tx_pkt_cnt() - update tx packet
5356 * @adapter: pointer to hdd adapter
5357 * @skb: pointer to sk_buff
5358 *
5359 * Increase the tx packet count, if the sender is not bssid and the packet is
5360 * not broadcast and muticast packet
5361 *
5362 * This sampling information will be used in TDLS connection tracker
5363 *
5364 * This function expected to be called in an atomic context so blocking APIs
5365 * not allowed
5366 *
5367 * Return: None
5368 */
5369void wlan_hdd_tdls_update_tx_pkt_cnt(hdd_adapter_t *adapter,
5370 struct sk_buff *skb)
5371{
5372 hdd_context_t *hdd_ctx;
5373 hdd_station_ctx_t *hdd_sta_ctx;
5374 tdlsCtx_t *tdls_ctx;
5375 uint8_t mac_cnt;
5376 uint8_t valid_mac_entries;
5377 struct qdf_mac_addr *mac_addr;
5378
Kabilan Kannan32eb5022016-10-04 12:24:50 -07005379 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5380
5381 if (!hdd_ctx->enable_tdls_connection_tracker)
5382 return;
5383
Kabilan Kannan36090ce2016-05-03 19:28:44 -07005384 mac_addr = (struct qdf_mac_addr *)skb->data;
5385 if (qdf_is_macaddr_group(mac_addr))
5386 return;
5387
5388 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5389 if (memcmp(hdd_sta_ctx->conn_info.bssId.bytes, mac_addr,
5390 QDF_MAC_ADDR_SIZE) == 0)
5391 return;
5392
Kabilan Kannan36090ce2016-05-03 19:28:44 -07005393 tdls_ctx = adapter->sessionCtx.station.pHddTdlsCtx;
5394
Kabilan Kannan24389de2016-08-10 18:15:59 -07005395 qdf_spin_lock_bh(&hdd_ctx->tdls_ct_spinlock);
Kabilan Kannan36090ce2016-05-03 19:28:44 -07005396 valid_mac_entries = tdls_ctx->valid_mac_entries;
5397
5398 for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) {
5399 if (memcmp(tdls_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes,
5400 mac_addr, QDF_MAC_ADDR_SIZE) == 0) {
5401 tdls_ctx->ct_peer_mac_table[mac_cnt].tx_packet_cnt++;
5402 goto tx_cnt_return;
5403 }
5404 }
5405
5406 /* If we have more than 8 peers within 30 mins. we will
5407 * stop tracking till the old entries are removed
5408 */
5409 if (mac_cnt < TDLS_CT_MAC_MAX_TABLE_SIZE) {
5410 memcpy(tdls_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes,
5411 mac_addr, QDF_MAC_ADDR_SIZE);
5412 tdls_ctx->ct_peer_mac_table[mac_cnt].tx_packet_cnt = 1;
5413 tdls_ctx->valid_mac_entries++;
5414 }
5415
5416tx_cnt_return:
Kabilan Kannan24389de2016-08-10 18:15:59 -07005417 qdf_spin_unlock_bh(&hdd_ctx->tdls_ct_spinlock);
Kabilan Kannan36090ce2016-05-03 19:28:44 -07005418 return;
5419}
5420
5421/**
5422 * wlan_hdd_tdls_implicit_send_discovery_request() - send discovery request
5423 * @hdd_tdls_ctx: tdls context
5424 *
5425 * Return: None
5426 */
Kabilan Kannan36090ce2016-05-03 19:28:44 -07005427void wlan_hdd_tdls_implicit_send_discovery_request(tdlsCtx_t *hdd_tdls_ctx)
5428{
5429 hdd_context_t *hdd_ctx;
5430 hddTdlsPeer_t *curr_peer, *temp_peer;
5431
5432 ENTER();
5433 if (NULL == hdd_tdls_ctx) {
5434 hdd_info("hdd_tdls_ctx is NULL");
5435 return;
5436 }
5437
5438 hdd_ctx = WLAN_HDD_GET_CTX(hdd_tdls_ctx->pAdapter);
5439
5440 if (0 != (wlan_hdd_validate_context(hdd_ctx)))
5441 return;
5442
5443 curr_peer = hdd_tdls_ctx->curr_candidate;
5444 if (NULL == curr_peer) {
5445 hdd_err("curr_peer is NULL");
5446 return;
5447 }
5448
5449 /* This function is called in mutex_lock */
5450 temp_peer = wlan_hdd_tdls_is_progress(hdd_ctx, NULL, 0, false);
5451 if (NULL != temp_peer) {
5452 hdd_info(MAC_ADDRESS_STR " ongoing. pre_setup ignored",
5453 MAC_ADDR_ARRAY(temp_peer->peerMac));
5454 goto done;
5455 }
5456
5457 if (eTDLS_CAP_UNKNOWN != curr_peer->tdls_support)
5458 wlan_hdd_tdls_set_peer_link_status(curr_peer,
5459 eTDLS_LINK_DISCOVERING,
5460 eTDLS_LINK_SUCCESS,
5461 false);
5462
5463 hdd_info("Implicit TDLS, Send Discovery request event");
5464 cfg80211_tdls_oper_request(hdd_tdls_ctx->pAdapter->dev,
5465 curr_peer->peerMac,
5466 NL80211_TDLS_DISCOVERY_REQ,
5467 false,
5468 GFP_KERNEL);
5469 hdd_tdls_ctx->discovery_sent_cnt++;
5470
5471 wlan_hdd_tdls_timer_restart(hdd_tdls_ctx->pAdapter,
5472 &hdd_tdls_ctx->peerDiscoveryTimeoutTimer,
5473 hdd_tdls_ctx->threshold_config.tx_period_t -
5474 TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE);
5475
5476 hdd_info("discovery count %u timeout %u msec",
5477 hdd_tdls_ctx->discovery_sent_cnt,
5478 hdd_tdls_ctx->threshold_config.tx_period_t -
5479 TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE);
5480done:
5481 hdd_tdls_ctx->curr_candidate = NULL;
5482 hdd_tdls_ctx->magic = 0;
5483 EXIT();
5484 return;
5485}
5486
5487/**
5488 * wlan_hdd_get_conn_info() - get the tdls connection information.
5489 * @hdd_ctx: hdd context
5490 * @hdd_ctx: sta id
5491 *
5492 * Function to check tdls sta index
5493 *
5494 * Return: None
5495 */
5496static tdlsConnInfo_t *wlan_hdd_get_conn_info(hdd_context_t *hdd_ctx,
5497 uint8_t idx)
5498{
5499 uint8_t sta_idx;
5500
5501 /* check if there is available index for this new TDLS STA */
5502 for (sta_idx = 0; sta_idx < HDD_MAX_NUM_TDLS_STA; sta_idx++) {
5503 if (idx == hdd_ctx->tdlsConnInfo[sta_idx].staId) {
5504 hdd_info("tdls peer with staIdx %u exists", idx);
5505 return &hdd_ctx->tdlsConnInfo[sta_idx];
5506 }
5507 }
5508 hdd_err("tdls peer with staIdx %u not exists", idx);
5509 return NULL;
5510}
5511
5512/**
5513 * wlan_hdd_tdls_idle_handler() - Check tdls idle traffic
5514 * @user_data: data from tdls idle timer
5515 *
5516 * Function to check the tdls idle traffic and make a decision about
5517 * tdls teardown
5518 *
5519 * Return: None
5520 */
5521static void wlan_hdd_tdls_idle_handler(void *user_data)
5522{
5523 tdlsConnInfo_t *tdls_info = (tdlsConnInfo_t *) user_data;
5524 hddTdlsPeer_t *curr_peer;
5525 tdlsCtx_t *hdd_tdls_ctx;
5526 hdd_context_t *hdd_ctx;
5527 v_CONTEXT_t cds_context;
5528 hdd_adapter_t *adapter;
5529
5530 if (!tdls_info->staId) {
5531 hdd_err("peer (staidx %u) doesn't exists", tdls_info->staId);
5532 return;
5533 }
5534
5535 cds_context = cds_get_global_context();
5536 if (NULL == cds_context) {
5537 hdd_err("cds_context points to NULL");
5538 return;
5539 }
5540
5541 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
5542 if (0 != (wlan_hdd_validate_context(hdd_ctx)))
5543 return;
5544
5545 adapter = hdd_get_adapter_by_sme_session_id(hdd_ctx,
5546 tdls_info->sessionId);
5547
5548 if (!adapter) {
5549 hdd_err("adapter is NULL");
5550 return;
5551 }
5552
5553 curr_peer = wlan_hdd_tdls_find_peer(adapter,
5554 (u8 *) &tdls_info->peerMac.bytes[0], true);
5555
5556 if (NULL == curr_peer) {
5557 hdd_err("Invalid tdls idle timer expired");
5558 goto error_idle_return;
5559 }
5560
5561 hdd_tdls_ctx = curr_peer->pHddTdlsCtx;
5562 if (NULL == hdd_tdls_ctx) {
5563 hdd_err("Invalid hdd_tdls_ctx context");
5564 goto error_idle_return;
5565 }
5566
5567 hdd_info(MAC_ADDRESS_STR " tx_pkt: %d, rx_pkt: %d, idle_packet_n: %d",
5568 MAC_ADDR_ARRAY(curr_peer->peerMac),
5569 curr_peer->tx_pkt,
5570 curr_peer->rx_pkt,
5571 curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n);
5572
5573 /* Check tx/rx statistics on this tdls link for recent activities and
5574 * then decide whether to tear down the link or keep it.
5575 */
5576 if ((curr_peer->tx_pkt >=
5577 curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n) ||
5578 (curr_peer->rx_pkt >=
5579 curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n)) {
5580 /* this tdls link got back to normal, so keep it */
5581 hdd_info("tdls link to " MAC_ADDRESS_STR
5582 " back to normal, will stay",
5583 MAC_ADDR_ARRAY(curr_peer->peerMac));
5584 } else {
5585 /* this tdls link needs to get torn down */
5586 hdd_info("trigger tdls link to "MAC_ADDRESS_STR
5587 " down", MAC_ADDR_ARRAY(curr_peer->peerMac));
5588 wlan_hdd_tdls_indicate_teardown(curr_peer->pHddTdlsCtx->pAdapter,
5589 curr_peer,
5590 eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON);
5591 }
5592error_idle_return:
5593 return;
5594}
5595
5596/**
5597 * tdls_ct_process_idle_and_discovery() - process the traffic data
5598 * @curr_peer: tdls peer needs to be examined
5599 * @hdd_ctx: hdd context
5600 * @hdd_tdls_ctx: tdls context
5601 *
5602 * Function to check the peer traffic data in idle link and tdls
5603 * discovering link
5604 *
5605 * Return: None
5606 */
5607static void tdls_ct_process_idle_and_discovery(hddTdlsPeer_t *curr_peer,
5608 tdlsCtx_t *hdd_tdls_ctx)
5609{
5610 uint16_t valid_peers;
5611
5612 valid_peers = wlan_hdd_tdls_connected_peers(hdd_tdls_ctx->pAdapter);
5613
5614 if ((curr_peer->tx_pkt + curr_peer->rx_pkt) >=
5615 hdd_tdls_ctx->threshold_config.tx_packet_n) {
5616 if (HDD_MAX_NUM_TDLS_STA > valid_peers) {
5617 hdd_info("Tput trigger TDLS pre-setup");
5618 hdd_tdls_ctx->curr_candidate = curr_peer;
5619 wlan_hdd_tdls_implicit_send_discovery_request(
5620 hdd_tdls_ctx);
5621 } else {
5622 hdd_info("Maximum peers connected already! %d",
5623 valid_peers);
5624 }
5625 }
5626}
5627
5628
5629/**
5630 * tdls_ct_process_connected_link() - process the traffic
5631 * @curr_peer: tdls peer needs to be examined
5632 * @hdd_ctx: hdd context
5633 * @hdd_tdls_ctx: tdls context
5634 *
5635 * Function to check the peer traffic data in active STA
5636 * session
5637 *
5638 * Return: None
5639 */
5640static void tdls_ct_process_connected_link(hddTdlsPeer_t *curr_peer,
5641 hdd_context_t *hdd_ctx,
5642 tdlsCtx_t *hdd_tdls_ctx)
5643{
5644 if ((int32_t)curr_peer->rssi <
5645 (int32_t)hdd_tdls_ctx->threshold_config.rssi_teardown_threshold) {
5646 hdd_warn("Tear down - low RSSI: " MAC_ADDRESS_STR "!",
5647 MAC_ADDR_ARRAY(curr_peer->peerMac));
5648 /* unlock the mutex here, it may used in caller function */
5649 mutex_unlock(&hdd_ctx->tdls_lock);
5650 wlan_hdd_tdls_indicate_teardown(hdd_tdls_ctx->pAdapter,
5651 curr_peer,
5652 eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON);
5653 mutex_lock(&hdd_ctx->tdls_lock);
5654 return;
5655 }
5656
5657 /* Only teardown based on non zero idle packet threshold, to address
5658 * a use case where this threshold does not get consider for TEAR DOWN
5659 */
5660 if ((0 != hdd_tdls_ctx->threshold_config.idle_packet_n) &&
5661 ((curr_peer->tx_pkt <
5662 hdd_tdls_ctx->threshold_config.idle_packet_n) &&
5663 (curr_peer->rx_pkt <
5664 hdd_tdls_ctx->threshold_config.idle_packet_n))) {
5665 if (!curr_peer->is_peer_idle_timer_initialised) {
5666 uint8_t staId = (uint8_t)curr_peer->staId;
5667 tdlsConnInfo_t *tdls_info;
5668 tdls_info = wlan_hdd_get_conn_info(hdd_ctx, staId);
5669 qdf_mc_timer_init(&curr_peer->peer_idle_timer,
5670 QDF_TIMER_TYPE_SW,
5671 wlan_hdd_tdls_idle_handler,
5672 tdls_info);
5673 curr_peer->is_peer_idle_timer_initialised = true;
5674 }
5675 if (QDF_TIMER_STATE_RUNNING !=
5676 curr_peer->peer_idle_timer.state) {
5677 hdd_warn("Tx/Rx Idle timer start: " MAC_ADDRESS_STR "!",
5678 MAC_ADDR_ARRAY(curr_peer->peerMac));
5679 wlan_hdd_tdls_timer_restart(hdd_tdls_ctx->pAdapter,
5680 &curr_peer->peer_idle_timer,
5681 hdd_tdls_ctx->threshold_config.idle_timeout_t);
5682 }
5683 } else if (QDF_TIMER_STATE_RUNNING ==
5684 curr_peer->peer_idle_timer.state) {
5685 hdd_warn("Tx/Rx Idle timer stop: " MAC_ADDRESS_STR "!",
5686 MAC_ADDR_ARRAY(curr_peer->peerMac));
5687 qdf_mc_timer_stop(&curr_peer->peer_idle_timer);
5688 }
5689}
5690
5691/**
5692 * wlan_hdd_tdls_ct_process_cap_supported() - process TDLS supported peer.
5693 * @curr_peer: tdls peer needs to be examined
5694 * @hdd_ctx: hdd context
5695 * @hdd_tdls_ctx: tdls context
5696 *
5697 * Function to check the peer traffic data for tdls supported peer
5698 *
5699 * Return: None
5700 */
5701static void wlan_hdd_tdls_ct_process_cap_supported(hddTdlsPeer_t *curr_peer,
5702 hdd_context_t *hdd_ctx,
5703 tdlsCtx_t *hdd_tdls_ctx)
5704{
5705 hdd_info("tx %d, rx %d (thr.pkt %d/idle %d), rssi %d (thr.trig %d/tear %d)",
5706 curr_peer->tx_pkt, curr_peer->rx_pkt,
5707 hdd_tdls_ctx->threshold_config.tx_packet_n,
5708 hdd_tdls_ctx->threshold_config.idle_packet_n,
5709 curr_peer->rssi,
5710 hdd_tdls_ctx->threshold_config.rssi_trigger_threshold,
5711 hdd_tdls_ctx->threshold_config.rssi_teardown_threshold);
5712
5713 switch (curr_peer->link_status) {
5714 case eTDLS_LINK_IDLE:
5715 case eTDLS_LINK_DISCOVERING:
5716 if (hdd_ctx->config->fTDLSExternalControl &&
5717 (!curr_peer->isForcedPeer))
5718 break;
5719 tdls_ct_process_idle_and_discovery(curr_peer, hdd_tdls_ctx);
5720 break;
5721 case eTDLS_LINK_CONNECTED:
5722 tdls_ct_process_connected_link(curr_peer, hdd_ctx,
5723 hdd_tdls_ctx);
5724 break;
5725 default:
5726 break;
5727 }
5728}
5729
5730/**
5731 * wlan_hdd_tdls_ct_process_cap_unknown() - process unknown peer
5732 * @curr_peer: tdls peer needs to be examined
5733 * @hdd_ctx: hdd context
5734 * @hdd_tdls_ctx: tdls context
5735 *
5736 * Function check the peer traffic data , when tdls capability is unknown
5737 *
5738 * Return: None
5739 */
5740static void wlan_hdd_tdls_ct_process_cap_unknown(hddTdlsPeer_t *curr_peer,
5741 hdd_context_t *hdd_ctx,
5742 tdlsCtx_t *hdd_tdls_ctx)
5743{
5744 if (hdd_ctx->config->fTDLSExternalControl &&
5745 (!curr_peer->isForcedPeer)) {
5746 return;
5747 }
5748
5749 hdd_info("threshold_config.tx_packet_n = %d curr_peer->tx_pkt = %d curr_peer->rx_pkt = %d ",
5750 hdd_tdls_ctx->threshold_config.tx_packet_n, curr_peer->tx_pkt,
5751 curr_peer->rx_pkt);
5752
5753 if (!TDLS_IS_CONNECTED(curr_peer) &&
5754 ((curr_peer->tx_pkt + curr_peer->rx_pkt) >=
5755 hdd_tdls_ctx->threshold_config.tx_packet_n)) {
5756 /* Ignore discovery attempt if External Control is enabled, that
5757 * is, peer is forced. In that case, continue discovery attempt
5758 * regardless attempt count
5759 */
5760 hdd_info("TDLS UNKNOWN pre discover ");
5761 if (curr_peer->isForcedPeer || curr_peer->discovery_attempt++ <
5762 hdd_tdls_ctx->threshold_config.discovery_tries_n) {
5763 hdd_info("TDLS UNKNOWN discover ");
5764 hdd_tdls_ctx->curr_candidate = curr_peer;
5765 wlan_hdd_tdls_implicit_send_discovery_request(hdd_tdls_ctx);
5766 } else {
5767 curr_peer->tdls_support = eTDLS_CAP_NOT_SUPPORTED;
5768 wlan_hdd_tdls_set_peer_link_status(
5769 curr_peer,
5770 eTDLS_LINK_IDLE,
5771 eTDLS_LINK_NOT_SUPPORTED,
5772 false);
5773 }
5774 }
5775}
5776
5777
5778/**
5779 * wlan_hdd_tdls_ct_process_peers() - process the peer
5780 * @curr_peer: tdls peer needs to be examined
5781 * @hdd_ctx: hdd context
5782 * @hdd_tdls_ctx: tdls context
5783 *
5784 * This function check the peer capability and process the metadata from
5785 * the peer
5786 *
5787 * Return: None
5788 */
5789static void wlan_hdd_tdls_ct_process_peers(hddTdlsPeer_t *curr_peer,
5790 hdd_context_t *hdd_ctx,
5791 tdlsCtx_t *hdd_tdls_ctx)
5792{
5793 hdd_info(MAC_ADDRESS_STR " link_status %d tdls_support %d",
5794 MAC_ADDR_ARRAY(curr_peer->peerMac),
5795 curr_peer->link_status, curr_peer->tdls_support);
5796
5797 switch (curr_peer->tdls_support) {
5798 case eTDLS_CAP_SUPPORTED:
5799 wlan_hdd_tdls_ct_process_cap_supported(curr_peer, hdd_ctx,
5800 hdd_tdls_ctx);
5801 break;
5802
5803 case eTDLS_CAP_UNKNOWN:
5804 wlan_hdd_tdls_ct_process_cap_unknown(curr_peer, hdd_ctx,
5805 hdd_tdls_ctx);
5806 break;
5807 default:
5808 break;
5809 }
5810
5811}
5812
5813/**
5814 * wlan_hdd_tdls_ct_handler() - TDLS connection tracker handler
5815 * @user_data: user data from timer
5816 *
5817 * tdls connection tracker timer starts, when the STA connected to AP
5818 * and it's scan the traffic between two STA peers and make TDLS
5819 * connection and teardown, based on the traffic threshold
5820 *
5821 * Return: None
5822 */
5823static void wlan_hdd_tdls_ct_handler(void *user_data)
5824{
5825 int i;
5826 hdd_adapter_t *adapter;
5827 struct list_head *head;
5828 struct list_head *pos;
5829 hddTdlsPeer_t *curr_peer;
5830 tdlsCtx_t *hdd_tdls_ctx;
5831 hdd_context_t *hdd_ctx;
5832
5833 adapter = (hdd_adapter_t *)user_data;
5834
5835 if (NULL == adapter) {
5836 hdd_err("Invalid adapter context");
5837 return;
5838 }
5839
5840 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5841
5842 if (0 != (wlan_hdd_validate_context(hdd_ctx)))
5843 return;
5844
5845 hdd_tdls_ctx = adapter->sessionCtx.station.pHddTdlsCtx;
5846
5847 if (NULL == hdd_tdls_ctx) {
5848 hdd_err("Invalid hdd_tdls_ctx context");
5849 return;
5850 }
5851
5852 /* If any concurrency is detected */
5853 if (!hdd_ctx->enable_tdls_connection_tracker)
5854 goto restart_return;
5855
5856 mutex_lock(&hdd_ctx->tdls_lock);
5857
5858 /* Update tx rx traffic sample in tdls data structures */
5859 wlan_hdd_tdls_ct_sampling_tx_rx(adapter, hdd_ctx,
5860 hdd_tdls_ctx);
5861
5862 for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
5863 head = &hdd_tdls_ctx->peer_list[i];
5864 list_for_each(pos, head) {
5865 curr_peer = list_entry(pos, hddTdlsPeer_t, node);
5866 wlan_hdd_tdls_ct_process_peers(curr_peer, hdd_ctx,
5867 hdd_tdls_ctx);
5868 curr_peer->tx_pkt = 0;
5869 curr_peer->rx_pkt = 0;
5870 }
5871 }
5872
5873 mutex_unlock(&hdd_ctx->tdls_lock);
5874
5875restart_return:
5876 wlan_hdd_tdls_timer_restart(hdd_tdls_ctx->pAdapter,
5877 &hdd_tdls_ctx->peer_update_timer,
5878 hdd_tdls_ctx->threshold_config.tx_period_t);
5879}
5880
5881/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005882 * hdd_set_tdls_scan_type - set scan during active tdls session
5883 * @hdd_ctx: ptr to hdd context.
5884 * @val: scan type value: 0 or 1.
5885 *
5886 * Set scan type during tdls session. If set to 1, that means driver
5887 * shall maintain tdls link and allow scan regardless if tdls peer is
5888 * buffer sta capable or not and/or if device is sleep sta capable or
5889 * not. If tdls peer is not buffer sta capable then during scan there
5890 * will be loss of Rx packets and Tx would stop when device moves away
5891 * from tdls channel. If set to 0, then driver shall teardown tdls link
5892 * before initiating scan if peer is not buffer sta capable and device
5893 * is not sleep sta capable. By default, scan type is set to 0.
5894 *
5895 * Return: success (0) or failure (errno value)
5896 */
5897int hdd_set_tdls_scan_type(hdd_context_t *hdd_ctx, int val)
5898{
5899 if ((val != 0) && (val != 1)) {
Kabilan Kannan38ff9f32016-08-25 14:51:14 -07005900 hdd_err("Incorrect value of tdls scan type: %d", val);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005901 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005902 }
Jeff Johnson68755312017-02-10 11:46:55 -08005903
5904 hdd_ctx->config->enable_tdls_scan = val;
5905
5906 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005907}
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07005908
5909/**
5910 * wlan_hdd_tdls_teardown_links() - teardown tdls links
5911 * @hddCtx : pointer to hdd context
5912 *
5913 * Return: 0 if success else non zero
5914 */
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005915static int wlan_hdd_tdls_teardown_links(hdd_context_t *hddctx,
5916 uint32_t mode)
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07005917{
5918 uint16_t connected_tdls_peers = 0;
5919 uint8_t staidx;
5920 hddTdlsPeer_t *curr_peer;
5921 hdd_adapter_t *adapter;
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005922 int ret = 0;
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07005923
5924 if (eTDLS_SUPPORT_NOT_ENABLED == hddctx->tdls_mode) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005925 hdd_info("TDLS mode is disabled OR not enabled in FW");
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07005926 return 0;
5927 }
5928
5929 adapter = hdd_get_adapter(hddctx, QDF_STA_MODE);
5930
5931 if (adapter == NULL) {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005932 hdd_info("Station Adapter Not Found");
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07005933 return 0;
5934 }
5935
5936 connected_tdls_peers = wlan_hdd_tdls_connected_peers(adapter);
5937
5938 if (!connected_tdls_peers)
5939 return 0;
5940
5941 for (staidx = 0; staidx < hddctx->max_num_tdls_sta;
5942 staidx++) {
5943 if (!hddctx->tdlsConnInfo[staidx].staId)
5944 continue;
5945
5946 curr_peer = wlan_hdd_tdls_find_all_peer(hddctx,
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005947 hddctx->tdlsConnInfo[staidx].peerMac.bytes);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07005948
5949 if (!curr_peer)
5950 continue;
5951
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005952 /* Check if connected peer supports more than one stream */
5953 if (curr_peer->spatial_streams == TDLS_NSS_1x1_MODE)
5954 continue;
5955
5956 hdd_info("Indicate TDLS teardown (staId %d)",
5957 curr_peer->staId);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07005958
5959 wlan_hdd_tdls_indicate_teardown(
5960 curr_peer->pHddTdlsCtx->pAdapter,
5961 curr_peer,
5962 eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON);
5963 mutex_lock(&hddctx->tdls_lock);
5964 hddctx->tdls_teardown_peers_cnt++;
5965 mutex_unlock(&hddctx->tdls_lock);
5966 }
5967 mutex_lock(&hddctx->tdls_lock);
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005968 if (hddctx->tdls_teardown_peers_cnt >= 1) {
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07005969 hddctx->tdls_nss_switch_in_progress = true;
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005970 hdd_info("TDLS peers to be torn down = %d",
5971 hddctx->tdls_teardown_peers_cnt);
5972 /* Antenna switch 2x2 to 1x1 */
Kabilan Kannanff89f742016-08-15 18:14:10 -07005973 if (mode == HDD_ANTENNA_MODE_1X1) {
5974 hddctx->tdls_nss_transition_mode =
5975 TDLS_NSS_TRANSITION_2x2_to_1x1;
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005976 ret = -EAGAIN;
Kabilan Kannanff89f742016-08-15 18:14:10 -07005977 } else {
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005978 /* Antenna switch 1x1 to 2x2 */
Kabilan Kannanff89f742016-08-15 18:14:10 -07005979 hddctx->tdls_nss_transition_mode =
5980 TDLS_NSS_TRANSITION_1x1_to_2x2;
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005981 ret = 0;
Kabilan Kannanff89f742016-08-15 18:14:10 -07005982 }
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005983 hdd_info("TDLS teardown for antenna switch operation starts");
5984 }
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07005985 mutex_unlock(&hddctx->tdls_lock);
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005986 return ret;
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07005987}
5988
5989/**
5990 * wlan_hdd_tdls_antenna_switch() - Dynamic TDLS antenna switch 1x1 <-> 2x2
5991 * antenna mode in standalone station
5992 * @hdd_ctx: Pointer to hdd contex
5993 * @adapter: Pointer to hdd adapter
5994 *
5995 * Return: 0 if success else non zero
5996 */
5997int wlan_hdd_tdls_antenna_switch(hdd_context_t *hdd_ctx,
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07005998 hdd_adapter_t *adapter, uint32_t mode)
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07005999{
6000 uint8_t tdls_peer_cnt;
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006001 uint32_t vdev_nss;
Kabilan Kannan32eb5022016-10-04 12:24:50 -07006002 hdd_station_ctx_t *sta_ctx;
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006003
Kabilan Kannan32eb5022016-10-04 12:24:50 -07006004 if (hdd_ctx->connected_peer_count == 0)
6005 return 0;
6006
6007 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006008 /* Check whether TDLS antenna switch is in progress */
6009 if (hdd_ctx->tdls_nss_switch_in_progress) {
Kabilan Kannanff89f742016-08-15 18:14:10 -07006010 if (hdd_ctx->tdls_nss_teardown_complete == false) {
6011 hdd_err("TDLS antenna switch is in progress");
6012 return -EAGAIN;
Kabilan Kannanff89f742016-08-15 18:14:10 -07006013 }
Jeff Johnson68755312017-02-10 11:46:55 -08006014 goto tdls_ant_sw_done;
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006015 }
6016
6017 /* Check whether TDLS is connected or not */
6018 mutex_lock(&hdd_ctx->tdls_lock);
6019 tdls_peer_cnt = hdd_ctx->connected_peer_count;
6020 mutex_unlock(&hdd_ctx->tdls_lock);
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006021 if (tdls_peer_cnt <= 0) {
6022 hdd_info("No TDLS connection established");
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006023 goto tdls_ant_sw_done;
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006024 }
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006025
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006026 /* Check the supported nss for TDLS */
6027 if (IS_5G_CH(sta_ctx->conn_info.operationChannel))
6028 vdev_nss = CFG_TDLS_NSS(
6029 hdd_ctx->config->vdev_type_nss_5g);
6030 else
6031 vdev_nss = CFG_TDLS_NSS(
6032 hdd_ctx->config->vdev_type_nss_2g);
6033
6034 if (vdev_nss == HDD_ANTENNA_MODE_1X1) {
6035 hdd_info("Supported NSS is 1X1, no need to teardown TDLS links");
6036 goto tdls_ant_sw_done;
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006037 }
6038
6039 /* teardown all the tdls connections */
Archana Ramachandran2ad7de22016-04-22 16:53:25 -07006040 return wlan_hdd_tdls_teardown_links(hdd_ctx, mode);
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006041
6042tdls_ant_sw_done:
Archana Ramachandrand5d2e922016-04-20 16:57:35 -07006043 return 0;
6044}
Nitesh Shah61c10d92016-10-19 19:29:15 +05306045
6046/**
6047 * wlan_hdd_change_tdls_mode - Change TDLS mode
6048 * @data: void pointer
6049 *
6050 * Return: None
6051 */
6052void wlan_hdd_change_tdls_mode(void *data)
6053{
6054 hdd_context_t *hdd_ctx = (hdd_context_t *)data;
6055
Kabilan Kannan8657a7e2017-01-25 01:16:05 -08006056 wlan_hdd_tdls_set_mode(hdd_ctx, hdd_ctx->tdls_mode_last, false,
6057 HDD_SET_TDLS_MODE_SOURCE_P2P);
Nitesh Shah61c10d92016-10-19 19:29:15 +05306058}
6059
Kabilan Kannan6ca98482017-02-14 13:26:15 -08006060void hdd_tdls_notify_p2p_roc(hdd_context_t *hdd_ctx,
6061 enum tdls_concerned_external_events event)
Nitesh Shah61c10d92016-10-19 19:29:15 +05306062{
Kabilan Kannan6ca98482017-02-14 13:26:15 -08006063 eTDLSSupportMode tdls_mode;
Nitesh Shah61c10d92016-10-19 19:29:15 +05306064
Kabilan Kannan6ca98482017-02-14 13:26:15 -08006065 qdf_mc_timer_stop(&hdd_ctx->tdls_source_timer);
6066
6067 if (event == P2P_ROC_START) {
6068 tdls_mode = eTDLS_SUPPORT_DISABLED;
6069 wlan_hdd_tdls_set_mode(hdd_ctx, tdls_mode, false,
Kabilan Kannan8657a7e2017-01-25 01:16:05 -08006070 HDD_SET_TDLS_MODE_SOURCE_P2P);
Kabilan Kannan6ca98482017-02-14 13:26:15 -08006071 wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_ctx);
Nitesh Shah57752482017-01-03 19:46:15 +05306072 }
Nitesh Shah61c10d92016-10-19 19:29:15 +05306073
Kabilan Kannan6ca98482017-02-14 13:26:15 -08006074 qdf_mc_timer_start(&hdd_ctx->tdls_source_timer,
6075 hdd_ctx->config->tdls_enable_defer_time);
Nitesh Shah61c10d92016-10-19 19:29:15 +05306076
6077 return;
6078}
6079