blob: d0be7d0b471d07c7248a88d305bca8837e716344 [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
Gopichand Nakkala92f07d82013-01-08 21:16:34 -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 */
21/*
Jeff Johnson32d95a32012-09-10 13:15:23 -070022 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
Jeff Johnson295189b2012-06-20 16:38:30 -070023 *
24 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
25 *
26 *
27 * Permission to use, copy, modify, and/or distribute this software for
28 * any purpose with or without fee is hereby granted, provided that the
29 * above copyright notice and this permission notice appear in all
30 * copies.
31 *
32 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
33 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
34 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
35 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
36 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
37 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
38 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
39 * PERFORMANCE OF THIS SOFTWARE.
40 */
41
42/**========================================================================
43
44 \file wlan_hdd_p2p.c
45
46 \brief WLAN Host Device Driver implementation for P2P commands interface
47
48 Copyright 2008 (c) Qualcomm, Incorporated. All Rights Reserved.
49
50 Qualcomm Confidential and Proprietary.
51
52 ========================================================================*/
Jeff Johnson295189b2012-06-20 16:38:30 -070053
54#include <wlan_hdd_includes.h>
55#include <wlan_hdd_hostapd.h>
56#include <net/cfg80211.h>
57#include "sme_Api.h"
58#include "wlan_hdd_p2p.h"
59#include "sapApi.h"
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +053060#include "wlan_hdd_main.h"
Jeff Johnson295189b2012-06-20 16:38:30 -070061
62#include <linux/netdevice.h>
63#include <linux/skbuff.h>
64#include <linux/etherdevice.h>
65#include <net/ieee80211_radiotap.h>
Hoonki Lee1090c6a2013-01-16 17:40:54 -080066#ifdef FEATURE_WLAN_TDLS
67#include "wlan_hdd_tdls.h"
68#endif
Jeff Johnson295189b2012-06-20 16:38:30 -070069
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -080070//Ms to Micro Sec
71#define MS_TO_MUS(x) ((x)*1000);
72
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -070073#ifdef WLAN_FEATURE_P2P_DEBUG
74#define MAX_P2P_ACTION_FRAME_TYPE 9
75const char *p2p_action_frame_type[]={"GO Negotiation Request",
76 "GO Negotiation Response",
77 "GO Negotiation Confirmation",
78 "P2P Invitation Request",
79 "P2P Invitation Response",
80 "Device Discoverability Request",
81 "Device Discoverability Response",
82 "Provision Discovery Request",
83 "Provision Discovery Response"};
84
85/* We no need to protect this variable since
86 * there is no chance of race to condition
87 * and also not make any complicating the code
88 * just for debugging log
89 */
90tP2PConnectionStatus globalP2PConnectionStatus = P2P_NOT_ACTIVE;
91
92#endif
Hoonki Lee1090c6a2013-01-16 17:40:54 -080093#ifdef WLAN_FEATURE_TDLS_DEBUG
94#define MAX_TDLS_ACTION_FRAME_TYPE 11
95const char *tdls_action_frame_type[] = {"TDLS Setup Request",
96 "TDLS Setup Response",
97 "TDLS Setup Confirm",
98 "TDLS Teardown",
99 "TDLS Peer Traffic Indication",
100 "TDLS Channel Switch Request",
101 "TDLS Channel Switch Response",
102 "TDLS Peer PSM Request",
103 "TDLS Peer PSM Response",
104 "TDLS Peer Traffic Response",
105 "TDLS Discovery Request" };
106#endif
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -0700107
Jeff Johnson295189b2012-06-20 16:38:30 -0700108extern struct net_device_ops net_ops_struct;
109
110static int hdd_wlan_add_rx_radiotap_hdr( struct sk_buff *skb,
111 int rtap_len, int flag );
112
113static void hdd_wlan_tx_complete( hdd_adapter_t* pAdapter,
114 hdd_cfg80211_state_t* cfgState,
115 tANI_BOOLEAN actionSendSuccess );
116
117static void hdd_sendMgmtFrameOverMonitorIface( hdd_adapter_t *pMonAdapter,
118 tANI_U32 nFrameLength,
119 tANI_U8* pbFrames,
120 tANI_U8 frameType );
121
Jeff Johnson295189b2012-06-20 16:38:30 -0700122eHalStatus wlan_hdd_remain_on_channel_callback( tHalHandle hHal, void* pCtx,
123 eHalStatus status )
124{
125 hdd_adapter_t *pAdapter = (hdd_adapter_t*) pCtx;
Jeff Johnson295189b2012-06-20 16:38:30 -0700126 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
127 hdd_remain_on_chan_ctx_t *pRemainChanCtx = cfgState->remain_on_chan_ctx;
128
129 if( pRemainChanCtx == NULL )
130 {
131 hddLog( LOGW,
132 "%s: No Rem on channel pending for which Rsp is received", __func__);
133 return eHAL_STATUS_SUCCESS;
134 }
135
136 hddLog( LOG1, "Received remain on channel rsp");
137
138 cfgState->remain_on_chan_ctx = NULL;
139
140 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
141 {
142 if( cfgState->buf )
143 {
144 hddLog( LOGP,
145 "%s: We need to receive yet an ack from one of tx packet",
146 __func__);
147 }
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800148 cfg80211_remain_on_channel_expired(
149#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
150 pRemainChanCtx->dev->ieee80211_ptr,
151#else
152 pRemainChanCtx->dev,
153#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700154 pRemainChanCtx->cookie,
155 &pRemainChanCtx->chan,
Yue Maf49ba872013-08-19 12:04:25 -0700156#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
157 pRemainChanCtx->chan_type,
158#endif
159 GFP_KERNEL);
Jeff Johnson295189b2012-06-20 16:38:30 -0700160 }
161
Jeff Johnson295189b2012-06-20 16:38:30 -0700162
163 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700164 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
165 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700166 )
167 {
168 tANI_U8 sessionId = pAdapter->sessionId;
Madan Mohan Koyyalamudi35885912012-11-30 15:05:42 -0800169 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
170 {
171 sme_DeregisterMgmtFrame(
172 hHal, sessionId,
173 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
174 NULL, 0 );
175 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700176 }
177 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
178 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
179 )
180 {
181 WLANSAP_DeRegisterMgmtFrame(
182 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
183 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
184 NULL, 0 );
185 }
186
Madan Mohan Koyyalamudi35885912012-11-30 15:05:42 -0800187 vos_mem_free( pRemainChanCtx );
Jeff Johnson295189b2012-06-20 16:38:30 -0700188 complete(&pAdapter->cancel_rem_on_chan_var);
189 return eHAL_STATUS_SUCCESS;
190}
191
Gopichand Nakkalaf527dc62012-12-31 16:35:10 -0800192void wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter)
Jeff Johnson295189b2012-06-20 16:38:30 -0700193{
Jeff Johnson295189b2012-06-20 16:38:30 -0700194 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
195 int status = 0;
Jeff Johnson295189b2012-06-20 16:38:30 -0700196
Jeff Johnson32d95a32012-09-10 13:15:23 -0700197 if(cfgState->remain_on_chan_ctx != NULL)
Jeff Johnson295189b2012-06-20 16:38:30 -0700198 {
Jeff Johnson32d95a32012-09-10 13:15:23 -0700199 hddLog( LOG1, "Cancel Existing Remain on Channel");
200
201 /* Wait till remain on channel ready indication before issuing cancel
202 * remain on channel request, otherwise if remain on channel not
203 * received and if the driver issues cancel remain on channel then lim
Jeff Johnson295189b2012-06-20 16:38:30 -0700204 * will be in unknown state.
205 */
206 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
207 msecs_to_jiffies(WAIT_REM_CHAN_READY));
208 if (!status)
209 {
210 hddLog( LOGE,
211 "%s: timeout waiting for remain on channel ready indication",
212 __func__);
213 }
214
215 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
Jeff Johnson32d95a32012-09-10 13:15:23 -0700216
Jeff Johnson295189b2012-06-20 16:38:30 -0700217 /* Issue abort remain on chan request to sme.
218 * The remain on channel callback will make sure the remain_on_chan
219 * expired event is sent.
220 */
221 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700222 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
223 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700224 )
225 {
226 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
227 pAdapter->sessionId );
228 }
229 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
230 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
231 )
232 {
233 WLANSAP_CancelRemainOnChannel(
234 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
235 }
Jeff Johnsone7245742012-09-05 17:12:55 -0700236
Jeff Johnson32d95a32012-09-10 13:15:23 -0700237 status = wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
Jeff Johnson295189b2012-06-20 16:38:30 -0700238 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
Jeff Johnson32d95a32012-09-10 13:15:23 -0700239
240 if (!status)
241 {
242 hddLog( LOGE,
243 "%s: timeout waiting for cancel remain on channel ready indication",
244 __func__);
245 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700246 }
Jeff Johnson32d95a32012-09-10 13:15:23 -0700247}
248
249int wlan_hdd_check_remain_on_channel(hdd_adapter_t *pAdapter)
250{
251 int status = 0;
252 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
253
254 if(WLAN_HDD_P2P_GO != pAdapter->device_mode)
255 {
256 //Cancel Existing Remain On Channel
257 //If no action frame is pending
258 if( cfgState->remain_on_chan_ctx != NULL)
259 {
260 //Check whether Action Frame is pending or not
261 if( cfgState->buf == NULL)
262 {
263 wlan_hdd_cancel_existing_remain_on_channel(pAdapter);
264 }
265 else
266 {
267 hddLog( LOG1, "Cannot Cancel Existing Remain on Channel");
268 status = -EBUSY;
269 }
270 }
271 }
272 return status;
273}
274
275static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy,
276 struct net_device *dev,
277 struct ieee80211_channel *chan,
Yue Maf49ba872013-08-19 12:04:25 -0700278#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
Jeff Johnson32d95a32012-09-10 13:15:23 -0700279 enum nl80211_channel_type channel_type,
Yue Maf49ba872013-08-19 12:04:25 -0700280#endif
Jeff Johnson32d95a32012-09-10 13:15:23 -0700281 unsigned int duration, u64 *cookie,
282 rem_on_channel_request_type_t request_type )
283{
284 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
285 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
286 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
287 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
288 __func__,pAdapter->device_mode);
289
Yue Maf49ba872013-08-19 12:04:25 -0700290#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
Jeff Johnson32d95a32012-09-10 13:15:23 -0700291 hddLog( LOG1,
292 "chan(hw_val)0x%x chan(centerfreq) %d chan type 0x%x, duration %d",
293 chan->hw_value, chan->center_freq, channel_type, duration );
Yue Maf49ba872013-08-19 12:04:25 -0700294#else
295 hddLog( LOG1,
296 "chan(hw_val)0x%x chan(centerfreq) %d, duration %d",
297 chan->hw_value, chan->center_freq, duration );
298#endif
Jeff Johnson32d95a32012-09-10 13:15:23 -0700299 //Cancel existing remain On Channel if any
300 wlan_hdd_cancel_existing_remain_on_channel(pAdapter);
Jeff Johnson295189b2012-06-20 16:38:30 -0700301
Jeff Johnsone7245742012-09-05 17:12:55 -0700302 /* When P2P-GO and if we are trying to unload the driver then
Jeff Johnson295189b2012-06-20 16:38:30 -0700303 * wlan driver is keep on receiving the remain on channel command
Jeff Johnsone7245742012-09-05 17:12:55 -0700304 * and which is resulting in crash. So not allowing any remain on
Jeff Johnson295189b2012-06-20 16:38:30 -0700305 * channel requets when Load/Unload is in progress*/
306 if (((hdd_context_t*)pAdapter->pHddCtx)->isLoadUnloadInProgress)
307 {
308 hddLog( LOGE,
309 "%s: Wlan Load/Unload is in progress", __func__);
310 return -EBUSY;
311 }
312
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700313 if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress)
314 {
315 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
316 "%s:LOGP in Progress. Ignore!!!", __func__);
317 return -EAGAIN;
318 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700319 pRemainChanCtx = vos_mem_malloc( sizeof(hdd_remain_on_chan_ctx_t) );
320 if( NULL == pRemainChanCtx )
321 {
322 hddLog(VOS_TRACE_LEVEL_FATAL,
323 "%s: Not able to allocate memory for Channel context",
324 __func__);
325 return -ENOMEM;
326 }
327
328 vos_mem_copy( &pRemainChanCtx->chan, chan,
329 sizeof(struct ieee80211_channel) );
330
Yue Maf49ba872013-08-19 12:04:25 -0700331#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
Jeff Johnson295189b2012-06-20 16:38:30 -0700332 pRemainChanCtx->chan_type = channel_type;
Yue Maf49ba872013-08-19 12:04:25 -0700333#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700334 pRemainChanCtx->duration = duration;
335 pRemainChanCtx->dev = dev;
Jeff Johnsonf67dca92013-11-08 17:07:40 -0800336 *cookie = (uintptr_t) pRemainChanCtx;
Jeff Johnson295189b2012-06-20 16:38:30 -0700337 pRemainChanCtx->cookie = *cookie;
338 pRemainChanCtx->rem_on_chan_request = request_type;
339 cfgState->remain_on_chan_ctx = pRemainChanCtx;
340 cfgState->current_freq = chan->center_freq;
341
342 INIT_COMPLETION(pAdapter->rem_on_chan_ready_event);
343
344 //call sme API to start remain on channel.
345 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700346 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
347 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700348 )
349 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700350 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700351 //call sme API to start remain on channel.
352 sme_RemainOnChannel(
353 WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId,
354 chan->hw_value, duration,
Gopichand Nakkala924e4552013-05-08 19:18:14 +0530355 wlan_hdd_remain_on_channel_callback, pAdapter,
356 (tANI_U8)(request_type == REMAIN_ON_CHANNEL_REQUEST)? TRUE:FALSE);
Jeff Johnson295189b2012-06-20 16:38:30 -0700357
Madan Mohan Koyyalamudi35885912012-11-30 15:05:42 -0800358 if( REMAIN_ON_CHANNEL_REQUEST == request_type)
359 {
360 sme_RegisterMgmtFrame(WLAN_HDD_GET_HAL_CTX(pAdapter),
361 sessionId, (SIR_MAC_MGMT_FRAME << 2) |
362 (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0 );
363 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700364
365 }
366 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
367 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
368 )
369 {
370 //call sme API to start remain on channel.
Jeff Johnson43971f52012-07-17 12:26:56 -0700371 if (VOS_STATUS_SUCCESS != WLANSAP_RemainOnChannel(
Jeff Johnson295189b2012-06-20 16:38:30 -0700372 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
373 chan->hw_value, duration,
374 wlan_hdd_remain_on_channel_callback, pAdapter ))
375
376 {
377 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
378 "%s: WLANSAP_RemainOnChannel returned fail", __func__);
379 cfgState->remain_on_chan_ctx = NULL;
Jeff Johnsone7245742012-09-05 17:12:55 -0700380 vos_mem_free (pRemainChanCtx);
Jeff Johnson295189b2012-06-20 16:38:30 -0700381 return -EINVAL;
382 }
383
384
Jeff Johnson43971f52012-07-17 12:26:56 -0700385 if (VOS_STATUS_SUCCESS != WLANSAP_RegisterMgmtFrame(
Jeff Johnson295189b2012-06-20 16:38:30 -0700386 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
387 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
388 NULL, 0 ))
389 {
390 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
391 "%s: WLANSAP_RegisterMgmtFrame returned fail", __func__);
392 WLANSAP_CancelRemainOnChannel(
393 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
394 return -EINVAL;
395 }
396
397 }
398 return 0;
399
400}
401
402int wlan_hdd_cfg80211_remain_on_channel( struct wiphy *wiphy,
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800403#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
404 struct wireless_dev *wdev,
405#else
Jeff Johnson295189b2012-06-20 16:38:30 -0700406 struct net_device *dev,
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800407#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700408 struct ieee80211_channel *chan,
Yue Maf49ba872013-08-19 12:04:25 -0700409#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
Jeff Johnson295189b2012-06-20 16:38:30 -0700410 enum nl80211_channel_type channel_type,
Yue Maf49ba872013-08-19 12:04:25 -0700411#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700412 unsigned int duration, u64 *cookie )
413{
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800414#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
415 struct net_device *dev = wdev->netdev;
416#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700417 return wlan_hdd_request_remain_on_channel(wiphy, dev,
Yue Maf49ba872013-08-19 12:04:25 -0700418 chan,
419#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
420 channel_type,
421#endif
422 duration, cookie,
Jeff Johnson295189b2012-06-20 16:38:30 -0700423 REMAIN_ON_CHANNEL_REQUEST);
424}
425
426void hdd_remainChanReadyHandler( hdd_adapter_t *pAdapter )
427{
428 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
429 hdd_remain_on_chan_ctx_t* pRemainChanCtx = cfgState->remain_on_chan_ctx;
430
431 hddLog( LOG1, "Ready on chan ind");
432
433 if( pRemainChanCtx != NULL )
434 {
435 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
436 {
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800437 cfg80211_ready_on_channel(
438#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
439 pAdapter->dev->ieee80211_ptr,
440#else
441 pAdapter->dev,
442#endif
Jeff Johnsonf67dca92013-11-08 17:07:40 -0800443 (uintptr_t)pRemainChanCtx,
Yue Maf49ba872013-08-19 12:04:25 -0700444 &pRemainChanCtx->chan,
445#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
446 pRemainChanCtx->chan_type,
447#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700448 pRemainChanCtx->duration, GFP_KERNEL );
449 }
450#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
451 else if( OFF_CHANNEL_ACTION_TX == pRemainChanCtx->rem_on_chan_request )
452 {
453 complete(&pAdapter->offchannel_tx_event);
454 }
455#endif
456 complete(&pAdapter->rem_on_chan_ready_event);
457 }
458 else
459 {
460 hddLog( LOGW, "%s: No Pending Remain on channel Request", __func__);
461 }
462 return;
463}
464
465int wlan_hdd_cfg80211_cancel_remain_on_channel( struct wiphy *wiphy,
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800466#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
467 struct wireless_dev *wdev,
468#else
469 struct net_device *dev,
470#endif
471 u64 cookie )
Jeff Johnson295189b2012-06-20 16:38:30 -0700472{
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800473#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
474 struct net_device *dev = wdev->netdev;
475#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700476 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson295189b2012-06-20 16:38:30 -0700477 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +0530478 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
479 int status;
Jeff Johnson295189b2012-06-20 16:38:30 -0700480
481 hddLog( LOG1, "Cancel remain on channel req");
482
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +0530483 status = wlan_hdd_validate_context(pHddCtx);
484
485 if (0 != status)
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700486 {
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +0530487 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
488 "%s: HDD context is not valid", __func__);
489 return status;
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700490 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700491 /* FIXME cancel currently running remain on chan.
492 * Need to check cookie and cancel accordingly
493 */
494 if( (cfgState->remain_on_chan_ctx == NULL) ||
495 (cfgState->remain_on_chan_ctx->cookie != cookie) )
496 {
497 hddLog( LOGE,
498 "%s: No Remain on channel pending with specified cookie value",
499 __func__);
500 return -EINVAL;
501 }
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +0530502
503 /* wait until remain on channel ready event received
Jeff Johnson295189b2012-06-20 16:38:30 -0700504 * for already issued remain on channel request */
505 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
506 msecs_to_jiffies(WAIT_REM_CHAN_READY));
507 if (!status)
508 {
509 hddLog( LOGE,
510 "%s: timeout waiting for remain on channel ready indication",
511 __func__);
512 }
513 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
514 /* Issue abort remain on chan request to sme.
515 * The remain on channel callback will make sure the remain_on_chan
516 * expired event is sent.
517 */
518 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700519 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
520 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700521 )
522 {
523 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700524 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
525 sessionId );
526 }
527 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
528 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
529 )
530 {
531 WLANSAP_CancelRemainOnChannel(
532 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
533 }
534 else
535 {
536 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Invalid device_mode = %d",
537 __func__, pAdapter->device_mode);
538 return -EIO;
539 }
540 wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
541 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
542 return 0;
543}
544
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800545#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
546int wlan_hdd_action( struct wiphy *wiphy, struct wireless_dev *wdev,
547 struct ieee80211_channel *chan, bool offchan,
Yue Maf49ba872013-08-19 12:04:25 -0700548#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800549 enum nl80211_channel_type channel_type,
Yue Maf49ba872013-08-19 12:04:25 -0700550 bool channel_type_valid,
551#endif
552 unsigned int wait,
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800553 const u8 *buf, size_t len, bool no_cck,
554 bool dont_wait_for_ack, u64 *cookie )
555#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
Jeff Johnson295189b2012-06-20 16:38:30 -0700556int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
557 struct ieee80211_channel *chan, bool offchan,
558 enum nl80211_channel_type channel_type,
559 bool channel_type_valid, unsigned int wait,
560 const u8 *buf, size_t len, bool no_cck,
561 bool dont_wait_for_ack, u64 *cookie )
562#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
563int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
564 struct ieee80211_channel *chan, bool offchan,
565 enum nl80211_channel_type channel_type,
566 bool channel_type_valid, unsigned int wait,
567 const u8 *buf, size_t len, u64 *cookie )
568#else
569int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
570 struct ieee80211_channel *chan,
571 enum nl80211_channel_type channel_type,
572 bool channel_type_valid,
573 const u8 *buf, size_t len, u64 *cookie )
574#endif //LINUX_VERSION_CODE
575{
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800576#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
577 struct net_device *dev = wdev->netdev;
578#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700579 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR( dev );
580 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +0530581 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
Jeff Johnsone7245742012-09-05 17:12:55 -0700582 tANI_U16 extendedWait = 0;
583 tANI_U8 type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]);
584 tANI_U8 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]);
585 tActionFrmType actionFrmType;
586 bool noack = 0;
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +0530587 int status;
Chet Lanctot186b5732013-03-18 10:26:30 -0700588#ifdef WLAN_FEATURE_11W
589 tANI_U8 *pTxFrmBuf = (tANI_U8 *) buf; // For SA Query, we have to set protect bit
590#endif
Jeff Johnsone7245742012-09-05 17:12:55 -0700591
Jeff Johnson295189b2012-06-20 16:38:30 -0700592#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
593 hdd_adapter_t *goAdapter;
594#endif
595
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +0530596 status = wlan_hdd_validate_context(pHddCtx);
597
598 if (0 != status)
Sameer Thalappil75ea31a2013-02-21 19:38:16 -0800599 {
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +0530600 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
601 "%s: HDD context is not valid", __func__);
602 return status;
Sameer Thalappil75ea31a2013-02-21 19:38:16 -0800603 }
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +0530604
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -0700605#ifdef WLAN_FEATURE_P2P_DEBUG
606 if ((type == SIR_MAC_MGMT_FRAME) &&
607 (subType == SIR_MAC_MGMT_ACTION) &&
608 (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
609 {
610 actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
Hoonki Lee1090c6a2013-01-16 17:40:54 -0800611 if(actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE)
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -0700612 {
613 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] unknown[%d] ---> OTA",
614 actionFrmType);
615 }
616 else
617 {
618 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] %s ---> OTA",
619 p2p_action_frame_type[actionFrmType]);
620 if( (actionFrmType == WLAN_HDD_PROV_DIS_REQ) &&
621 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
622 {
623 globalP2PConnectionStatus = P2P_GO_NEG_PROCESS;
624 hddLog(LOGE,"[P2P State]Inactive state to "
Jeff Johnson1250df42012-12-10 14:31:52 -0800625 "GO negotiation progress state");
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -0700626 }
627 else if( (actionFrmType == WLAN_HDD_GO_NEG_CNF) &&
628 (globalP2PConnectionStatus == P2P_GO_NEG_PROCESS) )
629 {
630 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
631 hddLog(LOGE,"[P2P State]GO nego progress to GO nego"
632 " completed state");
633 }
634 }
635 }
636#endif
637
Jeff Johnsone7245742012-09-05 17:12:55 -0700638#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
639 noack = dont_wait_for_ack;
640#endif
641
642 //If the wait is coming as 0 with off channel set
643 //then set the wait to 200 ms
644 if (offchan && !wait)
645 wait = ACTION_FRAME_DEFAULT_WAIT;
646
Jeff Johnson295189b2012-06-20 16:38:30 -0700647 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
648 __func__,pAdapter->device_mode);
649
650 //Call sme API to send out a action frame.
651 // OR can we send it directly through data path??
652 // After tx completion send tx status back.
653 if ( ( WLAN_HDD_SOFTAP == pAdapter->device_mode ) ||
654 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
655 )
656 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700657 if (type == SIR_MAC_MGMT_FRAME)
658 {
659 if (subType == SIR_MAC_MGMT_PROBE_RSP)
660 {
661 /* Drop Probe response recieved from supplicant, as for GO and
662 SAP PE itself sends probe response
663 */
664 goto err_rem_channel;
665 }
666 else if ((subType == SIR_MAC_MGMT_DISASSOC) ||
667 (subType == SIR_MAC_MGMT_DEAUTH))
668 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700669 /* During EAP failure or P2P Group Remove supplicant
670 * is sending del_station command to driver. From
671 * del_station function, Driver will send deauth frame to
672 * p2p client. No need to send disassoc frame from here.
673 * so Drop the frame here and send tx indication back to
674 * supplicant.
Jeff Johnson295189b2012-06-20 16:38:30 -0700675 */
676 tANI_U8 dstMac[ETH_ALEN] = {0};
677 memcpy(&dstMac, &buf[WLAN_HDD_80211_FRM_DA_OFFSET], ETH_ALEN);
Jeff Johnsone7245742012-09-05 17:12:55 -0700678 hddLog(VOS_TRACE_LEVEL_INFO,
Jeff Johnson295189b2012-06-20 16:38:30 -0700679 "%s: Deauth/Disassoc received for STA:"
Arif Hussain24bafea2013-11-15 15:10:03 -0800680 MAC_ADDRESS_STR,
Jeff Johnsone7245742012-09-05 17:12:55 -0700681 __func__,
Arif Hussain24bafea2013-11-15 15:10:03 -0800682 MAC_ADDR_ARRAY(dstMac));
Jeff Johnson295189b2012-06-20 16:38:30 -0700683 goto err_rem_channel;
684 }
685 }
686 }
687
688 if( NULL != cfgState->buf )
Sudhir Sattayappa Kohalli8ee532d2013-02-15 13:16:26 -0800689 {
690 if ( !noack )
691 {
692 hddLog( LOGE, "(%s):Previous P2P Action frame packet pending",
693 __func__);
694 hdd_cleanup_actionframe(pAdapter->pHddCtx, pAdapter);
695 }
696 else
697 {
698 hddLog( LOGE, "(%s):Pending Action frame packet return EBUSY",
699 __func__);
700 return -EBUSY;
701 }
702 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700703
704 hddLog( LOG1, "Action frame tx request");
705
706#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
707 goAdapter = hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_P2P_GO );
708
709 //If GO adapter exists and operating on same frequency
710 //then we will not request remain on channel
711 if( goAdapter && ( ieee80211_frequency_to_channel(chan->center_freq)
712 == goAdapter->sessionCtx.ap.operatingChannel ) )
713 {
714 goto send_frame;
715 }
716#endif
717
718#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
719 if( offchan && wait)
720 {
721 int status;
722
723 // In case of P2P Client mode if we are already
724 // on the same channel then send the frame directly
725
726 if((cfgState->remain_on_chan_ctx != NULL) &&
727 (cfgState->current_freq == chan->center_freq)
728 )
729 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700730 hddLog(LOG1,"action frame: extending the wait time\n");
731 extendedWait = (tANI_U16)wait;
Jeff Johnson295189b2012-06-20 16:38:30 -0700732 goto send_frame;
733 }
Kiet Lam62111f22013-10-08 21:43:54 +0530734 remain_on_channel:
Jeff Johnson295189b2012-06-20 16:38:30 -0700735 INIT_COMPLETION(pAdapter->offchannel_tx_event);
736
737 status = wlan_hdd_request_remain_on_channel(wiphy, dev,
Yue Maf49ba872013-08-19 12:04:25 -0700738 chan,
739#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
740 channel_type,
741#endif
742 wait, cookie,
Jeff Johnson295189b2012-06-20 16:38:30 -0700743 OFF_CHANNEL_ACTION_TX);
744
745 if(0 != status)
746 {
747 if( (-EBUSY == status) &&
748 (cfgState->current_freq == chan->center_freq) )
749 {
750 goto send_frame;
751 }
752 goto err_rem_channel;
753 }
Madan Mohan Koyyalamudi87673f62013-09-27 02:39:27 +0530754 /* This will extend timer in LIM when sending Any action frame
755 * It will cover remain on channel timer till next action frame
756 * in rx direction.
757 */
758 extendedWait = (tANI_U16)wait;
Jeff Johnson295189b2012-06-20 16:38:30 -0700759 /* Wait for driver to be ready on the requested channel */
760 status = wait_for_completion_interruptible_timeout(
761 &pAdapter->offchannel_tx_event,
762 msecs_to_jiffies(WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX));
763 if(!status)
764 {
765 hddLog( LOGE, "Not able to complete remain on channel request"
766 " within timeout period");
767 goto err_rem_channel;
768 }
769 }
770 else if ( offchan )
771 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700772 /* Check before sending action frame
773 whether we already remain on channel */
Jeff Johnson295189b2012-06-20 16:38:30 -0700774 if(NULL == cfgState->remain_on_chan_ctx)
775 {
776 goto err_rem_channel;
777 }
778 }
779 send_frame:
780#endif
781
Jeff Johnsone7245742012-09-05 17:12:55 -0700782 if(!noack)
783 {
784 cfgState->buf = vos_mem_malloc( len ); //buf;
785 if( cfgState->buf == NULL )
786 return -ENOMEM;
Jeff Johnson295189b2012-06-20 16:38:30 -0700787
Jeff Johnsone7245742012-09-05 17:12:55 -0700788 cfgState->len = len;
Jeff Johnson295189b2012-06-20 16:38:30 -0700789
Jeff Johnsone7245742012-09-05 17:12:55 -0700790 vos_mem_copy( cfgState->buf, buf, len);
Jeff Johnson295189b2012-06-20 16:38:30 -0700791
792#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnsone7245742012-09-05 17:12:55 -0700793 if( cfgState->remain_on_chan_ctx )
794 {
795 cfgState->action_cookie = cfgState->remain_on_chan_ctx->cookie;
796 *cookie = cfgState->action_cookie;
797 }
798 else
799 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700800#endif
Jeff Johnsonf67dca92013-11-08 17:07:40 -0800801 *cookie = (uintptr_t) cfgState->buf;
Jeff Johnsone7245742012-09-05 17:12:55 -0700802 cfgState->action_cookie = *cookie;
Kiet Lam62111f22013-10-08 21:43:54 +0530803 /*There is race between expiration of remain on channel
804 in driver and also sending an action frame in wlan_hdd_action.
805 As the remain on chan context is NULL here , which means
806 LIM remain on channel timer expired and
807 wlan_hdd_remain_on_channel_callback has cleared
808 cfgState->remain_on_chan_ctx to NULL so let's
809 do a fresh remain on channel.
810 */
811 goto remain_on_channel;
Jeff Johnson295189b2012-06-20 16:38:30 -0700812#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnsone7245742012-09-05 17:12:55 -0700813 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700814#endif
Jeff Johnsone7245742012-09-05 17:12:55 -0700815 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700816
817 if ( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700818 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
819 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700820 )
821 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700822 tANI_U8 sessionId = pAdapter->sessionId;
Hoonki Lee1090c6a2013-01-16 17:40:54 -0800823
Jeff Johnsone7245742012-09-05 17:12:55 -0700824 if ((type == SIR_MAC_MGMT_FRAME) &&
825 (subType == SIR_MAC_MGMT_ACTION) &&
826 (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
Jeff Johnson295189b2012-06-20 16:38:30 -0700827 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700828 actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
829 hddLog(LOG1, "Tx Action Frame %u \n", actionFrmType);
830 if (actionFrmType == WLAN_HDD_PROV_DIS_REQ)
Jeff Johnson295189b2012-06-20 16:38:30 -0700831 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700832 cfgState->actionFrmState = HDD_PD_REQ_ACK_PENDING;
833 hddLog(LOG1, "%s: HDD_PD_REQ_ACK_PENDING \n", __func__);
834 }
835 else if (actionFrmType == WLAN_HDD_GO_NEG_REQ)
836 {
837 cfgState->actionFrmState = HDD_GO_NEG_REQ_ACK_PENDING;
838 hddLog(LOG1, "%s: HDD_GO_NEG_REQ_ACK_PENDING \n", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700839 }
840 }
Chet Lanctot186b5732013-03-18 10:26:30 -0700841#ifdef WLAN_FEATURE_11W
842 if ((type == SIR_MAC_MGMT_FRAME) &&
843 (subType == SIR_MAC_MGMT_ACTION) &&
844 (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_SA_QUERY_ACTION_FRAME))
845 {
846 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
847 "%s: Calling sme_sendAction. For Category %s", __func__, "SA Query");
848 // Since this is an SA Query Action Frame, we have to protect it
849 WLAN_HDD_SET_WEP_FRM_FC(pTxFrmBuf[1]);
850 }
851#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700852 if (eHAL_STATUS_SUCCESS !=
853 sme_sendAction( WLAN_HDD_GET_HAL_CTX(pAdapter),
Jeff Johnsone7245742012-09-05 17:12:55 -0700854 sessionId, buf, len, extendedWait, noack))
Jeff Johnson295189b2012-06-20 16:38:30 -0700855 {
856 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
857 "%s: sme_sendAction returned fail", __func__);
858 goto err;
859 }
860 }
861 else if( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
862 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
863 )
864 {
Jeff Johnson43971f52012-07-17 12:26:56 -0700865 if( VOS_STATUS_SUCCESS !=
Jeff Johnson295189b2012-06-20 16:38:30 -0700866 WLANSAP_SendAction( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
Jeff Johnsone7245742012-09-05 17:12:55 -0700867 buf, len, 0 ) )
Jeff Johnson295189b2012-06-20 16:38:30 -0700868 {
869 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
870 "%s: WLANSAP_SendAction returned fail", __func__);
871 goto err;
872 }
873 }
874
875 return 0;
876err:
Jeff Johnsone7245742012-09-05 17:12:55 -0700877 if(!noack)
878 {
879 hdd_sendActionCnf( pAdapter, FALSE );
880 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700881 return 0;
882err_rem_channel:
Jeff Johnsonf67dca92013-11-08 17:07:40 -0800883 *cookie = (uintptr_t)cfgState;
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800884 cfg80211_mgmt_tx_status(
885#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
886 pAdapter->dev->ieee80211_ptr,
887#else
888 pAdapter->dev,
889#endif
890 *cookie, buf, len, FALSE, GFP_KERNEL );
Jeff Johnson295189b2012-06-20 16:38:30 -0700891 return 0;
892}
893
894#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800895#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
896int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
897 struct wireless_dev *wdev,
898 u64 cookie)
899{
900 return wlan_hdd_cfg80211_cancel_remain_on_channel( wiphy, wdev, cookie );
901}
902#else
903int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
Jeff Johnson295189b2012-06-20 16:38:30 -0700904 struct net_device *dev,
905 u64 cookie)
906{
907 return wlan_hdd_cfg80211_cancel_remain_on_channel( wiphy, dev, cookie );
908}
909#endif
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800910#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700911
912void hdd_sendActionCnf( hdd_adapter_t *pAdapter, tANI_BOOLEAN actionSendSuccess )
913{
914 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
915
Jeff Johnsone7245742012-09-05 17:12:55 -0700916 cfgState->actionFrmState = HDD_IDLE;
917
Jeff Johnson295189b2012-06-20 16:38:30 -0700918 hddLog( LOG1, "Send Action cnf, actionSendSuccess %d", actionSendSuccess);
919 if( NULL == cfgState->buf )
920 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700921 return;
922 }
923
924 /* If skb is NULL it means this packet was received on CFG80211 interface
925 * else it was received on Monitor interface */
926 if( cfgState->skb == NULL )
927 {
928 /*
929 * buf is the same pointer it passed us to send. Since we are sending
930 * it through control path, we use different buffers.
931 * In case of mac80211, they just push it to the skb and pass the same
932 * data while sending tx ack status.
933 * */
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800934 cfg80211_mgmt_tx_status(
935#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
936 pAdapter->dev->ieee80211_ptr,
937#else
938 pAdapter->dev,
939#endif
940 cfgState->action_cookie,
Jeff Johnson295189b2012-06-20 16:38:30 -0700941 cfgState->buf, cfgState->len, actionSendSuccess, GFP_KERNEL );
942 vos_mem_free( cfgState->buf );
943 cfgState->buf = NULL;
944 }
945 else
946 {
947 hdd_adapter_t* pMonAdapter =
948 hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_MONITOR );
949 if( pMonAdapter == NULL )
950 {
951 hddLog( LOGE, "Not able to get Monitor Adapter");
952 cfgState->skb = NULL;
953 vos_mem_free( cfgState->buf );
954 cfgState->buf = NULL;
955 complete(&pAdapter->tx_action_cnf_event);
956 return;
957 }
958 /* Send TX completion feedback over monitor interface. */
959 hdd_wlan_tx_complete( pMonAdapter, cfgState, actionSendSuccess );
960 cfgState->skb = NULL;
961 vos_mem_free( cfgState->buf );
962 cfgState->buf = NULL;
963 /* Look for the next Mgmt packet to TX */
964 hdd_mon_tx_mgmt_pkt(pAdapter);
965 }
966 complete(&pAdapter->tx_action_cnf_event);
967}
968
969/**
970 * hdd_setP2pNoa
971 *
972 *FUNCTION:
973 * This function is called from hdd_hostapd_ioctl function when Driver
974 * get P2P_SET_NOA comand from wpa_supplicant using private ioctl
975 *
976 *LOGIC:
977 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
978 *
979 *ASSUMPTIONS:
980 *
981 *
982 *NOTE:
983 *
984 * @param dev Pointer to net device structure
985 * @param command Pointer to command
986 *
987 * @return Status
988 */
989
990int hdd_setP2pNoa( struct net_device *dev, tANI_U8 *command )
991{
992 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
993 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
994 VOS_STATUS status = VOS_STATUS_SUCCESS;
995 tP2pPsConfig NoA;
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800996 int count, duration, start_time;
Jeff Johnson295189b2012-06-20 16:38:30 -0700997 char *param;
kalikinkar dhara19d77182013-11-12 14:29:46 -0800998 tANI_U8 ret = 0;
Jeff Johnson295189b2012-06-20 16:38:30 -0700999
Madan Mohan Koyyalamudid8ac8662012-11-06 19:04:56 -08001000 param = strnchr(command, strlen(command), ' ');
Jeff Johnson295189b2012-06-20 16:38:30 -07001001 if (param == NULL)
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08001002 return -EINVAL;
Jeff Johnson295189b2012-06-20 16:38:30 -07001003 param++;
kalikinkar dhara19d77182013-11-12 14:29:46 -08001004 ret = sscanf(param, "%d %d %d", &count, &start_time, &duration);
1005 if (ret < 3)
1006 {
1007 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1008 "%s: P2P_SET GO NoA: fail to read param "
1009 "count=%d duration=%d interval=%d \n",
1010 __func__, count, start_time, duration);
1011 return -EINVAL;
1012 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001013 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
1014 "%s: P2P_SET GO NoA: count=%d duration=%d interval=%d \n",
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -08001015 __func__, count, start_time, duration);
1016 duration = MS_TO_MUS(duration);
Jeff Johnson295189b2012-06-20 16:38:30 -07001017 /* PS Selection
1018 * Periodic NoA (2)
1019 * Single NOA (4)
1020 */
1021 NoA.opp_ps = 0;
1022 NoA.ctWindow = 0;
1023 if (count == 1)
1024 {
1025 NoA.duration = 0;
1026 NoA.single_noa_duration = duration;
1027 NoA.psSelection = P2P_POWER_SAVE_TYPE_SINGLE_NOA;
1028 }
1029 else
1030 {
1031 NoA.duration = duration;
1032 NoA.single_noa_duration = 0;
1033 NoA.psSelection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA;
1034 }
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -08001035 NoA.interval = MS_TO_MUS(100);
Jeff Johnson295189b2012-06-20 16:38:30 -07001036 NoA.count = count;
1037 NoA.sessionid = pAdapter->sessionId;
1038
1039 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
1040 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
1041 "interval %d count %d single noa duration %d "
1042 "PsSelection %x \n", __func__, NoA.opp_ps,
1043 NoA.ctWindow, NoA.duration, NoA.interval,
1044 NoA.count, NoA.single_noa_duration,
1045 NoA.psSelection);
1046
1047 sme_p2pSetPs(hHal, &NoA);
1048 return status;
1049}
1050
1051/**
1052 * hdd_setP2pOpps
1053 *
1054 *FUNCTION:
1055 * This function is called from hdd_hostapd_ioctl function when Driver
1056 * get P2P_SET_PS comand from wpa_supplicant using private ioctl
1057 *
1058 *LOGIC:
1059 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
1060 *
1061 *ASSUMPTIONS:
1062 *
1063 *
1064 *NOTE:
1065 *
1066 * @param dev Pointer to net device structure
1067 * @param command Pointer to command
1068 *
1069 * @return Status
1070 */
1071
1072int hdd_setP2pOpps( struct net_device *dev, tANI_U8 *command )
1073{
1074 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1075 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
1076 VOS_STATUS status = VOS_STATUS_SUCCESS;
1077 tP2pPsConfig NoA;
1078 char *param;
1079 int legacy_ps, opp_ps, ctwindow;
kalikinkar dhara19d77182013-11-12 14:29:46 -08001080 tANI_U8 ret = 0;
Jeff Johnson295189b2012-06-20 16:38:30 -07001081
Madan Mohan Koyyalamudid8ac8662012-11-06 19:04:56 -08001082 param = strnchr(command, strlen(command), ' ');
Jeff Johnson295189b2012-06-20 16:38:30 -07001083 if (param == NULL)
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08001084 return -EINVAL;
Jeff Johnson295189b2012-06-20 16:38:30 -07001085 param++;
kalikinkar dhara19d77182013-11-12 14:29:46 -08001086 ret = sscanf(param, "%d %d %d", &legacy_ps, &opp_ps, &ctwindow);
1087 if (ret < 3)
1088 {
1089 VOS_TRACE (VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1090 "%s: P2P_SET GO PS: fail to read param "
1091 " legacy_ps=%d opp_ps=%d ctwindow=%d \n",
1092 __func__, legacy_ps, opp_ps, ctwindow);
1093 return -EINVAL;
1094 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001095 VOS_TRACE (VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
1096 "%s: P2P_SET GO PS: legacy_ps=%d opp_ps=%d ctwindow=%d \n",
1097 __func__, legacy_ps, opp_ps, ctwindow);
1098
1099 /* PS Selection
1100 * Opportunistic Power Save (1)
1101 */
1102
1103 /* From wpa_cli user need to use separate command to set ctWindow and Opps
1104 * When user want to set ctWindow during that time other parameters
1105 * values are coming from wpa_supplicant as -1.
1106 * Example : User want to set ctWindow with 30 then wpa_cli command :
1107 * P2P_SET ctwindow 30
1108 * Command Received at hdd_hostapd_ioctl is as below:
1109 * P2P_SET_PS -1 -1 30 (legacy_ps = -1, opp_ps = -1, ctwindow = 30)
1110 */
1111 if (ctwindow != -1)
1112 {
1113
1114 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
1115 "Opportunistic Power Save is %s \n",
1116 (TRUE == pAdapter->ops) ? "Enable" : "Disable" );
1117
1118 if (ctwindow != pAdapter->ctw)
1119 {
1120 pAdapter->ctw = ctwindow;
1121
1122 if(pAdapter->ops)
1123 {
1124 NoA.opp_ps = pAdapter->ops;
1125 NoA.ctWindow = pAdapter->ctw;
1126 NoA.duration = 0;
1127 NoA.single_noa_duration = 0;
1128 NoA.interval = 0;
1129 NoA.count = 0;
1130 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
1131 NoA.sessionid = pAdapter->sessionId;
1132
1133 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
1134 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
1135 "interval %d count %d single noa duration %d "
1136 "PsSelection %x \n", __func__, NoA.opp_ps,
1137 NoA.ctWindow, NoA.duration, NoA.interval,
1138 NoA.count, NoA.single_noa_duration,
1139 NoA.psSelection);
1140
1141 sme_p2pSetPs(hHal, &NoA);
1142 }
1143 return 0;
1144 }
1145 }
1146
1147 if (opp_ps != -1)
1148 {
1149 pAdapter->ops = opp_ps;
1150
1151 if ((opp_ps != -1) && (pAdapter->ctw))
1152 {
1153 NoA.opp_ps = opp_ps;
1154 NoA.ctWindow = pAdapter->ctw;
1155 NoA.duration = 0;
1156 NoA.single_noa_duration = 0;
1157 NoA.interval = 0;
1158 NoA.count = 0;
1159 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
1160 NoA.sessionid = pAdapter->sessionId;
1161
1162 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
1163 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
1164 "interval %d count %d single noa duration %d "
1165 "PsSelection %x \n", __func__, NoA.opp_ps,
1166 NoA.ctWindow, NoA.duration, NoA.interval,
1167 NoA.count, NoA.single_noa_duration,
1168 NoA.psSelection);
1169
1170 sme_p2pSetPs(hHal, &NoA);
1171 }
1172 }
1173 return status;
1174}
1175
1176int hdd_setP2pPs( struct net_device *dev, void *msgData )
1177{
1178 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1179 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
1180 VOS_STATUS status = VOS_STATUS_SUCCESS;
1181 tP2pPsConfig NoA;
1182 p2p_app_setP2pPs_t *pappNoA = (p2p_app_setP2pPs_t *) msgData;
1183
1184 NoA.opp_ps = pappNoA->opp_ps;
1185 NoA.ctWindow = pappNoA->ctWindow;
1186 NoA.duration = pappNoA->duration;
1187 NoA.interval = pappNoA->interval;
1188 NoA.count = pappNoA->count;
1189 NoA.single_noa_duration = pappNoA->single_noa_duration;
1190 NoA.psSelection = pappNoA->psSelection;
1191 NoA.sessionid = pAdapter->sessionId;
1192
1193 sme_p2pSetPs(hHal, &NoA);
1194 return status;
1195}
Jeff Johnson295189b2012-06-20 16:38:30 -07001196
1197static tANI_U8 wlan_hdd_get_session_type( enum nl80211_iftype type )
1198{
1199 tANI_U8 sessionType;
1200
1201 switch( type )
1202 {
1203 case NL80211_IFTYPE_AP:
1204 sessionType = WLAN_HDD_SOFTAP;
1205 break;
1206 case NL80211_IFTYPE_P2P_GO:
1207 sessionType = WLAN_HDD_P2P_GO;
1208 break;
1209 case NL80211_IFTYPE_P2P_CLIENT:
1210 sessionType = WLAN_HDD_P2P_CLIENT;
1211 break;
1212 case NL80211_IFTYPE_STATION:
1213 sessionType = WLAN_HDD_INFRA_STATION;
1214 break;
1215 case NL80211_IFTYPE_MONITOR:
1216 sessionType = WLAN_HDD_MONITOR;
1217 break;
1218 default:
1219 sessionType = WLAN_HDD_INFRA_STATION;
1220 break;
1221 }
1222
1223 return sessionType;
1224}
1225
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -08001226#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0))
1227struct wireless_dev* wlan_hdd_add_virtual_intf(
1228 struct wiphy *wiphy, const char *name,
1229 enum nl80211_iftype type,
1230 u32 *flags, struct vif_params *params )
1231#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
1232struct wireless_dev* wlan_hdd_add_virtual_intf(
1233 struct wiphy *wiphy, char *name, enum nl80211_iftype type,
1234 u32 *flags, struct vif_params *params )
1235#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnson295189b2012-06-20 16:38:30 -07001236struct net_device* wlan_hdd_add_virtual_intf(
1237 struct wiphy *wiphy, char *name, enum nl80211_iftype type,
1238 u32 *flags, struct vif_params *params )
1239#else
1240int wlan_hdd_add_virtual_intf( struct wiphy *wiphy, char *name,
1241 enum nl80211_iftype type,
1242 u32 *flags, struct vif_params *params )
1243#endif
1244{
1245 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
1246 hdd_adapter_t* pAdapter = NULL;
1247
1248 ENTER();
1249
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001250 if(hdd_get_adapter(pHddCtx, wlan_hdd_get_session_type(type)) != NULL)
1251 {
Jeff Johnsond13512a2012-07-17 11:42:19 -07001252 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Interface type %d already exists. Two"
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001253 "interfaces of same type are not supported currently.",__func__, type);
Jeff Johnsond13512a2012-07-17 11:42:19 -07001254 return NULL;
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001255 }
1256
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -07001257 if (pHddCtx->isLogpInProgress)
1258 {
1259 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1260 "%s:LOGP in Progress. Ignore!!!", __func__);
1261#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1262 return NULL;
1263#else
1264 return -EAGAIN;
1265#endif
1266 }
Kiet Lam04e26912013-10-18 20:13:38 +05301267 if (pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated &&
1268 ((NL80211_IFTYPE_P2P_GO == type) ||
1269 (NL80211_IFTYPE_P2P_CLIENT == type)))
Jeff Johnson295189b2012-06-20 16:38:30 -07001270 {
Jeff Johnson295189b2012-06-20 16:38:30 -07001271 /* Generate the P2P Interface Address. this address must be
1272 * different from the P2P Device Address.
1273 */
1274 v_MACADDR_t p2pDeviceAddress = pHddCtx->p2pDeviceAddress;
1275 p2pDeviceAddress.bytes[4] ^= 0x80;
1276 pAdapter = hdd_open_adapter( pHddCtx,
1277 wlan_hdd_get_session_type(type),
1278 name, p2pDeviceAddress.bytes,
1279 VOS_TRUE );
Jeff Johnson295189b2012-06-20 16:38:30 -07001280 }
1281 else
1282 {
1283 pAdapter = hdd_open_adapter( pHddCtx, wlan_hdd_get_session_type(type),
1284 name, wlan_hdd_get_intf_addr(pHddCtx), VOS_TRUE );
1285 }
1286
1287 if( NULL == pAdapter)
1288 {
1289 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: hdd_open_adapter failed",__func__);
1290#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1291 return NULL;
1292#else
1293 return -EINVAL;
1294#endif
1295 }
1296 EXIT();
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -08001297#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
1298 return pAdapter->dev->ieee80211_ptr;
1299#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnson295189b2012-06-20 16:38:30 -07001300 return pAdapter->dev;
1301#else
1302 return 0;
1303#endif
1304}
1305
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -08001306#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
1307int wlan_hdd_del_virtual_intf( struct wiphy *wiphy, struct wireless_dev *wdev )
1308#else
Jeff Johnson295189b2012-06-20 16:38:30 -07001309int wlan_hdd_del_virtual_intf( struct wiphy *wiphy, struct net_device *dev )
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -08001310#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001311{
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -08001312#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
1313 struct net_device *dev = wdev->netdev;
1314#endif
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +05301315 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
1316 hdd_adapter_t *pVirtAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1317 int status;
1318 ENTER();
Jeff Johnson295189b2012-06-20 16:38:30 -07001319
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +05301320 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
1321 __func__,pVirtAdapter->device_mode);
Jeff Johnson295189b2012-06-20 16:38:30 -07001322
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +05301323 status = wlan_hdd_validate_context(pHddCtx);
1324
1325 if (0 != status)
1326 {
1327 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1328 "%s: HDD context is not valid", __func__);
1329 return status;
1330 }
1331
1332 wlan_hdd_release_intf_addr( pHddCtx,
Jeff Johnson295189b2012-06-20 16:38:30 -07001333 pVirtAdapter->macAddressCurrent.bytes );
1334
Gopichand Nakkalaf502e2b2013-05-24 18:34:25 +05301335 hdd_stop_adapter( pHddCtx, pVirtAdapter );
1336 hdd_close_adapter( pHddCtx, pVirtAdapter, TRUE );
1337 EXIT();
1338 return 0;
Jeff Johnson295189b2012-06-20 16:38:30 -07001339}
1340
1341void hdd_sendMgmtFrameOverMonitorIface( hdd_adapter_t *pMonAdapter,
Jeff Johnsonc9ca3732013-03-27 11:31:03 -07001342 tANI_U32 nFrameLength,
1343 tANI_U8* pbFrames,
Jeff Johnson295189b2012-06-20 16:38:30 -07001344 tANI_U8 frameType )
1345{
1346 //Indicate a Frame over Monitor Intf.
1347 int rxstat;
1348 struct sk_buff *skb = NULL;
1349 int needed_headroom = 0;
1350 int flag = HDD_RX_FLAG_IV_STRIPPED | HDD_RX_FLAG_DECRYPTED |
1351 HDD_RX_FLAG_MMIC_STRIPPED;
Sameer Thalappil50dc0092013-02-19 17:23:33 -08001352#ifdef WLAN_OPEN_SOURCE
Jeff Johnsone7245742012-09-05 17:12:55 -07001353#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1354 hdd_context_t* pHddCtx = (hdd_context_t*)(pMonAdapter->pHddCtx);
1355#endif
Sameer Thalappil50dc0092013-02-19 17:23:33 -08001356#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001357 hddLog( LOG1, FL("Indicate Frame over Monitor Intf"));
1358
Jeff Johnsonc9ca3732013-03-27 11:31:03 -07001359 if (NULL == pbFrames)
1360 {
1361 hddLog(LOGE, FL("NULL frame pointer"));
1362 return;
1363 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001364
1365 /* room for the radiotap header based on driver features
1366 * 1 Byte for RADIO TAP Flag, 1 Byte padding and 2 Byte for
1367 * RX flags.
1368 * */
1369 needed_headroom = sizeof(struct ieee80211_radiotap_header) + 4;
1370
1371 //alloc skb here
1372 skb = alloc_skb(VPKT_SIZE_BUFFER, GFP_ATOMIC);
1373 if (unlikely(NULL == skb))
1374 {
1375 hddLog( LOGW, FL("Unable to allocate skb"));
1376 return;
1377 }
1378 skb_reserve(skb, VPKT_SIZE_BUFFER);
1379 if (unlikely(skb_headroom(skb) < nFrameLength))
1380 {
1381 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
1382 "HDD [%d]: Insufficient headroom, "
1383 "head[%p], data[%p], req[%d]",
1384 __LINE__, skb->head, skb->data, nFrameLength);
1385 kfree_skb(skb);
1386 return ;
1387 }
1388 // actually push the data
1389 memcpy(skb_push(skb, nFrameLength), pbFrames, nFrameLength);
1390 /* prepend radiotap information */
1391 if( 0 != hdd_wlan_add_rx_radiotap_hdr( skb, needed_headroom, flag ) )
1392 {
1393 hddLog( LOGE, FL("Not Able Add Radio Tap"));
1394 //free skb
1395 kfree_skb(skb);
1396 return ;
1397 }
1398
1399 skb_reset_mac_header( skb );
1400 skb->dev = pMonAdapter->dev;
1401 skb->protocol = eth_type_trans( skb, skb->dev );
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001402 skb->ip_summed = CHECKSUM_NONE;
Sameer Thalappil50dc0092013-02-19 17:23:33 -08001403#ifdef WLAN_OPEN_SOURCE
Jeff Johnsone7245742012-09-05 17:12:55 -07001404#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
Amar Singhal6144c002013-05-03 16:11:42 -07001405 wake_lock_timeout(&pHddCtx->rx_wake_lock, msecs_to_jiffies(HDD_WAKE_LOCK_DURATION));
Jeff Johnsone7245742012-09-05 17:12:55 -07001406#endif
Sameer Thalappil50dc0092013-02-19 17:23:33 -08001407#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001408 rxstat = netif_rx_ni(skb);
1409 if( NET_RX_SUCCESS == rxstat )
1410 {
1411 hddLog( LOG1, FL("Success"));
1412 }
1413 else
1414 hddLog( LOGE, FL("Failed %d"), rxstat);
1415
1416 return ;
1417}
1418
1419void hdd_indicateMgmtFrame( hdd_adapter_t *pAdapter,
1420 tANI_U32 nFrameLength,
1421 tANI_U8* pbFrames,
1422 tANI_U8 frameType,
Chilam NG571c65a2013-01-19 12:27:36 +05301423 tANI_U32 rxChan,
1424 tANI_S8 rxRssi )
Jeff Johnson295189b2012-06-20 16:38:30 -07001425{
1426 tANI_U16 freq;
Jeff Johnsone7245742012-09-05 17:12:55 -07001427 tANI_U8 type = 0;
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001428 tANI_U8 subType = 0;
Jeff Johnsone7245742012-09-05 17:12:55 -07001429 tActionFrmType actionFrmType;
1430 hdd_cfg80211_state_t *cfgState = NULL;
Jeff Johnson295189b2012-06-20 16:38:30 -07001431
1432 hddLog(VOS_TRACE_LEVEL_INFO, "%s: Frame Type = %d Frame Length = %d\n",
1433 __func__, frameType, nFrameLength);
1434
1435 if (NULL == pAdapter)
1436 {
Jeff Johnsonc9ca3732013-03-27 11:31:03 -07001437 hddLog(LOGE, FL("pAdapter is NULL"));
1438 return;
1439 }
1440
1441 if (0 == nFrameLength)
1442 {
1443 hddLog(LOGE, FL("Frame Length is Invalid ZERO"));
1444 return;
1445 }
1446
1447 if (NULL == pbFrames)
1448 {
1449 hddLog(LOGE, FL("pbFrames is NULL"));
Jeff Johnson295189b2012-06-20 16:38:30 -07001450 return;
1451 }
1452
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001453 type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]);
1454 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]);
1455
1456 /* Get pAdapter from Destination mac address of the frame */
1457 if ((type == SIR_MAC_MGMT_FRAME) &&
1458 (subType != SIR_MAC_MGMT_PROBE_REQ))
1459 {
1460 pAdapter = hdd_get_adapter_by_macaddr( WLAN_HDD_GET_CTX(pAdapter),
1461 &pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET]);
1462 if (NULL == pAdapter)
1463 {
1464 /* Under assumtion that we don't receive any action frame
1465 * with BCST as destination we dropping action frame
1466 */
Madan Mohan Koyyalamudi051ff0b2012-12-03 16:55:26 -08001467 hddLog(VOS_TRACE_LEVEL_FATAL,"pAdapter for action frame is NULL Macaddr = "
1468 MAC_ADDRESS_STR ,
1469 MAC_ADDR_ARRAY(&pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET]));
1470 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Frame Type = %d Frame Length = %d"
1471 " subType = %d \n",__func__,frameType,nFrameLength,subType);
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001472 return;
1473 }
1474 }
1475
Jeff Johnsonc9ca3732013-03-27 11:31:03 -07001476
Jeff Johnson295189b2012-06-20 16:38:30 -07001477 if (NULL == pAdapter->dev)
1478 {
1479 hddLog( LOGE, FL("pAdapter->dev is NULL"));
1480 return;
1481 }
1482
1483 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
1484 {
1485 hddLog( LOGE, FL("pAdapter has invalid magic"));
1486 return;
1487 }
1488
Jeff Johnsonc9ca3732013-03-27 11:31:03 -07001489 if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) ||
1490 (WLAN_HDD_P2P_GO == pAdapter->device_mode ))
Jeff Johnson295189b2012-06-20 16:38:30 -07001491 {
1492 hdd_adapter_t *pMonAdapter =
1493 hdd_get_mon_adapter( WLAN_HDD_GET_CTX(pAdapter) );
1494
Jeff Johnsonc9ca3732013-03-27 11:31:03 -07001495 if (NULL != pMonAdapter)
Jeff Johnson295189b2012-06-20 16:38:30 -07001496 {
1497 hddLog( LOG1, FL("Indicate Frame over Monitor Interface"));
1498 hdd_sendMgmtFrameOverMonitorIface( pMonAdapter, nFrameLength,
1499 pbFrames, frameType);
1500 return;
1501 }
1502 }
1503
1504 //Channel indicated may be wrong. TODO
1505 //Indicate an action frame.
1506 if( rxChan <= MAX_NO_OF_2_4_CHANNELS )
1507 {
1508 freq = ieee80211_channel_to_frequency( rxChan,
1509 IEEE80211_BAND_2GHZ);
1510 }
1511 else
1512 {
1513 freq = ieee80211_channel_to_frequency( rxChan,
1514 IEEE80211_BAND_5GHZ);
1515 }
1516
Jeff Johnsone7245742012-09-05 17:12:55 -07001517 cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
1518
1519 if ((type == SIR_MAC_MGMT_FRAME) &&
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001520 (subType == SIR_MAC_MGMT_ACTION))
Jeff Johnsone7245742012-09-05 17:12:55 -07001521 {
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001522 if(pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME)
1523 {
1524 // public action frame
1525 if((pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+1] == SIR_MAC_ACTION_VENDOR_SPECIFIC) &&
Sudhir Sattayappa Kohallic8239802013-02-22 18:46:44 -08001526 vos_mem_compare(&pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+2], SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE))
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001527 // P2P action frames
1528 {
1529 actionFrmType = pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
1530 hddLog(LOG1, "Rx Action Frame %u \n", actionFrmType);
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -07001531#ifdef WLAN_FEATURE_P2P_DEBUG
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001532 if(actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE)
1533 {
1534 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] unknown[%d] <--- OTA",
1535 actionFrmType);
1536 }
1537 else
1538 {
1539 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] %s <--- OTA",
1540 p2p_action_frame_type[actionFrmType]);
1541 if( (actionFrmType == WLAN_HDD_PROV_DIS_REQ) &&
1542 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
1543 {
1544 globalP2PConnectionStatus = P2P_GO_NEG_PROCESS;
1545 hddLog(LOGE,"[P2P State]Inactive state to "
Jeff Johnson1250df42012-12-10 14:31:52 -08001546 "GO negotiation progress state");
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001547 }
1548 else if( (actionFrmType == WLAN_HDD_GO_NEG_CNF) &&
1549 (globalP2PConnectionStatus == P2P_GO_NEG_PROCESS) )
1550 {
1551 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
Jeff Johnson1250df42012-12-10 14:31:52 -08001552 hddLog(LOGE,"[P2P State]GO negotiation progress to "
1553 "GO negotiation completed state");
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001554 }
1555 else if( (actionFrmType == WLAN_HDD_INVITATION_REQ) &&
1556 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
1557 {
1558 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
1559 hddLog(LOGE,"[P2P State]Inactive state to GO negotiation"
1560 " completed state Autonomous GO formation");
1561 }
1562 }
1563#endif
1564
1565 if (((actionFrmType == WLAN_HDD_PROV_DIS_RESP) &&
1566 (cfgState->actionFrmState == HDD_PD_REQ_ACK_PENDING)) ||
1567 ((actionFrmType == WLAN_HDD_GO_NEG_RESP) &&
1568 (cfgState->actionFrmState == HDD_GO_NEG_REQ_ACK_PENDING)))
1569 {
1570 hddLog(LOG1, "%s: ACK_PENDING and But received RESP for Action frame ",
1571 __func__);
1572 hdd_sendActionCnf(pAdapter, TRUE);
1573 }
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -07001574 }
Gopichand Nakkalab977a972013-02-18 19:15:09 -08001575#ifdef FEATURE_WLAN_TDLS
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001576 else if(pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+1] == WLAN_HDD_PUBLIC_ACTION_TDLS_DISC_RESP)
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -07001577 {
Shailender Karmuchi13c0d082013-03-26 14:41:39 -07001578 u8 *mac = &pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET+6];
1579#ifdef WLAN_FEATURE_TDLS_DEBUG
1580 hddLog(VOS_TRACE_LEVEL_ERROR,"[TDLS] TDLS Discovery Response," MAC_ADDRESS_STR " RSSI[%d] <--- OTA",
1581 MAC_ADDR_ARRAY(mac),rxRssi);
1582#endif
1583 wlan_hdd_tdls_set_rssi(pAdapter, mac, rxRssi);
1584 wlan_hdd_tdls_recv_discovery_resp(pAdapter, mac);
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001585 }
1586#endif
1587 }
Shailender Karmuchi13c0d082013-03-26 14:41:39 -07001588#ifdef WLAN_FEATURE_TDLS_DEBUG
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001589 if(pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_TDLS_ACTION_FRAME)
1590 {
1591 actionFrmType = pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+1];
1592 if(actionFrmType >= MAX_TDLS_ACTION_FRAME_TYPE)
1593 {
1594 hddLog(VOS_TRACE_LEVEL_ERROR,"[TDLS] unknown[%d] <--- OTA",
1595 actionFrmType);
1596 }
1597 else
1598 {
1599 hddLog(VOS_TRACE_LEVEL_ERROR,"[TDLS] %s <--- OTA",
1600 tdls_action_frame_type[actionFrmType]);
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -07001601 }
1602 }
1603#endif
Jeff Johnsone7245742012-09-05 17:12:55 -07001604 }
1605
Jeff Johnson295189b2012-06-20 16:38:30 -07001606 //Indicate Frame Over Normal Interface
1607 hddLog( LOG1, FL("Indicate Frame over NL80211 Interface"));
1608
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -08001609#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
1610 cfg80211_rx_mgmt( pAdapter->dev->ieee80211_ptr, freq, 0,
1611 pbFrames, nFrameLength,
1612 GFP_ATOMIC );
1613#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0))
Jeff Johnson295189b2012-06-20 16:38:30 -07001614 cfg80211_rx_mgmt( pAdapter->dev, freq, 0,
1615 pbFrames, nFrameLength,
1616 GFP_ATOMIC );
1617#else
1618 cfg80211_rx_mgmt( pAdapter->dev, freq,
1619 pbFrames, nFrameLength,
1620 GFP_ATOMIC );
1621#endif //LINUX_VERSION_CODE
1622}
1623
1624/*
1625 * ieee80211_add_rx_radiotap_header - add radiotap header
1626 */
1627static int hdd_wlan_add_rx_radiotap_hdr (
1628 struct sk_buff *skb, int rtap_len, int flag )
1629{
1630 u8 rtap_temp[20] = {0};
1631 struct ieee80211_radiotap_header *rthdr;
1632 unsigned char *pos;
1633 u16 rx_flags = 0;
1634
1635 rthdr = (struct ieee80211_radiotap_header *)(&rtap_temp[0]);
1636
1637 /* radiotap header, set always present flags */
1638 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
1639 (1 << IEEE80211_RADIOTAP_RX_FLAGS));
1640 rthdr->it_len = cpu_to_le16(rtap_len);
1641
1642 pos = (unsigned char *) (rthdr + 1);
1643
1644 /* the order of the following fields is important */
1645
1646 /* IEEE80211_RADIOTAP_FLAGS */
1647 *pos = 0;
1648 pos++;
1649
1650 /* IEEE80211_RADIOTAP_RX_FLAGS: Length 2 Bytes */
1651 /* ensure 2 byte alignment for the 2 byte field as required */
1652 if ((pos - (u8 *)rthdr) & 1)
1653 pos++;
1654 put_unaligned_le16(rx_flags, pos);
1655 pos += 2;
1656
1657 // actually push the data
1658 memcpy(skb_push(skb, rtap_len), &rtap_temp[0], rtap_len);
1659
1660 return 0;
1661}
1662
1663static void hdd_wlan_tx_complete( hdd_adapter_t* pAdapter,
1664 hdd_cfg80211_state_t* cfgState,
1665 tANI_BOOLEAN actionSendSuccess )
1666{
1667 struct ieee80211_radiotap_header *rthdr;
1668 unsigned char *pos;
1669 struct sk_buff *skb = cfgState->skb;
Sameer Thalappil50dc0092013-02-19 17:23:33 -08001670#ifdef WLAN_OPEN_SOURCE
Jeff Johnsone7245742012-09-05 17:12:55 -07001671#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1672 hdd_context_t *pHddCtx = (hdd_context_t*)(pAdapter->pHddCtx);
1673#endif
Sameer Thalappil50dc0092013-02-19 17:23:33 -08001674#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001675
1676 /* 2 Byte for TX flags and 1 Byte for Retry count */
1677 u32 rtHdrLen = sizeof(*rthdr) + 3;
1678
1679 u8 *data;
1680
1681 /* We have to return skb with Data starting with MAC header. We have
1682 * copied SKB data starting with MAC header to cfgState->buf. We will pull
1683 * entire skb->len from skb and then we will push cfgState->buf to skb
1684 * */
1685 if( NULL == skb_pull(skb, skb->len) )
1686 {
1687 hddLog( LOGE, FL("Not Able to Pull %d byte from skb"), skb->len);
1688 kfree_skb(cfgState->skb);
1689 return;
1690 }
1691
1692 data = skb_push( skb, cfgState->len );
1693
1694 if (data == NULL)
1695 {
Jeff Johnson59a121e2013-11-30 09:46:08 -08001696 hddLog( LOGE, FL("Not Able to Push %zu byte to skb"), cfgState->len);
Jeff Johnson295189b2012-06-20 16:38:30 -07001697 kfree_skb( cfgState->skb );
1698 return;
1699 }
1700
1701 memcpy( data, cfgState->buf, cfgState->len );
1702
1703 /* send frame to monitor interfaces now */
1704 if( skb_headroom(skb) < rtHdrLen )
1705 {
1706 hddLog( LOGE, FL("No headroom for rtap header"));
1707 kfree_skb(cfgState->skb);
1708 return;
1709 }
1710
1711 rthdr = (struct ieee80211_radiotap_header*) skb_push( skb, rtHdrLen );
1712
1713 memset( rthdr, 0, rtHdrLen );
1714 rthdr->it_len = cpu_to_le16( rtHdrLen );
1715 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
1716 (1 << IEEE80211_RADIOTAP_DATA_RETRIES)
1717 );
1718
1719 pos = (unsigned char *)( rthdr+1 );
1720
1721 // Fill TX flags
1722 *pos = actionSendSuccess;
1723 pos += 2;
1724
1725 // Fill retry count
1726 *pos = 0;
1727 pos++;
1728
1729 skb_set_mac_header( skb, 0 );
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001730 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnson295189b2012-06-20 16:38:30 -07001731 skb->pkt_type = PACKET_OTHERHOST;
1732 skb->protocol = htons(ETH_P_802_2);
1733 memset( skb->cb, 0, sizeof( skb->cb ) );
Sameer Thalappil50dc0092013-02-19 17:23:33 -08001734#ifdef WLAN_OPEN_SOURCE
Jeff Johnsone7245742012-09-05 17:12:55 -07001735#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
Amar Singhal6144c002013-05-03 16:11:42 -07001736 wake_lock_timeout(&pHddCtx->rx_wake_lock, msecs_to_jiffies(HDD_WAKE_LOCK_DURATION));
Jeff Johnsone7245742012-09-05 17:12:55 -07001737#endif
Sameer Thalappil50dc0092013-02-19 17:23:33 -08001738#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001739 if (in_interrupt())
1740 netif_rx( skb );
1741 else
1742 netif_rx_ni( skb );
1743
1744 /* Enable Queues which we have disabled earlier */
Gopichand Nakkala8c0386c2013-07-09 23:31:37 +05301745 netif_tx_start_all_queues( pAdapter->dev );
Jeff Johnson295189b2012-06-20 16:38:30 -07001746
1747}
Gopichand Nakkala8c0386c2013-07-09 23:31:37 +05301748