blob: 43805548365b8286a89c035f5de4c2ba17fae7d1 [file] [log] [blame]
Kiran V1ccee932012-12-12 14:49:46 -08001/*
Gopichand Nakkala0c1331e2013-01-07 22:49:07 -08002 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
3 *
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 */
Kiran V1ccee932012-12-12 14:49:46 -080021
22/**========================================================================
23
24 \file wlan_hdd_tdls.c
25
Chilam NG571c65a2013-01-19 12:27:36 +053026 \brief WLAN Host Device Driver implementation for TDLS
Kiran V1ccee932012-12-12 14:49:46 -080027
Kiran V1ccee932012-12-12 14:49:46 -080028 ========================================================================*/
29
30#include <wlan_hdd_includes.h>
31#include <wlan_hdd_hostapd.h>
32#include <net/cfg80211.h>
33#include <linux/netdevice.h>
34#include <linux/skbuff.h>
Chilam NG571c65a2013-01-19 12:27:36 +053035#include <linux/list.h>
Kiran V1ccee932012-12-12 14:49:46 -080036#include <linux/etherdevice.h>
37#include <net/ieee80211_radiotap.h>
38#include "wlan_hdd_tdls.h"
Chilam NG571c65a2013-01-19 12:27:36 +053039#include "wlan_hdd_cfg80211.h"
Kiran V1ccee932012-12-12 14:49:46 -080040
Chilam NG571c65a2013-01-19 12:27:36 +053041
Chilam Nga75d8b62013-01-29 01:35:59 -080042static tdlsCtx_t *pHddTdlsCtx;
43static v_BOOL_t tdlsImplicitTrigger;
Chilam NG571c65a2013-01-19 12:27:36 +053044
Hoonki Lee5a4b2172013-01-29 01:45:53 -080045#ifndef WLAN_FEATURE_TDLS_DEBUG
46#define TDLS_LOG_LEVEL VOS_TRACE_LEVEL_INFO
47#else
48#define TDLS_LOG_LEVEL VOS_TRACE_LEVEL_WARN
49#endif
50
Hoonki Lee387663d2013-02-05 18:08:43 -080051static u8 wlan_hdd_tdls_hash_key (u8 *mac)
Hoonki Leef63df0d2013-01-16 19:29:14 -080052{
53 int i;
Hoonki Lee387663d2013-02-05 18:08:43 -080054 u8 key = 0;
55
56 for (i = 0; i < 6; i++)
57 key ^= mac[i];
58
59 return key;
60}
61
62static v_VOID_t wlan_hdd_tdls_discover_peer_cb( v_PVOID_t userData )
63{
64 int i;
65 struct list_head *head;
66 struct list_head *pos;
Chilam NG571c65a2013-01-19 12:27:36 +053067 hddTdlsPeer_t *curr_peer;
Hoonki Leebfee0342013-01-21 16:43:45 -080068 hdd_adapter_t *pAdapter;
69 hdd_context_t *pHddCtx;
70
71 if (NULL == pHddTdlsCtx) return;
72
73 pAdapter = WLAN_HDD_GET_PRIV_PTR(pHddTdlsCtx->dev);
74 pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
Hoonki Leef63df0d2013-01-16 19:29:14 -080075
Hoonki Lee387663d2013-02-05 18:08:43 -080076 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: ", __func__);
77
Gopichand Nakkala91b09262013-02-10 14:27:02 -080078 if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
79 {
80 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
81 "%s: unable to lock list", __func__);
82 return;
83 }
84
Chilam NG571c65a2013-01-19 12:27:36 +053085 for (i = 0; i < 256; i++) {
Hoonki Lee387663d2013-02-05 18:08:43 -080086 head = &pHddTdlsCtx->peer_list[i];
Chilam NG571c65a2013-01-19 12:27:36 +053087
Hoonki Lee387663d2013-02-05 18:08:43 -080088 list_for_each (pos, head) {
89 curr_peer = list_entry (pos, hddTdlsPeer_t, node);
Chilam NG571c65a2013-01-19 12:27:36 +053090
Gopichand Nakkala2a0a1572013-02-10 21:39:16 -080091 VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
92 "%d %02x:%02x:%02x:%02x:%02x:%02x %d %d %d %d", i,
Hoonki Lee387663d2013-02-05 18:08:43 -080093 curr_peer->peerMac[0],
94 curr_peer->peerMac[1],
95 curr_peer->peerMac[2],
96 curr_peer->peerMac[3],
97 curr_peer->peerMac[4],
Gopichand Nakkala2a0a1572013-02-10 21:39:16 -080098 curr_peer->peerMac[5],
99 curr_peer->tdls_support,
100 curr_peer->link_status,
101 curr_peer->discovery_attempt,
102 pHddTdlsCtx->threshold_config.discovery_tries_n);
Hoonki Lee387663d2013-02-05 18:08:43 -0800103
Chilam NG571c65a2013-01-19 12:27:36 +0530104 if ((eTDLS_CAP_UNKNOWN == curr_peer->tdls_support) &&
105 (eTDLS_LINK_NOT_CONNECTED == curr_peer->link_status) &&
106 (curr_peer->discovery_attempt <
107 pHddTdlsCtx->threshold_config.discovery_tries_n)) {
Hoonki Lee387663d2013-02-05 18:08:43 -0800108 /*
109 * We expected cfg80211_tdls_oper_request will have NL80211_TDLS_DISVOERY_REQ, but
110 * actually supplicant doesn't support NL80211_TDLS_DISCOVERY_REQ with tdls_oper_request yet.
111 * In the mean-time, we directly call hdd callback for discovery request here
112 * If supplicant have this support, use below code.
113 * cfg80211_tdls_oper_request(pHddTdlsCtx->dev, curr_peer->peerMac,
114 * NL80211_TDLS_DISCOVERY_REQ, FALSE, GFP_KERNEL);
115 */
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800116 sme_SendTdlsMgmtFrame(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId,
117 curr_peer->peerMac, WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, NULL, 0, 0);
Chilam NG571c65a2013-01-19 12:27:36 +0530118
119// if (++curr_peer->discovery_attempt >= pHddTdlsCtx->threshold_config.discovery_tries_n) {
120// curr_peer->tdls_support = eTDLS_CAP_NOT_SUPPORTED;
121// }
122 }
Hoonki Lee387663d2013-02-05 18:08:43 -0800123 }
Hoonki Leef63df0d2013-01-16 19:29:14 -0800124 }
125
Chilam NG571c65a2013-01-19 12:27:36 +0530126 vos_timer_start( &pHddTdlsCtx->peerDiscoverTimer,
127 pHddTdlsCtx->threshold_config.discovery_period_t );
128
129 wlan_hdd_get_rssi(pAdapter, &pHddTdlsCtx->ap_rssi);
130
131 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "beacon rssi: %d",
132 pHddTdlsCtx->ap_rssi);
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800133
134 mutex_unlock(&pHddTdlsCtx->lock);
Hoonki Leef63df0d2013-01-16 19:29:14 -0800135}
Chilam NG571c65a2013-01-19 12:27:36 +0530136
Hoonki Lee387663d2013-02-05 18:08:43 -0800137static v_VOID_t wlan_hdd_tdls_update_peer_cb( v_PVOID_t userData )
Chilam NG571c65a2013-01-19 12:27:36 +0530138{
139 int i;
Hoonki Lee387663d2013-02-05 18:08:43 -0800140 struct list_head *head;
141 struct list_head *pos;
Chilam NG571c65a2013-01-19 12:27:36 +0530142 hddTdlsPeer_t *curr_peer;
143
Hoonki Leebfee0342013-01-21 16:43:45 -0800144 if (NULL == pHddTdlsCtx) return;
145
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800146 if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
147 {
148 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
149 "%s: unable to lock list", __func__);
150 return;
151 }
152
Chilam NG571c65a2013-01-19 12:27:36 +0530153 for (i = 0; i < 256; i++) {
Hoonki Lee387663d2013-02-05 18:08:43 -0800154 head = &pHddTdlsCtx->peer_list[i];
Chilam NG571c65a2013-01-19 12:27:36 +0530155
Hoonki Lee387663d2013-02-05 18:08:43 -0800156 list_for_each (pos, head) {
157 curr_peer = list_entry (pos, hddTdlsPeer_t, node);
Chilam NG571c65a2013-01-19 12:27:36 +0530158
Hoonki Lee387663d2013-02-05 18:08:43 -0800159 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
160 "hdd update cb - %d: %x %x %x %x %x %x -> %d\n", i,
161 curr_peer->peerMac[0],
162 curr_peer->peerMac[1],
163 curr_peer->peerMac[2],
164 curr_peer->peerMac[3],
165 curr_peer->peerMac[4],
166 curr_peer->peerMac[5],
167 curr_peer->tx_pkt);
168
Chilam NG571c65a2013-01-19 12:27:36 +0530169 if (eTDLS_CAP_SUPPORTED == curr_peer->tdls_support) {
Hoonki Lee5a4b2172013-01-29 01:45:53 -0800170 VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
171 "%s: (tx %d, rx %d, config %d) %02x:%02x:%02x:%02x:%02x:%02x (%d) ",
172 __func__, curr_peer->tx_pkt, curr_peer->rx_pkt,
173 pHddTdlsCtx->threshold_config.tx_packet_n,
174 curr_peer->peerMac[0], curr_peer->peerMac[1], curr_peer->peerMac[2],
175 curr_peer->peerMac[3], curr_peer->peerMac[4], curr_peer->peerMac[5],
176 curr_peer->link_status);
Chilam NG571c65a2013-01-19 12:27:36 +0530177 if (eTDLS_LINK_CONNECTED != curr_peer->link_status) {
178 if (curr_peer->tx_pkt >=
179 pHddTdlsCtx->threshold_config.tx_packet_n) {
Hoonki Lee5a4b2172013-01-29 01:45:53 -0800180
181 VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL, "-> Tput trigger TDLS SETUP");
Chilam NG571c65a2013-01-19 12:27:36 +0530182#ifdef CONFIG_TDLS_IMPLICIT
183 cfg80211_tdls_oper_request(pHddTdlsCtx->dev,
184 curr_peer->peerMac,
185 NL80211_TDLS_SETUP, FALSE,
186 GFP_KERNEL);
187#endif
Hoonki Leecdd8e962013-01-20 00:45:46 -0800188 goto next_peer;
Chilam NG571c65a2013-01-19 12:27:36 +0530189 }
Hoonki Lee5a4b2172013-01-29 01:45:53 -0800190#ifdef WLAN_FEATURE_TDLS_DEBUG
191 else {
192 VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL, "-> ignored.");
193 }
194#endif
Hoonki Leecdd8e962013-01-20 00:45:46 -0800195 if ((tANI_S32)curr_peer->rssi >
196 (tANI_S32)(pHddTdlsCtx->threshold_config.rssi_hysteresis +
Chilam NG571c65a2013-01-19 12:27:36 +0530197 pHddTdlsCtx->ap_rssi)) {
198
Hoonki Lee5a4b2172013-01-29 01:45:53 -0800199 VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
200 "%s: RSSI (peer %d > ap %d + hysteresis %d) triggering to %02x:%02x:%02x:%02x:%02x:%02x ",
201 __func__, (tANI_S32)curr_peer->rssi,
202 pHddTdlsCtx->ap_rssi,
203 (tANI_S32)(pHddTdlsCtx->threshold_config.rssi_hysteresis),
204 curr_peer->peerMac[0], curr_peer->peerMac[1], curr_peer->peerMac[2],
205 curr_peer->peerMac[3], curr_peer->peerMac[4], curr_peer->peerMac[5]);
Chilam NG571c65a2013-01-19 12:27:36 +0530206
207#ifdef CONFIG_TDLS_IMPLICIT
208 cfg80211_tdls_oper_request(pHddTdlsCtx->dev,
209 curr_peer->peerMac,
210 NL80211_TDLS_SETUP, FALSE,
211 GFP_KERNEL);
212#endif
213 }
214 } else {
Chilam Ng47d06d62013-02-04 20:25:05 -0800215 /* if we are receiving pakcets (rx_pkt > 0), don't start
216 * the idle timer regardless of tx
217 */
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800218 if ((curr_peer->rx_pkt == 0) &&
Chilam Ng47d06d62013-02-04 20:25:05 -0800219 (curr_peer->tx_pkt <
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800220 pHddTdlsCtx->threshold_config.tx_packet_n)) {
Chilam Ng1279e232013-01-25 15:06:52 -0800221 if (VOS_TIMER_STATE_RUNNING !=
222 vos_timer_getCurrentState(&curr_peer->peerIdleTimer)) {
Hoonki Lee5a4b2172013-01-29 01:45:53 -0800223 VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL, "-> start Idle Timer (%d)", pHddTdlsCtx->threshold_config.rx_timeout_t);
Chilam Ng1279e232013-01-25 15:06:52 -0800224 vos_timer_start( &curr_peer->peerIdleTimer,
225 pHddTdlsCtx->threshold_config.rx_timeout_t );
226 }
Hoonki Lee5a4b2172013-01-29 01:45:53 -0800227
Hoonki Leecdd8e962013-01-20 00:45:46 -0800228 goto next_peer;
Chilam NG571c65a2013-01-19 12:27:36 +0530229 }
Hoonki Lee5a4b2172013-01-29 01:45:53 -0800230 else {
231 if (VOS_TIMER_STATE_RUNNING ==
232 vos_timer_getCurrentState(&curr_peer->peerIdleTimer)) {
233 VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL, "-> stop Idle Timer ");
234 vos_timer_stop ( &curr_peer->peerIdleTimer );
235 }
236#ifdef WLAN_FEATURE_TDLS_DEBUG
237 else
238 VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL, "-> idle time was not running. ignored.");
239#endif
240 }
Hoonki Leecdd8e962013-01-20 00:45:46 -0800241// if (curr_peer->rssi <
242// (pHddTdlsCtx->threshold_config.rssi_hysteresis +
243// pHddTdlsCtx->ap_rssi)) {
244//
245//#ifdef CONFIG_TDLS_IMPLICIT
246// cfg80211_tdls_oper_request(pHddTdlsCtx->dev,
247// curr_peer->peerMac,
248// NL80211_TDLS_TEARDOWN, FALSE,
249// GFP_KERNEL);
250//#endif
251// }
Chilam NG571c65a2013-01-19 12:27:36 +0530252 }
253 }
254
Hoonki Leecdd8e962013-01-20 00:45:46 -0800255next_peer:
Chilam NG571c65a2013-01-19 12:27:36 +0530256 curr_peer->tx_pkt = 0;
Chilam Ng1279e232013-01-25 15:06:52 -0800257 curr_peer->rx_pkt = 0;
Hoonki Lee387663d2013-02-05 18:08:43 -0800258 }
Chilam NG571c65a2013-01-19 12:27:36 +0530259 }
260
261 vos_timer_start( &pHddTdlsCtx->peerUpdateTimer,
262 pHddTdlsCtx->threshold_config.tx_period_t );
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800263 mutex_unlock(&pHddTdlsCtx->lock);
Chilam NG571c65a2013-01-19 12:27:36 +0530264}
265
Chilam Ng1279e232013-01-25 15:06:52 -0800266static v_VOID_t wlan_hdd_tdls_idle_cb( v_PVOID_t userData )
267{
Lee Hoonkic1262f22013-01-24 21:59:00 -0800268#ifdef CONFIG_TDLS_IMPLICIT
Chilam Ng1279e232013-01-25 15:06:52 -0800269 hddTdlsPeer_t *curr_peer = (hddTdlsPeer_t *)userData;
270
Chilam Ng1279e232013-01-25 15:06:52 -0800271
Hoonki Lee5a4b2172013-01-29 01:45:53 -0800272 VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
273 "%s: Tx/Rx Idle %02x:%02x:%02x:%02x:%02x:%02x trigger teardown",
274 __func__,
275 curr_peer->peerMac[0], curr_peer->peerMac[1], curr_peer->peerMac[2],
276 curr_peer->peerMac[3], curr_peer->peerMac[4], curr_peer->peerMac[5]);
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800277 if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
278 {
279 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
280 "%s: unable to lock list", __func__);
281 return;
282 }
Hoonki Lee5a4b2172013-01-29 01:45:53 -0800283
Chilam Ng1279e232013-01-25 15:06:52 -0800284 cfg80211_tdls_oper_request(pHddTdlsCtx->dev,
285 curr_peer->peerMac,
Hoonki Leea34dd892013-02-05 22:56:02 -0800286 NL80211_TDLS_TEARDOWN,
287 eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON,
Chilam Ng1279e232013-01-25 15:06:52 -0800288 GFP_KERNEL);
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800289 mutex_unlock(&pHddTdlsCtx->lock);
Chilam Ng1279e232013-01-25 15:06:52 -0800290#endif
291}
292
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800293static void wlan_hdd_tdls_free_list(void)
294{
295 int i;
296 struct list_head *head;
297 hddTdlsPeer_t *tmp;
298 struct list_head *pos, *q;
299
300 if (NULL == pHddTdlsCtx) return;
301
302 if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
303 {
304 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
305 "%s: unable to lock list", __func__);
306 return;
307 }
308
309 for (i = 0; i < 256; i++) {
310 head = &pHddTdlsCtx->peer_list[i];
311 list_for_each_safe (pos, q, head) {
312 tmp = list_entry(pos, hddTdlsPeer_t, node);
313 list_del(pos);
314 vos_mem_free(tmp);
315 }
316 }
317 mutex_unlock(&pHddTdlsCtx->lock);
318
319}
320
Chilam NG571c65a2013-01-19 12:27:36 +0530321int wlan_hdd_tdls_init(struct net_device *dev)
322{
Hoonki Lee387663d2013-02-05 18:08:43 -0800323 int i;
Chilam NG571c65a2013-01-19 12:27:36 +0530324 VOS_STATUS status;
Hoonki Leebf870f32013-01-19 15:53:30 +0530325 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
326 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
Chilam NG571c65a2013-01-19 12:27:36 +0530327
Hoonki Lee387663d2013-02-05 18:08:43 -0800328 if (FALSE == pHddCtx->cfg_ini->fEnableTDLSSupport)
Hoonki Leebf870f32013-01-19 15:53:30 +0530329 {
330 hddLog(VOS_TRACE_LEVEL_ERROR, "%s TDLS not enabled!", __func__);
Hoonki Lee387663d2013-02-05 18:08:43 -0800331 return 0;
Hoonki Leebf870f32013-01-19 15:53:30 +0530332 }
333
334 pHddTdlsCtx = vos_mem_malloc(sizeof(tdlsCtx_t));
Chilam NG571c65a2013-01-19 12:27:36 +0530335 if (NULL == pHddTdlsCtx) {
336 hddLog(VOS_TRACE_LEVEL_ERROR, "%s malloc failed!", __func__);
337 return -1;
338 }
339
340 vos_mem_zero(pHddTdlsCtx, sizeof(tdlsCtx_t));
341
342 pHddTdlsCtx->dev = dev;
343
Hoonki Lee387663d2013-02-05 18:08:43 -0800344 mutex_init(&pHddTdlsCtx->lock);
345 for (i = 0; i < 256; i++)
346 {
347 INIT_LIST_HEAD(&pHddTdlsCtx->peer_list[i]);
348 }
349
Chilam Nga75d8b62013-01-29 01:35:59 -0800350 tdlsImplicitTrigger = pHddCtx->cfg_ini->fEnableTDLSImplicitTrigger;
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800351
352 status = vos_timer_init(&pHddTdlsCtx->peerDiscoverTimer,
353 VOS_TIMER_TYPE_SW,
354 wlan_hdd_tdls_discover_peer_cb,
355 pHddTdlsCtx);
356
357 status = vos_timer_init(&pHddTdlsCtx->peerUpdateTimer,
358 VOS_TIMER_TYPE_SW,
359 wlan_hdd_tdls_update_peer_cb,
360 pHddTdlsCtx);
361
Hoonki Lee387663d2013-02-05 18:08:43 -0800362 if (FALSE == tdlsImplicitTrigger)
Hoonki Leebf870f32013-01-19 15:53:30 +0530363 {
364 hddLog(VOS_TRACE_LEVEL_ERROR, "%s TDLS Implicit trigger not enabled!", __func__);
Hoonki Lee387663d2013-02-05 18:08:43 -0800365 return 0;
Hoonki Leebf870f32013-01-19 15:53:30 +0530366 }
367 pHddTdlsCtx->threshold_config.tx_period_t = pHddCtx->cfg_ini->fTDLSTxStatsPeriod;
368 pHddTdlsCtx->threshold_config.tx_packet_n = pHddCtx->cfg_ini->fTDLSTxPacketThreshold;
369 pHddTdlsCtx->threshold_config.discovery_period_t = pHddCtx->cfg_ini->fTDLSDiscoveryPeriod;
370 pHddTdlsCtx->threshold_config.discovery_tries_n = pHddCtx->cfg_ini->fTDLSMaxDiscoveryAttempt;
371 pHddTdlsCtx->threshold_config.rx_timeout_t = pHddCtx->cfg_ini->fTDLSRxIdleTimeout;
372 pHddTdlsCtx->threshold_config.rssi_hysteresis = pHddCtx->cfg_ini->fTDLSRssiHysteresis;
Chilam NG571c65a2013-01-19 12:27:36 +0530373
Chilam NG571c65a2013-01-19 12:27:36 +0530374
375 status = vos_timer_start( &pHddTdlsCtx->peerDiscoverTimer,
376 pHddTdlsCtx->threshold_config.discovery_period_t );
377
Chilam NG571c65a2013-01-19 12:27:36 +0530378
379 status = vos_timer_start( &pHddTdlsCtx->peerUpdateTimer,
380 pHddTdlsCtx->threshold_config.tx_period_t );
381
382 return 0;
383}
384
385void wlan_hdd_tdls_exit()
386{
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800387 if (NULL == pHddTdlsCtx)
388 {
Hoonki Leebfee0342013-01-21 16:43:45 -0800389 hddLog(VOS_TRACE_LEVEL_WARN, "%s TDLS not enabled, exiting!", __func__);
390 return;
391 }
392
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800393 if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
394 {
395 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
396 "%s: unable to lock list", __func__);
397 return;
Hoonki Leebfee0342013-01-21 16:43:45 -0800398 }
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800399 /* must stop timer here before freeing peer list, because peerIdleTimer is
400 part of peer list structure. */
401 wlan_hdd_tdls_timers_stop();
402 mutex_unlock(&pHddTdlsCtx->lock);
Hoonki Lee387663d2013-02-05 18:08:43 -0800403 wlan_hdd_tdls_free_list();
Chilam Nga75d8b62013-01-29 01:35:59 -0800404
405 vos_mem_free(pHddTdlsCtx);
406 pHddTdlsCtx = NULL;
Chilam NG571c65a2013-01-19 12:27:36 +0530407}
408
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800409/* Stop all the tdls timers running */
410void wlan_hdd_tdls_timers_stop()
411{
412 int i;
413 struct list_head *head;
414 struct list_head *pos;
415 hddTdlsPeer_t *curr_peer;
416
417 vos_timer_stop(&pHddTdlsCtx->peerDiscoverTimer);
418 vos_timer_destroy(&pHddTdlsCtx->peerDiscoverTimer);
419 vos_timer_stop(&pHddTdlsCtx->peerUpdateTimer);
420 vos_timer_destroy(&pHddTdlsCtx->peerUpdateTimer);
421
422 for (i = 0; i < 256; i++)
423 {
424 head = &pHddTdlsCtx->peer_list[i];
425
426 list_for_each (pos, head) {
427 curr_peer = list_entry (pos, hddTdlsPeer_t, node);
428
429 VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
430 "%s: %02x:%02x:%02x:%02x:%02x:%02x -> destroy idle timer ",
431 __func__,
432 curr_peer->peerMac[0], curr_peer->peerMac[1],
433 curr_peer->peerMac[2], curr_peer->peerMac[3],
434 curr_peer->peerMac[4], curr_peer->peerMac[5]);
435 vos_timer_stop ( &curr_peer->peerIdleTimer );
436 vos_timer_destroy ( &curr_peer->peerIdleTimer );
437 }
438 }
439}
440
Hoonki Lee387663d2013-02-05 18:08:43 -0800441/* if mac address exist, return pointer
442 if mac address doesn't exist, create a list and add, return pointer
443 return NULL if fails to get new mac address
444*/
445hddTdlsPeer_t *wlan_hdd_tdls_get_peer(u8 *mac)
Chilam NG571c65a2013-01-19 12:27:36 +0530446{
Hoonki Lee387663d2013-02-05 18:08:43 -0800447 struct list_head *head;
448 hddTdlsPeer_t *peer;
449 u8 key;
Chilam NG571c65a2013-01-19 12:27:36 +0530450
Hoonki Lee387663d2013-02-05 18:08:43 -0800451 if (NULL == pHddTdlsCtx)
452 return NULL;
Hoonki Leebfee0342013-01-21 16:43:45 -0800453
Hoonki Lee387663d2013-02-05 18:08:43 -0800454 /* if already there, just update */
455 peer = wlan_hdd_tdls_find_peer(mac);
456 if (peer != NULL)
457 {
458 return peer;
Chilam NG571c65a2013-01-19 12:27:36 +0530459 }
460
Hoonki Lee387663d2013-02-05 18:08:43 -0800461 /* not found, allocate and add the list */
462 peer = vos_mem_malloc(sizeof(hddTdlsPeer_t));
463 if (NULL == peer) {
464 hddLog(VOS_TRACE_LEVEL_ERROR, "%s peer malloc failed!", __func__);
465 return NULL;
466 }
Chilam NG571c65a2013-01-19 12:27:36 +0530467
Hoonki Lee387663d2013-02-05 18:08:43 -0800468 key = wlan_hdd_tdls_hash_key(mac);
469 head = &pHddTdlsCtx->peer_list[key];
Chilam NG571c65a2013-01-19 12:27:36 +0530470
Hoonki Lee387663d2013-02-05 18:08:43 -0800471 if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
472 {
473 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
474 "%s: unable to lock list", __func__);
475 return NULL;
476 }
Chilam NG571c65a2013-01-19 12:27:36 +0530477
Hoonki Lee387663d2013-02-05 18:08:43 -0800478 vos_mem_zero(peer, sizeof(hddTdlsPeer_t));
479 vos_mem_copy(peer->peerMac, mac, sizeof(peer->peerMac));
480
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800481 vos_timer_init(&peer->peerIdleTimer,
482 VOS_TIMER_TYPE_SW,
483 wlan_hdd_tdls_idle_cb,
484 peer);
485
Hoonki Lee387663d2013-02-05 18:08:43 -0800486 list_add_tail(&peer->node, head);
487 mutex_unlock(&pHddTdlsCtx->lock);
488
489 return peer;
490}
491
492void wlan_hdd_tdls_set_link_status(hddTdlsPeer_t *curr_peer, int status)
493{
494 if (curr_peer == NULL)
495 return;
496
497 hddLog(VOS_TRACE_LEVEL_WARN, "tdls set peer %02x:%02x:%02x:%02x:%02x:%02x link status to %d",
498 curr_peer->peerMac[0], curr_peer->peerMac[1],
499 curr_peer->peerMac[2], curr_peer->peerMac[3],
500 curr_peer->peerMac[4], curr_peer->peerMac[5],
501 status);
Chilam NG571c65a2013-01-19 12:27:36 +0530502
503 curr_peer->link_status = status;
504
Chilam NG571c65a2013-01-19 12:27:36 +0530505}
506
507int wlan_hdd_tdls_set_cap(u8 *mac, int cap)
508{
509 hddTdlsPeer_t *curr_peer;
Chilam NG571c65a2013-01-19 12:27:36 +0530510
Hoonki Leebfee0342013-01-21 16:43:45 -0800511 if (NULL == pHddTdlsCtx) return -1;
512
Hoonki Lee387663d2013-02-05 18:08:43 -0800513 curr_peer = wlan_hdd_tdls_get_peer(mac);
514 if (curr_peer == NULL)
515 return -1;
Chilam NG571c65a2013-01-19 12:27:36 +0530516
517 curr_peer->tdls_support = cap;
518
Hoonki Lee387663d2013-02-05 18:08:43 -0800519 return 0;
Chilam NG571c65a2013-01-19 12:27:36 +0530520}
521
522int wlan_hdd_tdls_set_rssi(u8 *mac, tANI_S8 rxRssi)
523{
524 hddTdlsPeer_t *curr_peer;
Chilam NG571c65a2013-01-19 12:27:36 +0530525
Hoonki Leebfee0342013-01-21 16:43:45 -0800526 if (NULL == pHddTdlsCtx) return -1;
527
Hoonki Lee387663d2013-02-05 18:08:43 -0800528 curr_peer = wlan_hdd_tdls_get_peer(mac);
529 if (curr_peer == NULL)
530 return -1;
Chilam NG571c65a2013-01-19 12:27:36 +0530531
532 curr_peer->rssi = rxRssi;
533
Hoonki Lee387663d2013-02-05 18:08:43 -0800534 return 0;
Chilam NG571c65a2013-01-19 12:27:36 +0530535}
536
Hoonki Leea34dd892013-02-05 22:56:02 -0800537int wlan_hdd_tdls_set_responder(u8 *mac, tANI_U8 responder)
538{
539 hddTdlsPeer_t *curr_peer;
540
541 if (NULL == pHddTdlsCtx) return -1;
542
543 curr_peer = wlan_hdd_tdls_get_peer(mac);
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800544 if (curr_peer == NULL)
Hoonki Leea34dd892013-02-05 22:56:02 -0800545 return -1;
546
547 curr_peer->is_responder = responder;
548
549 return 0;
550}
551
552int wlan_hdd_tdls_get_responder(u8 *mac)
553{
554 hddTdlsPeer_t *curr_peer;
555
556 if (NULL == pHddTdlsCtx) return -1;
557
558 curr_peer = wlan_hdd_tdls_find_peer(mac);
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800559 if (curr_peer == NULL)
Hoonki Leea34dd892013-02-05 22:56:02 -0800560 return -1;
561
562 return (curr_peer->is_responder);
563}
564
565
Hoonki Lee387663d2013-02-05 18:08:43 -0800566void wlan_hdd_tdls_extract_da(struct sk_buff *skb, u8 *mac)
Chilam NG571c65a2013-01-19 12:27:36 +0530567{
Chilam NG571c65a2013-01-19 12:27:36 +0530568 memcpy(mac, skb->data, 6);
Chilam NG571c65a2013-01-19 12:27:36 +0530569}
570
Hoonki Lee387663d2013-02-05 18:08:43 -0800571void wlan_hdd_tdls_extract_sa(struct sk_buff *skb, u8 *mac)
Chilam Ng1279e232013-01-25 15:06:52 -0800572{
Chilam Ng1279e232013-01-25 15:06:52 -0800573 memcpy(mac, skb->data+6, 6);
Chilam Ng1279e232013-01-25 15:06:52 -0800574}
575
Hoonki Lee387663d2013-02-05 18:08:43 -0800576int wlan_hdd_tdls_increment_pkt_count(u8 *mac, u8 tx)
Chilam NG571c65a2013-01-19 12:27:36 +0530577{
Hoonki Lee387663d2013-02-05 18:08:43 -0800578 hddTdlsPeer_t *curr_peer;
Chilam NG571c65a2013-01-19 12:27:36 +0530579
Hoonki Leebfee0342013-01-21 16:43:45 -0800580 if (NULL == pHddTdlsCtx) return -1;
581
Hoonki Lee387663d2013-02-05 18:08:43 -0800582 curr_peer = wlan_hdd_tdls_get_peer(mac);
583 if (curr_peer == NULL)
Chilam NG571c65a2013-01-19 12:27:36 +0530584 return -1;
Chilam NG571c65a2013-01-19 12:27:36 +0530585
Chilam Ng1279e232013-01-25 15:06:52 -0800586 if (tx)
587 curr_peer->tx_pkt++;
588 else
589 curr_peer->rx_pkt++;
Chilam NG571c65a2013-01-19 12:27:36 +0530590
Chilam NG571c65a2013-01-19 12:27:36 +0530591 return 0;
592}
593
594int wlan_hdd_tdls_set_params(tdls_config_params_t *config)
595{
Chilam Nga75d8b62013-01-29 01:35:59 -0800596 if (NULL == pHddTdlsCtx ||
597 FALSE == tdlsImplicitTrigger) return -1;
Hoonki Leebfee0342013-01-21 16:43:45 -0800598
Chilam NG571c65a2013-01-19 12:27:36 +0530599 vos_timer_stop( &pHddTdlsCtx->peerDiscoverTimer);
600
601 vos_timer_stop( &pHddTdlsCtx->peerUpdateTimer);
602
603 memcpy(&pHddTdlsCtx->threshold_config, config, sizeof(tdls_config_params_t));
604
605 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
606 "iw set tdls params: %d %d %d %d %d %d",
607 pHddTdlsCtx->threshold_config.tx_period_t,
608 pHddTdlsCtx->threshold_config.tx_packet_n,
609 pHddTdlsCtx->threshold_config.discovery_period_t,
610 pHddTdlsCtx->threshold_config.discovery_tries_n,
611 pHddTdlsCtx->threshold_config.rx_timeout_t,
612 pHddTdlsCtx->threshold_config.rssi_hysteresis);
613
614 vos_timer_start( &pHddTdlsCtx->peerDiscoverTimer,
615 pHddTdlsCtx->threshold_config.discovery_period_t );
616
617 vos_timer_start( &pHddTdlsCtx->peerUpdateTimer,
618 pHddTdlsCtx->threshold_config.tx_period_t );
619 return 0;
620}
621
Hoonki Lee387663d2013-02-05 18:08:43 -0800622int wlan_hdd_tdls_set_sta_id(u8 *mac, u8 staId)
Kiran V1ccee932012-12-12 14:49:46 -0800623{
Hoonki Lee387663d2013-02-05 18:08:43 -0800624 hddTdlsPeer_t *curr_peer;
Kiran V1ccee932012-12-12 14:49:46 -0800625
Hoonki Leebfee0342013-01-21 16:43:45 -0800626 if (NULL == pHddTdlsCtx) return -1;
627
Hoonki Lee387663d2013-02-05 18:08:43 -0800628 curr_peer = wlan_hdd_tdls_get_peer(mac);
629 if (curr_peer == NULL)
Chilam NG571c65a2013-01-19 12:27:36 +0530630 return -1;
Chilam NG571c65a2013-01-19 12:27:36 +0530631
Hoonki Lee387663d2013-02-05 18:08:43 -0800632 curr_peer->staId = staId;
Chilam NG571c65a2013-01-19 12:27:36 +0530633
634 return 0;
Kiran V1ccee932012-12-12 14:49:46 -0800635}
636
Hoonki Lee387663d2013-02-05 18:08:43 -0800637/* if peerMac is found, then it returns pointer to hddTdlsPeer_t
638 otherwise, it returns NULL
639*/
640hddTdlsPeer_t *wlan_hdd_tdls_find_peer(u8 *mac)
Kiran V1ccee932012-12-12 14:49:46 -0800641{
Hoonki Lee387663d2013-02-05 18:08:43 -0800642 u8 key;
643 struct list_head *pos;
644 struct list_head *head;
645 hddTdlsPeer_t *curr_peer;
646
647 if (NULL == pHddTdlsCtx)
648 return NULL;
649
650 key = wlan_hdd_tdls_hash_key(mac);
651
652 head = &pHddTdlsCtx->peer_list[key];
653
654 if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
655 {
656 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
657 "%s: unable to lock list", __func__);
658 return NULL;
659 }
660
661 list_for_each(pos, head) {
662 curr_peer = list_entry (pos, hddTdlsPeer_t, node);
663 if (!memcmp(mac, curr_peer->peerMac, 6)) {
664 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
665 "findTdlsPeer: found staId %d", curr_peer->staId);
666 mutex_unlock(&pHddTdlsCtx->lock);
667 return curr_peer;
668 }
669 }
670
671 mutex_unlock(&pHddTdlsCtx->lock);
672 return NULL;
673}
674
675int wlan_hdd_tdls_reset_peer(u8 *mac)
676{
Chilam NG571c65a2013-01-19 12:27:36 +0530677 hddTdlsPeer_t *curr_peer;
Kiran V1ccee932012-12-12 14:49:46 -0800678
Hoonki Leebfee0342013-01-21 16:43:45 -0800679 if (NULL == pHddTdlsCtx) return -1;
680
Hoonki Lee387663d2013-02-05 18:08:43 -0800681 curr_peer = wlan_hdd_tdls_get_peer(mac);
682 if (curr_peer == NULL)
683 return -1;
Chilam NG571c65a2013-01-19 12:27:36 +0530684
Hoonki Leecdd8e962013-01-20 00:45:46 -0800685 curr_peer->link_status = eTDLS_LINK_NOT_CONNECTED;
686 curr_peer->staId = 0;
687 curr_peer->rssi = -120;
Hoonki Lee387663d2013-02-05 18:08:43 -0800688
689 if (FALSE != tdlsImplicitTrigger) {
Chilam Nga75d8b62013-01-29 01:35:59 -0800690 vos_timer_stop( &curr_peer->peerIdleTimer );
Chilam Nga75d8b62013-01-29 01:35:59 -0800691 }
Hoonki Lee387663d2013-02-05 18:08:43 -0800692 return 0;
Hoonki Leecdd8e962013-01-20 00:45:46 -0800693}
694
Lee Hoonkic1262f22013-01-24 21:59:00 -0800695/* TODO: Currently I am using conn_info.staId
696 here as per current design but tdls.c shouldn't
697 have touch this.*/
698u8 wlan_hdd_tdlsConnectedPeers(void)
699{
700 hdd_adapter_t *pAdapter;
701 hdd_station_ctx_t *pHddStaCtx;
702 u8 staIdx;
703 u8 count = 0;
704
705 if (NULL == pHddTdlsCtx) return -1;
706
707 pAdapter = WLAN_HDD_GET_PRIV_PTR(pHddTdlsCtx->dev);
708 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
709
Gopichand Nakkala2a0a1572013-02-10 21:39:16 -0800710 /* 0 staIdx is assigned to AP we dont want to touch that */
711 for (staIdx = 1 ; staIdx < HDD_MAX_NUM_TDLS_STA; staIdx++)
Lee Hoonkic1262f22013-01-24 21:59:00 -0800712 {
713 if (0 != pHddStaCtx->conn_info.staId[staIdx] )
714 count++;
715 }
716 return count;
717}
Chilam Ng16a2a1c2013-01-29 01:27:29 -0800718
719int wlan_hdd_tdls_get_all_peers(char *buf, int buflen)
720{
721 int i;
722 int len, init_len;
Hoonki Lee387663d2013-02-05 18:08:43 -0800723 struct list_head *head;
724 struct list_head *pos;
Chilam Ng16a2a1c2013-01-29 01:27:29 -0800725 hddTdlsPeer_t *curr_peer;
726
727 if (NULL == pHddTdlsCtx) {
728 len = snprintf(buf, buflen, "TDLS not enabled\n");
729 return len;
730 }
731
732 init_len = buflen;
733 len = snprintf(buf, buflen, "\n%-18s%-3s%-4s%-3s%-5s\n", "MAC", "Id", "cap", "up", "RSSI");
734 buf += len;
735 buflen -= len;
736 /* 1234567890123456789012345678901234567 */
737 len = snprintf(buf, buflen, "---------------------------------\n");
738 buf += len;
739 buflen -= len;
740
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800741 if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
742 {
743 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
744 "%s: unable to lock list", __func__);
745 return init_len-buflen;
746 }
Chilam Ng16a2a1c2013-01-29 01:27:29 -0800747 for (i = 0; i < 256; i++) {
Hoonki Lee387663d2013-02-05 18:08:43 -0800748 head = &pHddTdlsCtx->peer_list[i];
Chilam Ng16a2a1c2013-01-29 01:27:29 -0800749
Hoonki Lee387663d2013-02-05 18:08:43 -0800750 list_for_each(pos, head) {
751 curr_peer= list_entry (pos, hddTdlsPeer_t, node);
Chilam Ng16a2a1c2013-01-29 01:27:29 -0800752
Hoonki Lee387663d2013-02-05 18:08:43 -0800753 if (buflen < 32+1)
754 break;
755 len = snprintf(buf, buflen,
756 "%02x:%02x:%02x:%02x:%02x:%02x%3d%4s%3s%5d\n",
757 curr_peer->peerMac[0], curr_peer->peerMac[1],
758 curr_peer->peerMac[2], curr_peer->peerMac[3],
759 curr_peer->peerMac[4], curr_peer->peerMac[5],
760 curr_peer->staId,
761 (curr_peer->tdls_support == eTDLS_CAP_SUPPORTED) ? "Y":"N",
762 (curr_peer->link_status == eTDLS_LINK_CONNECTED) ? "Y":"N",
763 curr_peer->rssi);
764 buf += len;
765 buflen -= len;
Chilam Ng16a2a1c2013-01-29 01:27:29 -0800766 }
767 }
Gopichand Nakkala91b09262013-02-10 14:27:02 -0800768 mutex_unlock(&pHddTdlsCtx->lock);
Chilam Ng16a2a1c2013-01-29 01:27:29 -0800769 return init_len-buflen;
770}