blob: a0a8bb8a6356f469c2b6a6df412bf482c75d4c41 [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 ========================================================================*/
53#ifdef CONFIG_CFG80211
54
55#include <wlan_hdd_includes.h>
56#include <wlan_hdd_hostapd.h>
57#include <net/cfg80211.h>
58#include "sme_Api.h"
59#include "wlan_hdd_p2p.h"
60#include "sapApi.h"
61
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
122#ifdef WLAN_FEATURE_P2P
123eHalStatus wlan_hdd_remain_on_channel_callback( tHalHandle hHal, void* pCtx,
124 eHalStatus status )
125{
126 hdd_adapter_t *pAdapter = (hdd_adapter_t*) pCtx;
Jeff Johnson295189b2012-06-20 16:38:30 -0700127 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
128 hdd_remain_on_chan_ctx_t *pRemainChanCtx = cfgState->remain_on_chan_ctx;
129
130 if( pRemainChanCtx == NULL )
131 {
132 hddLog( LOGW,
133 "%s: No Rem on channel pending for which Rsp is received", __func__);
134 return eHAL_STATUS_SUCCESS;
135 }
136
137 hddLog( LOG1, "Received remain on channel rsp");
138
139 cfgState->remain_on_chan_ctx = NULL;
140
141 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
142 {
143 if( cfgState->buf )
144 {
145 hddLog( LOGP,
146 "%s: We need to receive yet an ack from one of tx packet",
147 __func__);
148 }
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800149 cfg80211_remain_on_channel_expired(
150#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
151 pRemainChanCtx->dev->ieee80211_ptr,
152#else
153 pRemainChanCtx->dev,
154#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700155 pRemainChanCtx->cookie,
156 &pRemainChanCtx->chan,
157 pRemainChanCtx->chan_type, GFP_KERNEL );
158 }
159
Jeff Johnson295189b2012-06-20 16:38:30 -0700160
161 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700162 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
163 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700164 )
165 {
166 tANI_U8 sessionId = pAdapter->sessionId;
Madan Mohan Koyyalamudi35885912012-11-30 15:05:42 -0800167 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
168 {
169 sme_DeregisterMgmtFrame(
170 hHal, sessionId,
171 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
172 NULL, 0 );
173 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700174 }
175 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
176 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
177 )
178 {
179 WLANSAP_DeRegisterMgmtFrame(
180 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
181 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
182 NULL, 0 );
183 }
184
Madan Mohan Koyyalamudi35885912012-11-30 15:05:42 -0800185 vos_mem_free( pRemainChanCtx );
Jeff Johnson295189b2012-06-20 16:38:30 -0700186 complete(&pAdapter->cancel_rem_on_chan_var);
187 return eHAL_STATUS_SUCCESS;
188}
189
Gopichand Nakkalaf527dc62012-12-31 16:35:10 -0800190void wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter)
Jeff Johnson295189b2012-06-20 16:38:30 -0700191{
Jeff Johnson295189b2012-06-20 16:38:30 -0700192 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
193 int status = 0;
Jeff Johnson295189b2012-06-20 16:38:30 -0700194
Jeff Johnson32d95a32012-09-10 13:15:23 -0700195 if(cfgState->remain_on_chan_ctx != NULL)
Jeff Johnson295189b2012-06-20 16:38:30 -0700196 {
Jeff Johnson32d95a32012-09-10 13:15:23 -0700197 hddLog( LOG1, "Cancel Existing Remain on Channel");
198
199 /* Wait till remain on channel ready indication before issuing cancel
200 * remain on channel request, otherwise if remain on channel not
201 * received and if the driver issues cancel remain on channel then lim
Jeff Johnson295189b2012-06-20 16:38:30 -0700202 * will be in unknown state.
203 */
204 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
205 msecs_to_jiffies(WAIT_REM_CHAN_READY));
206 if (!status)
207 {
208 hddLog( LOGE,
209 "%s: timeout waiting for remain on channel ready indication",
210 __func__);
211 }
212
213 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
Jeff Johnson32d95a32012-09-10 13:15:23 -0700214
Jeff Johnson295189b2012-06-20 16:38:30 -0700215 /* Issue abort remain on chan request to sme.
216 * The remain on channel callback will make sure the remain_on_chan
217 * expired event is sent.
218 */
219 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700220 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
221 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700222 )
223 {
224 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
225 pAdapter->sessionId );
226 }
227 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
228 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
229 )
230 {
231 WLANSAP_CancelRemainOnChannel(
232 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
233 }
Jeff Johnsone7245742012-09-05 17:12:55 -0700234
Jeff Johnson32d95a32012-09-10 13:15:23 -0700235 status = wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
Jeff Johnson295189b2012-06-20 16:38:30 -0700236 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
Jeff Johnson32d95a32012-09-10 13:15:23 -0700237
238 if (!status)
239 {
240 hddLog( LOGE,
241 "%s: timeout waiting for cancel remain on channel ready indication",
242 __func__);
243 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700244 }
Jeff Johnson32d95a32012-09-10 13:15:23 -0700245}
246
247int wlan_hdd_check_remain_on_channel(hdd_adapter_t *pAdapter)
248{
249 int status = 0;
250 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
251
252 if(WLAN_HDD_P2P_GO != pAdapter->device_mode)
253 {
254 //Cancel Existing Remain On Channel
255 //If no action frame is pending
256 if( cfgState->remain_on_chan_ctx != NULL)
257 {
258 //Check whether Action Frame is pending or not
259 if( cfgState->buf == NULL)
260 {
261 wlan_hdd_cancel_existing_remain_on_channel(pAdapter);
262 }
263 else
264 {
265 hddLog( LOG1, "Cannot Cancel Existing Remain on Channel");
266 status = -EBUSY;
267 }
268 }
269 }
270 return status;
271}
272
273static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy,
274 struct net_device *dev,
275 struct ieee80211_channel *chan,
276 enum nl80211_channel_type channel_type,
277 unsigned int duration, u64 *cookie,
278 rem_on_channel_request_type_t request_type )
279{
280 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
281 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
282 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
283 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
284 __func__,pAdapter->device_mode);
285
286 hddLog( LOG1,
287 "chan(hw_val)0x%x chan(centerfreq) %d chan type 0x%x, duration %d",
288 chan->hw_value, chan->center_freq, channel_type, duration );
289
290 //Cancel existing remain On Channel if any
291 wlan_hdd_cancel_existing_remain_on_channel(pAdapter);
Jeff Johnson295189b2012-06-20 16:38:30 -0700292
Jeff Johnsone7245742012-09-05 17:12:55 -0700293 /* When P2P-GO and if we are trying to unload the driver then
Jeff Johnson295189b2012-06-20 16:38:30 -0700294 * wlan driver is keep on receiving the remain on channel command
Jeff Johnsone7245742012-09-05 17:12:55 -0700295 * and which is resulting in crash. So not allowing any remain on
Jeff Johnson295189b2012-06-20 16:38:30 -0700296 * channel requets when Load/Unload is in progress*/
297 if (((hdd_context_t*)pAdapter->pHddCtx)->isLoadUnloadInProgress)
298 {
299 hddLog( LOGE,
300 "%s: Wlan Load/Unload is in progress", __func__);
301 return -EBUSY;
302 }
303
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700304 if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress)
305 {
306 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
307 "%s:LOGP in Progress. Ignore!!!", __func__);
308 return -EAGAIN;
309 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700310 pRemainChanCtx = vos_mem_malloc( sizeof(hdd_remain_on_chan_ctx_t) );
311 if( NULL == pRemainChanCtx )
312 {
313 hddLog(VOS_TRACE_LEVEL_FATAL,
314 "%s: Not able to allocate memory for Channel context",
315 __func__);
316 return -ENOMEM;
317 }
318
319 vos_mem_copy( &pRemainChanCtx->chan, chan,
320 sizeof(struct ieee80211_channel) );
321
322 pRemainChanCtx->chan_type = channel_type;
323 pRemainChanCtx->duration = duration;
324 pRemainChanCtx->dev = dev;
325 *cookie = (tANI_U32) pRemainChanCtx;
326 pRemainChanCtx->cookie = *cookie;
327 pRemainChanCtx->rem_on_chan_request = request_type;
328 cfgState->remain_on_chan_ctx = pRemainChanCtx;
329 cfgState->current_freq = chan->center_freq;
330
331 INIT_COMPLETION(pAdapter->rem_on_chan_ready_event);
332
333 //call sme API to start remain on channel.
334 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700335 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
336 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700337 )
338 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700339 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700340 //call sme API to start remain on channel.
341 sme_RemainOnChannel(
342 WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId,
343 chan->hw_value, duration,
344 wlan_hdd_remain_on_channel_callback, pAdapter );
345
Madan Mohan Koyyalamudi35885912012-11-30 15:05:42 -0800346 if( REMAIN_ON_CHANNEL_REQUEST == request_type)
347 {
348 sme_RegisterMgmtFrame(WLAN_HDD_GET_HAL_CTX(pAdapter),
349 sessionId, (SIR_MAC_MGMT_FRAME << 2) |
350 (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0 );
351 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700352
353 }
354 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
355 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
356 )
357 {
358 //call sme API to start remain on channel.
Jeff Johnson43971f52012-07-17 12:26:56 -0700359 if (VOS_STATUS_SUCCESS != WLANSAP_RemainOnChannel(
Jeff Johnson295189b2012-06-20 16:38:30 -0700360 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
361 chan->hw_value, duration,
362 wlan_hdd_remain_on_channel_callback, pAdapter ))
363
364 {
365 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
366 "%s: WLANSAP_RemainOnChannel returned fail", __func__);
367 cfgState->remain_on_chan_ctx = NULL;
Jeff Johnsone7245742012-09-05 17:12:55 -0700368 vos_mem_free (pRemainChanCtx);
Jeff Johnson295189b2012-06-20 16:38:30 -0700369 return -EINVAL;
370 }
371
372
Jeff Johnson43971f52012-07-17 12:26:56 -0700373 if (VOS_STATUS_SUCCESS != WLANSAP_RegisterMgmtFrame(
Jeff Johnson295189b2012-06-20 16:38:30 -0700374 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
375 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
376 NULL, 0 ))
377 {
378 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
379 "%s: WLANSAP_RegisterMgmtFrame returned fail", __func__);
380 WLANSAP_CancelRemainOnChannel(
381 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
382 return -EINVAL;
383 }
384
385 }
386 return 0;
387
388}
389
390int wlan_hdd_cfg80211_remain_on_channel( struct wiphy *wiphy,
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800391#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
392 struct wireless_dev *wdev,
393#else
Jeff Johnson295189b2012-06-20 16:38:30 -0700394 struct net_device *dev,
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800395#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700396 struct ieee80211_channel *chan,
397 enum nl80211_channel_type channel_type,
398 unsigned int duration, u64 *cookie )
399{
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800400#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
401 struct net_device *dev = wdev->netdev;
402#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700403 return wlan_hdd_request_remain_on_channel(wiphy, dev,
404 chan, channel_type, duration, cookie,
405 REMAIN_ON_CHANNEL_REQUEST);
406}
407
408void hdd_remainChanReadyHandler( hdd_adapter_t *pAdapter )
409{
410 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
411 hdd_remain_on_chan_ctx_t* pRemainChanCtx = cfgState->remain_on_chan_ctx;
412
413 hddLog( LOG1, "Ready on chan ind");
414
415 if( pRemainChanCtx != NULL )
416 {
417 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
418 {
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800419 cfg80211_ready_on_channel(
420#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
421 pAdapter->dev->ieee80211_ptr,
422#else
423 pAdapter->dev,
424#endif
425 (tANI_U32)pRemainChanCtx,
Jeff Johnson295189b2012-06-20 16:38:30 -0700426 &pRemainChanCtx->chan, pRemainChanCtx->chan_type,
427 pRemainChanCtx->duration, GFP_KERNEL );
428 }
429#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
430 else if( OFF_CHANNEL_ACTION_TX == pRemainChanCtx->rem_on_chan_request )
431 {
432 complete(&pAdapter->offchannel_tx_event);
433 }
434#endif
435 complete(&pAdapter->rem_on_chan_ready_event);
436 }
437 else
438 {
439 hddLog( LOGW, "%s: No Pending Remain on channel Request", __func__);
440 }
441 return;
442}
443
444int wlan_hdd_cfg80211_cancel_remain_on_channel( struct wiphy *wiphy,
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800445#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
446 struct wireless_dev *wdev,
447#else
448 struct net_device *dev,
449#endif
450 u64 cookie )
Jeff Johnson295189b2012-06-20 16:38:30 -0700451{
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800452#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
453 struct net_device *dev = wdev->netdev;
454#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700455 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson295189b2012-06-20 16:38:30 -0700456 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
457 int status = 0;
458
459 hddLog( LOG1, "Cancel remain on channel req");
460
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700461 if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress)
462 {
463 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
464 "%s:LOGP in Progress. Ignore!!!", __func__);
465 return -EAGAIN;
466 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700467 /* FIXME cancel currently running remain on chan.
468 * Need to check cookie and cancel accordingly
469 */
470 if( (cfgState->remain_on_chan_ctx == NULL) ||
471 (cfgState->remain_on_chan_ctx->cookie != cookie) )
472 {
473 hddLog( LOGE,
474 "%s: No Remain on channel pending with specified cookie value",
475 __func__);
476 return -EINVAL;
477 }
478
479 /* wait until remain on channel ready event received
480 * for already issued remain on channel request */
481 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
482 msecs_to_jiffies(WAIT_REM_CHAN_READY));
483 if (!status)
484 {
485 hddLog( LOGE,
486 "%s: timeout waiting for remain on channel ready indication",
487 __func__);
488 }
489 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
490 /* Issue abort remain on chan request to sme.
491 * The remain on channel callback will make sure the remain_on_chan
492 * expired event is sent.
493 */
494 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700495 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
496 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700497 )
498 {
499 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700500 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
501 sessionId );
502 }
503 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
504 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
505 )
506 {
507 WLANSAP_CancelRemainOnChannel(
508 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
509 }
510 else
511 {
512 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Invalid device_mode = %d",
513 __func__, pAdapter->device_mode);
514 return -EIO;
515 }
516 wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
517 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
518 return 0;
519}
520
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800521#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
522int wlan_hdd_action( struct wiphy *wiphy, struct wireless_dev *wdev,
523 struct ieee80211_channel *chan, bool offchan,
524 enum nl80211_channel_type channel_type,
525 bool channel_type_valid, unsigned int wait,
526 const u8 *buf, size_t len, bool no_cck,
527 bool dont_wait_for_ack, u64 *cookie )
528#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
Jeff Johnson295189b2012-06-20 16:38:30 -0700529int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
530 struct ieee80211_channel *chan, bool offchan,
531 enum nl80211_channel_type channel_type,
532 bool channel_type_valid, unsigned int wait,
533 const u8 *buf, size_t len, bool no_cck,
534 bool dont_wait_for_ack, u64 *cookie )
535#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
536int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
537 struct ieee80211_channel *chan, bool offchan,
538 enum nl80211_channel_type channel_type,
539 bool channel_type_valid, unsigned int wait,
540 const u8 *buf, size_t len, u64 *cookie )
541#else
542int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
543 struct ieee80211_channel *chan,
544 enum nl80211_channel_type channel_type,
545 bool channel_type_valid,
546 const u8 *buf, size_t len, u64 *cookie )
547#endif //LINUX_VERSION_CODE
548{
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800549#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
550 struct net_device *dev = wdev->netdev;
551#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700552 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR( dev );
553 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
Jeff Johnsone7245742012-09-05 17:12:55 -0700554 tANI_U16 extendedWait = 0;
555 tANI_U8 type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]);
556 tANI_U8 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]);
557 tActionFrmType actionFrmType;
558 bool noack = 0;
559
Jeff Johnson295189b2012-06-20 16:38:30 -0700560#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
561 hdd_adapter_t *goAdapter;
562#endif
563
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -0700564#ifdef WLAN_FEATURE_P2P_DEBUG
565 if ((type == SIR_MAC_MGMT_FRAME) &&
566 (subType == SIR_MAC_MGMT_ACTION) &&
567 (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
568 {
569 actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
Hoonki Lee1090c6a2013-01-16 17:40:54 -0800570 if(actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE)
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -0700571 {
572 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] unknown[%d] ---> OTA",
573 actionFrmType);
574 }
575 else
576 {
577 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] %s ---> OTA",
578 p2p_action_frame_type[actionFrmType]);
579 if( (actionFrmType == WLAN_HDD_PROV_DIS_REQ) &&
580 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
581 {
582 globalP2PConnectionStatus = P2P_GO_NEG_PROCESS;
583 hddLog(LOGE,"[P2P State]Inactive state to "
Jeff Johnson1250df42012-12-10 14:31:52 -0800584 "GO negotiation progress state");
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -0700585 }
586 else if( (actionFrmType == WLAN_HDD_GO_NEG_CNF) &&
587 (globalP2PConnectionStatus == P2P_GO_NEG_PROCESS) )
588 {
589 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
590 hddLog(LOGE,"[P2P State]GO nego progress to GO nego"
591 " completed state");
592 }
593 }
594 }
595#endif
596
Jeff Johnsone7245742012-09-05 17:12:55 -0700597#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
598 noack = dont_wait_for_ack;
599#endif
600
601 //If the wait is coming as 0 with off channel set
602 //then set the wait to 200 ms
603 if (offchan && !wait)
604 wait = ACTION_FRAME_DEFAULT_WAIT;
605
Jeff Johnson295189b2012-06-20 16:38:30 -0700606 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
607 __func__,pAdapter->device_mode);
608
609 //Call sme API to send out a action frame.
610 // OR can we send it directly through data path??
611 // After tx completion send tx status back.
612 if ( ( WLAN_HDD_SOFTAP == pAdapter->device_mode ) ||
613 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
614 )
615 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700616 if (type == SIR_MAC_MGMT_FRAME)
617 {
618 if (subType == SIR_MAC_MGMT_PROBE_RSP)
619 {
620 /* Drop Probe response recieved from supplicant, as for GO and
621 SAP PE itself sends probe response
622 */
623 goto err_rem_channel;
624 }
625 else if ((subType == SIR_MAC_MGMT_DISASSOC) ||
626 (subType == SIR_MAC_MGMT_DEAUTH))
627 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700628 /* During EAP failure or P2P Group Remove supplicant
629 * is sending del_station command to driver. From
630 * del_station function, Driver will send deauth frame to
631 * p2p client. No need to send disassoc frame from here.
632 * so Drop the frame here and send tx indication back to
633 * supplicant.
Jeff Johnson295189b2012-06-20 16:38:30 -0700634 */
635 tANI_U8 dstMac[ETH_ALEN] = {0};
636 memcpy(&dstMac, &buf[WLAN_HDD_80211_FRM_DA_OFFSET], ETH_ALEN);
Jeff Johnsone7245742012-09-05 17:12:55 -0700637 hddLog(VOS_TRACE_LEVEL_INFO,
Jeff Johnson295189b2012-06-20 16:38:30 -0700638 "%s: Deauth/Disassoc received for STA:"
Jeff Johnsone7245742012-09-05 17:12:55 -0700639 "%02x:%02x:%02x:%02x:%02x:%02x",
640 __func__,
641 dstMac[0], dstMac[1], dstMac[2],
Jeff Johnson295189b2012-06-20 16:38:30 -0700642 dstMac[3], dstMac[4], dstMac[5]);
Jeff Johnson295189b2012-06-20 16:38:30 -0700643 goto err_rem_channel;
644 }
645 }
646 }
647
648 if( NULL != cfgState->buf )
649 return -EBUSY;
650
651 hddLog( LOG1, "Action frame tx request");
652
653#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
654 goAdapter = hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_P2P_GO );
655
656 //If GO adapter exists and operating on same frequency
657 //then we will not request remain on channel
658 if( goAdapter && ( ieee80211_frequency_to_channel(chan->center_freq)
659 == goAdapter->sessionCtx.ap.operatingChannel ) )
660 {
661 goto send_frame;
662 }
663#endif
664
665#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
666 if( offchan && wait)
667 {
668 int status;
669
670 // In case of P2P Client mode if we are already
671 // on the same channel then send the frame directly
672
673 if((cfgState->remain_on_chan_ctx != NULL) &&
674 (cfgState->current_freq == chan->center_freq)
675 )
676 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700677 hddLog(LOG1,"action frame: extending the wait time\n");
678 extendedWait = (tANI_U16)wait;
Jeff Johnson295189b2012-06-20 16:38:30 -0700679 goto send_frame;
680 }
681
682 INIT_COMPLETION(pAdapter->offchannel_tx_event);
683
684 status = wlan_hdd_request_remain_on_channel(wiphy, dev,
685 chan, channel_type, wait, cookie,
686 OFF_CHANNEL_ACTION_TX);
687
688 if(0 != status)
689 {
690 if( (-EBUSY == status) &&
691 (cfgState->current_freq == chan->center_freq) )
692 {
693 goto send_frame;
694 }
695 goto err_rem_channel;
696 }
697
698 /* Wait for driver to be ready on the requested channel */
699 status = wait_for_completion_interruptible_timeout(
700 &pAdapter->offchannel_tx_event,
701 msecs_to_jiffies(WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX));
702 if(!status)
703 {
704 hddLog( LOGE, "Not able to complete remain on channel request"
705 " within timeout period");
706 goto err_rem_channel;
707 }
708 }
709 else if ( offchan )
710 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700711 /* Check before sending action frame
712 whether we already remain on channel */
Jeff Johnson295189b2012-06-20 16:38:30 -0700713 if(NULL == cfgState->remain_on_chan_ctx)
714 {
715 goto err_rem_channel;
716 }
717 }
718 send_frame:
719#endif
720
Jeff Johnsone7245742012-09-05 17:12:55 -0700721 if(!noack)
722 {
723 cfgState->buf = vos_mem_malloc( len ); //buf;
724 if( cfgState->buf == NULL )
725 return -ENOMEM;
Jeff Johnson295189b2012-06-20 16:38:30 -0700726
Jeff Johnsone7245742012-09-05 17:12:55 -0700727 cfgState->len = len;
Jeff Johnson295189b2012-06-20 16:38:30 -0700728
Jeff Johnsone7245742012-09-05 17:12:55 -0700729 vos_mem_copy( cfgState->buf, buf, len);
Jeff Johnson295189b2012-06-20 16:38:30 -0700730
731#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnsone7245742012-09-05 17:12:55 -0700732 if( cfgState->remain_on_chan_ctx )
733 {
734 cfgState->action_cookie = cfgState->remain_on_chan_ctx->cookie;
735 *cookie = cfgState->action_cookie;
736 }
737 else
738 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700739#endif
Jeff Johnsone7245742012-09-05 17:12:55 -0700740 *cookie = (tANI_U32) cfgState->buf;
741 cfgState->action_cookie = *cookie;
Jeff Johnson295189b2012-06-20 16:38:30 -0700742#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnsone7245742012-09-05 17:12:55 -0700743 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700744#endif
Jeff Johnsone7245742012-09-05 17:12:55 -0700745 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700746
747 if ( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700748 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
749 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700750 )
751 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700752 tANI_U8 sessionId = pAdapter->sessionId;
Hoonki Lee1090c6a2013-01-16 17:40:54 -0800753
Jeff Johnsone7245742012-09-05 17:12:55 -0700754 if ((type == SIR_MAC_MGMT_FRAME) &&
755 (subType == SIR_MAC_MGMT_ACTION) &&
756 (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
Jeff Johnson295189b2012-06-20 16:38:30 -0700757 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700758 actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
759 hddLog(LOG1, "Tx Action Frame %u \n", actionFrmType);
760 if (actionFrmType == WLAN_HDD_PROV_DIS_REQ)
Jeff Johnson295189b2012-06-20 16:38:30 -0700761 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700762 cfgState->actionFrmState = HDD_PD_REQ_ACK_PENDING;
763 hddLog(LOG1, "%s: HDD_PD_REQ_ACK_PENDING \n", __func__);
764 }
765 else if (actionFrmType == WLAN_HDD_GO_NEG_REQ)
766 {
767 cfgState->actionFrmState = HDD_GO_NEG_REQ_ACK_PENDING;
768 hddLog(LOG1, "%s: HDD_GO_NEG_REQ_ACK_PENDING \n", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700769 }
770 }
Jeff Johnsone7245742012-09-05 17:12:55 -0700771
Jeff Johnson295189b2012-06-20 16:38:30 -0700772 if (eHAL_STATUS_SUCCESS !=
773 sme_sendAction( WLAN_HDD_GET_HAL_CTX(pAdapter),
Jeff Johnsone7245742012-09-05 17:12:55 -0700774 sessionId, buf, len, extendedWait, noack))
Jeff Johnson295189b2012-06-20 16:38:30 -0700775 {
776 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
777 "%s: sme_sendAction returned fail", __func__);
778 goto err;
779 }
780 }
781 else if( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
782 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
783 )
784 {
Jeff Johnson43971f52012-07-17 12:26:56 -0700785 if( VOS_STATUS_SUCCESS !=
Jeff Johnson295189b2012-06-20 16:38:30 -0700786 WLANSAP_SendAction( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
Jeff Johnsone7245742012-09-05 17:12:55 -0700787 buf, len, 0 ) )
Jeff Johnson295189b2012-06-20 16:38:30 -0700788 {
789 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
790 "%s: WLANSAP_SendAction returned fail", __func__);
791 goto err;
792 }
793 }
794
795 return 0;
796err:
Jeff Johnsone7245742012-09-05 17:12:55 -0700797 if(!noack)
798 {
799 hdd_sendActionCnf( pAdapter, FALSE );
800 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700801 return 0;
802err_rem_channel:
803 *cookie = (tANI_U32)cfgState;
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800804 cfg80211_mgmt_tx_status(
805#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
806 pAdapter->dev->ieee80211_ptr,
807#else
808 pAdapter->dev,
809#endif
810 *cookie, buf, len, FALSE, GFP_KERNEL );
Jeff Johnson295189b2012-06-20 16:38:30 -0700811 return 0;
812}
813
814#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800815#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
816int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
817 struct wireless_dev *wdev,
818 u64 cookie)
819{
820 return wlan_hdd_cfg80211_cancel_remain_on_channel( wiphy, wdev, cookie );
821}
822#else
823int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
Jeff Johnson295189b2012-06-20 16:38:30 -0700824 struct net_device *dev,
825 u64 cookie)
826{
827 return wlan_hdd_cfg80211_cancel_remain_on_channel( wiphy, dev, cookie );
828}
829#endif
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800830#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700831
832void hdd_sendActionCnf( hdd_adapter_t *pAdapter, tANI_BOOLEAN actionSendSuccess )
833{
834 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
835
Jeff Johnsone7245742012-09-05 17:12:55 -0700836 cfgState->actionFrmState = HDD_IDLE;
837
Jeff Johnson295189b2012-06-20 16:38:30 -0700838 hddLog( LOG1, "Send Action cnf, actionSendSuccess %d", actionSendSuccess);
839 if( NULL == cfgState->buf )
840 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700841 return;
842 }
843
844 /* If skb is NULL it means this packet was received on CFG80211 interface
845 * else it was received on Monitor interface */
846 if( cfgState->skb == NULL )
847 {
848 /*
849 * buf is the same pointer it passed us to send. Since we are sending
850 * it through control path, we use different buffers.
851 * In case of mac80211, they just push it to the skb and pass the same
852 * data while sending tx ack status.
853 * */
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -0800854 cfg80211_mgmt_tx_status(
855#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
856 pAdapter->dev->ieee80211_ptr,
857#else
858 pAdapter->dev,
859#endif
860 cfgState->action_cookie,
Jeff Johnson295189b2012-06-20 16:38:30 -0700861 cfgState->buf, cfgState->len, actionSendSuccess, GFP_KERNEL );
862 vos_mem_free( cfgState->buf );
863 cfgState->buf = NULL;
864 }
865 else
866 {
867 hdd_adapter_t* pMonAdapter =
868 hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_MONITOR );
869 if( pMonAdapter == NULL )
870 {
871 hddLog( LOGE, "Not able to get Monitor Adapter");
872 cfgState->skb = NULL;
873 vos_mem_free( cfgState->buf );
874 cfgState->buf = NULL;
875 complete(&pAdapter->tx_action_cnf_event);
876 return;
877 }
878 /* Send TX completion feedback over monitor interface. */
879 hdd_wlan_tx_complete( pMonAdapter, cfgState, actionSendSuccess );
880 cfgState->skb = NULL;
881 vos_mem_free( cfgState->buf );
882 cfgState->buf = NULL;
883 /* Look for the next Mgmt packet to TX */
884 hdd_mon_tx_mgmt_pkt(pAdapter);
885 }
886 complete(&pAdapter->tx_action_cnf_event);
887}
888
889/**
890 * hdd_setP2pNoa
891 *
892 *FUNCTION:
893 * This function is called from hdd_hostapd_ioctl function when Driver
894 * get P2P_SET_NOA comand from wpa_supplicant using private ioctl
895 *
896 *LOGIC:
897 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
898 *
899 *ASSUMPTIONS:
900 *
901 *
902 *NOTE:
903 *
904 * @param dev Pointer to net device structure
905 * @param command Pointer to command
906 *
907 * @return Status
908 */
909
910int hdd_setP2pNoa( struct net_device *dev, tANI_U8 *command )
911{
912 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
913 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
914 VOS_STATUS status = VOS_STATUS_SUCCESS;
915 tP2pPsConfig NoA;
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800916 int count, duration, start_time;
Jeff Johnson295189b2012-06-20 16:38:30 -0700917 char *param;
918
Madan Mohan Koyyalamudid8ac8662012-11-06 19:04:56 -0800919 param = strnchr(command, strlen(command), ' ');
Jeff Johnson295189b2012-06-20 16:38:30 -0700920 if (param == NULL)
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -0800921 return -EINVAL;
Jeff Johnson295189b2012-06-20 16:38:30 -0700922 param++;
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800923 sscanf(param, "%d %d %d", &count, &start_time, &duration);
Jeff Johnson295189b2012-06-20 16:38:30 -0700924 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
925 "%s: P2P_SET GO NoA: count=%d duration=%d interval=%d \n",
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800926 __func__, count, start_time, duration);
927 duration = MS_TO_MUS(duration);
Jeff Johnson295189b2012-06-20 16:38:30 -0700928 /* PS Selection
929 * Periodic NoA (2)
930 * Single NOA (4)
931 */
932 NoA.opp_ps = 0;
933 NoA.ctWindow = 0;
934 if (count == 1)
935 {
936 NoA.duration = 0;
937 NoA.single_noa_duration = duration;
938 NoA.psSelection = P2P_POWER_SAVE_TYPE_SINGLE_NOA;
939 }
940 else
941 {
942 NoA.duration = duration;
943 NoA.single_noa_duration = 0;
944 NoA.psSelection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA;
945 }
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800946 NoA.interval = MS_TO_MUS(100);
Jeff Johnson295189b2012-06-20 16:38:30 -0700947 NoA.count = count;
948 NoA.sessionid = pAdapter->sessionId;
949
950 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
951 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
952 "interval %d count %d single noa duration %d "
953 "PsSelection %x \n", __func__, NoA.opp_ps,
954 NoA.ctWindow, NoA.duration, NoA.interval,
955 NoA.count, NoA.single_noa_duration,
956 NoA.psSelection);
957
958 sme_p2pSetPs(hHal, &NoA);
959 return status;
960}
961
962/**
963 * hdd_setP2pOpps
964 *
965 *FUNCTION:
966 * This function is called from hdd_hostapd_ioctl function when Driver
967 * get P2P_SET_PS comand from wpa_supplicant using private ioctl
968 *
969 *LOGIC:
970 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
971 *
972 *ASSUMPTIONS:
973 *
974 *
975 *NOTE:
976 *
977 * @param dev Pointer to net device structure
978 * @param command Pointer to command
979 *
980 * @return Status
981 */
982
983int hdd_setP2pOpps( struct net_device *dev, tANI_U8 *command )
984{
985 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
986 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
987 VOS_STATUS status = VOS_STATUS_SUCCESS;
988 tP2pPsConfig NoA;
989 char *param;
990 int legacy_ps, opp_ps, ctwindow;
991
Madan Mohan Koyyalamudid8ac8662012-11-06 19:04:56 -0800992 param = strnchr(command, strlen(command), ' ');
Jeff Johnson295189b2012-06-20 16:38:30 -0700993 if (param == NULL)
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -0800994 return -EINVAL;
Jeff Johnson295189b2012-06-20 16:38:30 -0700995 param++;
996 sscanf(param, "%d %d %d", &legacy_ps, &opp_ps, &ctwindow);
997 VOS_TRACE (VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
998 "%s: P2P_SET GO PS: legacy_ps=%d opp_ps=%d ctwindow=%d \n",
999 __func__, legacy_ps, opp_ps, ctwindow);
1000
1001 /* PS Selection
1002 * Opportunistic Power Save (1)
1003 */
1004
1005 /* From wpa_cli user need to use separate command to set ctWindow and Opps
1006 * When user want to set ctWindow during that time other parameters
1007 * values are coming from wpa_supplicant as -1.
1008 * Example : User want to set ctWindow with 30 then wpa_cli command :
1009 * P2P_SET ctwindow 30
1010 * Command Received at hdd_hostapd_ioctl is as below:
1011 * P2P_SET_PS -1 -1 30 (legacy_ps = -1, opp_ps = -1, ctwindow = 30)
1012 */
1013 if (ctwindow != -1)
1014 {
1015
1016 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
1017 "Opportunistic Power Save is %s \n",
1018 (TRUE == pAdapter->ops) ? "Enable" : "Disable" );
1019
1020 if (ctwindow != pAdapter->ctw)
1021 {
1022 pAdapter->ctw = ctwindow;
1023
1024 if(pAdapter->ops)
1025 {
1026 NoA.opp_ps = pAdapter->ops;
1027 NoA.ctWindow = pAdapter->ctw;
1028 NoA.duration = 0;
1029 NoA.single_noa_duration = 0;
1030 NoA.interval = 0;
1031 NoA.count = 0;
1032 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
1033 NoA.sessionid = pAdapter->sessionId;
1034
1035 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
1036 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
1037 "interval %d count %d single noa duration %d "
1038 "PsSelection %x \n", __func__, NoA.opp_ps,
1039 NoA.ctWindow, NoA.duration, NoA.interval,
1040 NoA.count, NoA.single_noa_duration,
1041 NoA.psSelection);
1042
1043 sme_p2pSetPs(hHal, &NoA);
1044 }
1045 return 0;
1046 }
1047 }
1048
1049 if (opp_ps != -1)
1050 {
1051 pAdapter->ops = opp_ps;
1052
1053 if ((opp_ps != -1) && (pAdapter->ctw))
1054 {
1055 NoA.opp_ps = opp_ps;
1056 NoA.ctWindow = pAdapter->ctw;
1057 NoA.duration = 0;
1058 NoA.single_noa_duration = 0;
1059 NoA.interval = 0;
1060 NoA.count = 0;
1061 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
1062 NoA.sessionid = pAdapter->sessionId;
1063
1064 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
1065 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
1066 "interval %d count %d single noa duration %d "
1067 "PsSelection %x \n", __func__, NoA.opp_ps,
1068 NoA.ctWindow, NoA.duration, NoA.interval,
1069 NoA.count, NoA.single_noa_duration,
1070 NoA.psSelection);
1071
1072 sme_p2pSetPs(hHal, &NoA);
1073 }
1074 }
1075 return status;
1076}
1077
1078int hdd_setP2pPs( struct net_device *dev, void *msgData )
1079{
1080 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1081 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
1082 VOS_STATUS status = VOS_STATUS_SUCCESS;
1083 tP2pPsConfig NoA;
1084 p2p_app_setP2pPs_t *pappNoA = (p2p_app_setP2pPs_t *) msgData;
1085
1086 NoA.opp_ps = pappNoA->opp_ps;
1087 NoA.ctWindow = pappNoA->ctWindow;
1088 NoA.duration = pappNoA->duration;
1089 NoA.interval = pappNoA->interval;
1090 NoA.count = pappNoA->count;
1091 NoA.single_noa_duration = pappNoA->single_noa_duration;
1092 NoA.psSelection = pappNoA->psSelection;
1093 NoA.sessionid = pAdapter->sessionId;
1094
1095 sme_p2pSetPs(hHal, &NoA);
1096 return status;
1097}
1098#endif
1099
1100static tANI_U8 wlan_hdd_get_session_type( enum nl80211_iftype type )
1101{
1102 tANI_U8 sessionType;
1103
1104 switch( type )
1105 {
1106 case NL80211_IFTYPE_AP:
1107 sessionType = WLAN_HDD_SOFTAP;
1108 break;
1109 case NL80211_IFTYPE_P2P_GO:
1110 sessionType = WLAN_HDD_P2P_GO;
1111 break;
1112 case NL80211_IFTYPE_P2P_CLIENT:
1113 sessionType = WLAN_HDD_P2P_CLIENT;
1114 break;
1115 case NL80211_IFTYPE_STATION:
1116 sessionType = WLAN_HDD_INFRA_STATION;
1117 break;
1118 case NL80211_IFTYPE_MONITOR:
1119 sessionType = WLAN_HDD_MONITOR;
1120 break;
1121 default:
1122 sessionType = WLAN_HDD_INFRA_STATION;
1123 break;
1124 }
1125
1126 return sessionType;
1127}
1128
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -08001129#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0))
1130struct wireless_dev* wlan_hdd_add_virtual_intf(
1131 struct wiphy *wiphy, const char *name,
1132 enum nl80211_iftype type,
1133 u32 *flags, struct vif_params *params )
1134#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
1135struct wireless_dev* wlan_hdd_add_virtual_intf(
1136 struct wiphy *wiphy, char *name, enum nl80211_iftype type,
1137 u32 *flags, struct vif_params *params )
1138#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnson295189b2012-06-20 16:38:30 -07001139struct net_device* wlan_hdd_add_virtual_intf(
1140 struct wiphy *wiphy, char *name, enum nl80211_iftype type,
1141 u32 *flags, struct vif_params *params )
1142#else
1143int wlan_hdd_add_virtual_intf( struct wiphy *wiphy, char *name,
1144 enum nl80211_iftype type,
1145 u32 *flags, struct vif_params *params )
1146#endif
1147{
1148 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
1149 hdd_adapter_t* pAdapter = NULL;
1150
1151 ENTER();
1152
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001153 if(hdd_get_adapter(pHddCtx, wlan_hdd_get_session_type(type)) != NULL)
1154 {
Jeff Johnsond13512a2012-07-17 11:42:19 -07001155 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Interface type %d already exists. Two"
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001156 "interfaces of same type are not supported currently.",__func__, type);
Jeff Johnsond13512a2012-07-17 11:42:19 -07001157 return NULL;
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001158 }
1159
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -07001160 if (pHddCtx->isLogpInProgress)
1161 {
1162 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1163 "%s:LOGP in Progress. Ignore!!!", __func__);
1164#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1165 return NULL;
1166#else
1167 return -EAGAIN;
1168#endif
1169 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001170 if ( pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated )
1171 {
1172 if( (NL80211_IFTYPE_P2P_GO == type) ||
1173 (NL80211_IFTYPE_P2P_CLIENT == type) )
1174 {
1175 /* Generate the P2P Interface Address. this address must be
1176 * different from the P2P Device Address.
1177 */
1178 v_MACADDR_t p2pDeviceAddress = pHddCtx->p2pDeviceAddress;
1179 p2pDeviceAddress.bytes[4] ^= 0x80;
1180 pAdapter = hdd_open_adapter( pHddCtx,
1181 wlan_hdd_get_session_type(type),
1182 name, p2pDeviceAddress.bytes,
1183 VOS_TRUE );
1184 }
1185 }
1186 else
1187 {
1188 pAdapter = hdd_open_adapter( pHddCtx, wlan_hdd_get_session_type(type),
1189 name, wlan_hdd_get_intf_addr(pHddCtx), VOS_TRUE );
1190 }
1191
1192 if( NULL == pAdapter)
1193 {
1194 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: hdd_open_adapter failed",__func__);
1195#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1196 return NULL;
1197#else
1198 return -EINVAL;
1199#endif
1200 }
1201 EXIT();
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -08001202#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
1203 return pAdapter->dev->ieee80211_ptr;
1204#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnson295189b2012-06-20 16:38:30 -07001205 return pAdapter->dev;
1206#else
1207 return 0;
1208#endif
1209}
1210
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -08001211#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
1212int wlan_hdd_del_virtual_intf( struct wiphy *wiphy, struct wireless_dev *wdev )
1213#else
Jeff Johnson295189b2012-06-20 16:38:30 -07001214int wlan_hdd_del_virtual_intf( struct wiphy *wiphy, struct net_device *dev )
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -08001215#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001216{
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -08001217#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
1218 struct net_device *dev = wdev->netdev;
1219#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001220 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
1221 hdd_adapter_t *pVirtAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1222 ENTER();
1223
1224 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
1225 __func__,pVirtAdapter->device_mode);
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -07001226 if (pHddCtx->isLogpInProgress)
1227 {
1228 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1229 "%s:LOGP in Progress. Ignore!!!", __func__);
1230 return -EAGAIN;
1231 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001232
1233 wlan_hdd_release_intf_addr( pHddCtx,
1234 pVirtAdapter->macAddressCurrent.bytes );
1235
1236 hdd_stop_adapter( pHddCtx, pVirtAdapter );
1237 hdd_close_adapter( pHddCtx, pVirtAdapter, TRUE );
1238 EXIT();
1239 return 0;
1240}
1241
1242void hdd_sendMgmtFrameOverMonitorIface( hdd_adapter_t *pMonAdapter,
1243 tANI_U32 nFrameLength, tANI_U8* pbFrames,
1244 tANI_U8 frameType )
1245{
1246 //Indicate a Frame over Monitor Intf.
1247 int rxstat;
1248 struct sk_buff *skb = NULL;
1249 int needed_headroom = 0;
1250 int flag = HDD_RX_FLAG_IV_STRIPPED | HDD_RX_FLAG_DECRYPTED |
1251 HDD_RX_FLAG_MMIC_STRIPPED;
Jeff Johnsone7245742012-09-05 17:12:55 -07001252#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1253 hdd_context_t* pHddCtx = (hdd_context_t*)(pMonAdapter->pHddCtx);
1254#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001255 hddLog( LOG1, FL("Indicate Frame over Monitor Intf"));
1256
1257 VOS_ASSERT( (pbFrames != NULL) );
1258
1259 /* room for the radiotap header based on driver features
1260 * 1 Byte for RADIO TAP Flag, 1 Byte padding and 2 Byte for
1261 * RX flags.
1262 * */
1263 needed_headroom = sizeof(struct ieee80211_radiotap_header) + 4;
1264
1265 //alloc skb here
1266 skb = alloc_skb(VPKT_SIZE_BUFFER, GFP_ATOMIC);
1267 if (unlikely(NULL == skb))
1268 {
1269 hddLog( LOGW, FL("Unable to allocate skb"));
1270 return;
1271 }
1272 skb_reserve(skb, VPKT_SIZE_BUFFER);
1273 if (unlikely(skb_headroom(skb) < nFrameLength))
1274 {
1275 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
1276 "HDD [%d]: Insufficient headroom, "
1277 "head[%p], data[%p], req[%d]",
1278 __LINE__, skb->head, skb->data, nFrameLength);
1279 kfree_skb(skb);
1280 return ;
1281 }
1282 // actually push the data
1283 memcpy(skb_push(skb, nFrameLength), pbFrames, nFrameLength);
1284 /* prepend radiotap information */
1285 if( 0 != hdd_wlan_add_rx_radiotap_hdr( skb, needed_headroom, flag ) )
1286 {
1287 hddLog( LOGE, FL("Not Able Add Radio Tap"));
1288 //free skb
1289 kfree_skb(skb);
1290 return ;
1291 }
1292
1293 skb_reset_mac_header( skb );
1294 skb->dev = pMonAdapter->dev;
1295 skb->protocol = eth_type_trans( skb, skb->dev );
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001296 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnsone7245742012-09-05 17:12:55 -07001297#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1298 wake_lock_timeout(&pHddCtx->rx_wake_lock, HDD_WAKE_LOCK_DURATION);
1299#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001300 rxstat = netif_rx_ni(skb);
1301 if( NET_RX_SUCCESS == rxstat )
1302 {
1303 hddLog( LOG1, FL("Success"));
1304 }
1305 else
1306 hddLog( LOGE, FL("Failed %d"), rxstat);
1307
1308 return ;
1309}
1310
1311void hdd_indicateMgmtFrame( hdd_adapter_t *pAdapter,
1312 tANI_U32 nFrameLength,
1313 tANI_U8* pbFrames,
1314 tANI_U8 frameType,
Chilam NG571c65a2013-01-19 12:27:36 +05301315 tANI_U32 rxChan,
1316 tANI_S8 rxRssi )
Jeff Johnson295189b2012-06-20 16:38:30 -07001317{
1318 tANI_U16 freq;
Jeff Johnsone7245742012-09-05 17:12:55 -07001319 tANI_U8 type = 0;
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001320 tANI_U8 subType = 0;
Jeff Johnsone7245742012-09-05 17:12:55 -07001321 tActionFrmType actionFrmType;
1322 hdd_cfg80211_state_t *cfgState = NULL;
Jeff Johnson295189b2012-06-20 16:38:30 -07001323
1324 hddLog(VOS_TRACE_LEVEL_INFO, "%s: Frame Type = %d Frame Length = %d\n",
1325 __func__, frameType, nFrameLength);
1326
1327 if (NULL == pAdapter)
1328 {
1329 hddLog( LOGE, FL("pAdapter is NULL"));
1330 return;
1331 }
1332
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001333 type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]);
1334 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]);
1335
1336 /* Get pAdapter from Destination mac address of the frame */
1337 if ((type == SIR_MAC_MGMT_FRAME) &&
1338 (subType != SIR_MAC_MGMT_PROBE_REQ))
1339 {
1340 pAdapter = hdd_get_adapter_by_macaddr( WLAN_HDD_GET_CTX(pAdapter),
1341 &pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET]);
1342 if (NULL == pAdapter)
1343 {
1344 /* Under assumtion that we don't receive any action frame
1345 * with BCST as destination we dropping action frame
1346 */
Madan Mohan Koyyalamudi051ff0b2012-12-03 16:55:26 -08001347 hddLog(VOS_TRACE_LEVEL_FATAL,"pAdapter for action frame is NULL Macaddr = "
1348 MAC_ADDRESS_STR ,
1349 MAC_ADDR_ARRAY(&pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET]));
1350 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Frame Type = %d Frame Length = %d"
1351 " subType = %d \n",__func__,frameType,nFrameLength,subType);
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001352 return;
1353 }
1354 }
1355
Jeff Johnson295189b2012-06-20 16:38:30 -07001356 if (NULL == pAdapter->dev)
1357 {
1358 hddLog( LOGE, FL("pAdapter->dev is NULL"));
1359 return;
1360 }
1361
1362 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
1363 {
1364 hddLog( LOGE, FL("pAdapter has invalid magic"));
1365 return;
1366 }
1367
1368 if( !nFrameLength )
1369 {
1370 hddLog( LOGE, FL("Frame Length is Invalid ZERO"));
1371 return;
1372 }
1373
Madan Mohan Koyyalamudic75be962012-10-18 19:19:03 -07001374 if (NULL == pbFrames) {
1375 hddLog( LOGE, FL("pbFrames is NULL"));
1376 return;
1377 }
1378
1379
Jeff Johnson295189b2012-06-20 16:38:30 -07001380 if( ( WLAN_HDD_SOFTAP == pAdapter->device_mode )
1381 || ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
1382 )
1383 {
1384 hdd_adapter_t *pMonAdapter =
1385 hdd_get_mon_adapter( WLAN_HDD_GET_CTX(pAdapter) );
1386
1387 if( NULL != pMonAdapter )
1388 {
1389 hddLog( LOG1, FL("Indicate Frame over Monitor Interface"));
1390 hdd_sendMgmtFrameOverMonitorIface( pMonAdapter, nFrameLength,
1391 pbFrames, frameType);
1392 return;
1393 }
1394 }
1395
1396 //Channel indicated may be wrong. TODO
1397 //Indicate an action frame.
1398 if( rxChan <= MAX_NO_OF_2_4_CHANNELS )
1399 {
1400 freq = ieee80211_channel_to_frequency( rxChan,
1401 IEEE80211_BAND_2GHZ);
1402 }
1403 else
1404 {
1405 freq = ieee80211_channel_to_frequency( rxChan,
1406 IEEE80211_BAND_5GHZ);
1407 }
1408
Jeff Johnsone7245742012-09-05 17:12:55 -07001409 cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
1410
1411 if ((type == SIR_MAC_MGMT_FRAME) &&
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001412 (subType == SIR_MAC_MGMT_ACTION))
Jeff Johnsone7245742012-09-05 17:12:55 -07001413 {
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001414 if(pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME)
1415 {
1416 // public action frame
1417 if((pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+1] == SIR_MAC_ACTION_VENDOR_SPECIFIC) &&
1418 !vos_mem_compare(&pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+2], SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE))
1419 // P2P action frames
1420 {
1421 actionFrmType = pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
1422 hddLog(LOG1, "Rx Action Frame %u \n", actionFrmType);
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -07001423#ifdef WLAN_FEATURE_P2P_DEBUG
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001424 if(actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE)
1425 {
1426 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] unknown[%d] <--- OTA",
1427 actionFrmType);
1428 }
1429 else
1430 {
1431 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] %s <--- OTA",
1432 p2p_action_frame_type[actionFrmType]);
1433 if( (actionFrmType == WLAN_HDD_PROV_DIS_REQ) &&
1434 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
1435 {
1436 globalP2PConnectionStatus = P2P_GO_NEG_PROCESS;
1437 hddLog(LOGE,"[P2P State]Inactive state to "
Jeff Johnson1250df42012-12-10 14:31:52 -08001438 "GO negotiation progress state");
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001439 }
1440 else if( (actionFrmType == WLAN_HDD_GO_NEG_CNF) &&
1441 (globalP2PConnectionStatus == P2P_GO_NEG_PROCESS) )
1442 {
1443 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
Jeff Johnson1250df42012-12-10 14:31:52 -08001444 hddLog(LOGE,"[P2P State]GO negotiation progress to "
1445 "GO negotiation completed state");
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001446 }
1447 else if( (actionFrmType == WLAN_HDD_INVITATION_REQ) &&
1448 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
1449 {
1450 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
1451 hddLog(LOGE,"[P2P State]Inactive state to GO negotiation"
1452 " completed state Autonomous GO formation");
1453 }
1454 }
1455#endif
1456
1457 if (((actionFrmType == WLAN_HDD_PROV_DIS_RESP) &&
1458 (cfgState->actionFrmState == HDD_PD_REQ_ACK_PENDING)) ||
1459 ((actionFrmType == WLAN_HDD_GO_NEG_RESP) &&
1460 (cfgState->actionFrmState == HDD_GO_NEG_REQ_ACK_PENDING)))
1461 {
1462 hddLog(LOG1, "%s: ACK_PENDING and But received RESP for Action frame ",
1463 __func__);
1464 hdd_sendActionCnf(pAdapter, TRUE);
1465 }
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -07001466 }
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001467#ifdef WLAN_FEATURE_TDLS_DEBUG
1468 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 -07001469 {
Chilam NG571c65a2013-01-19 12:27:36 +05301470 wlan_hdd_tdls_set_cap(&pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+6], 1);
1471 wlan_hdd_tdls_set_rssi(&pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+6], rxRssi);
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001472 hddLog(VOS_TRACE_LEVEL_ERROR,"[TDLS] TDLS Discovery Response <--- OTA");
1473 }
1474#endif
1475 }
1476#ifdef WLAN_FEATURE_TDLS_DEBUG
1477 if(pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_TDLS_ACTION_FRAME)
1478 {
1479 actionFrmType = pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+1];
1480 if(actionFrmType >= MAX_TDLS_ACTION_FRAME_TYPE)
1481 {
1482 hddLog(VOS_TRACE_LEVEL_ERROR,"[TDLS] unknown[%d] <--- OTA",
1483 actionFrmType);
1484 }
1485 else
1486 {
1487 hddLog(VOS_TRACE_LEVEL_ERROR,"[TDLS] %s <--- OTA",
1488 tdls_action_frame_type[actionFrmType]);
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -07001489 }
1490 }
1491#endif
Jeff Johnsone7245742012-09-05 17:12:55 -07001492 }
1493
Jeff Johnson295189b2012-06-20 16:38:30 -07001494 //Indicate Frame Over Normal Interface
1495 hddLog( LOG1, FL("Indicate Frame over NL80211 Interface"));
1496
Jeff Johnson3bbe4bf2013-01-18 17:05:29 -08001497#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
1498 cfg80211_rx_mgmt( pAdapter->dev->ieee80211_ptr, freq, 0,
1499 pbFrames, nFrameLength,
1500 GFP_ATOMIC );
1501#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0))
Jeff Johnson295189b2012-06-20 16:38:30 -07001502 cfg80211_rx_mgmt( pAdapter->dev, freq, 0,
1503 pbFrames, nFrameLength,
1504 GFP_ATOMIC );
1505#else
1506 cfg80211_rx_mgmt( pAdapter->dev, freq,
1507 pbFrames, nFrameLength,
1508 GFP_ATOMIC );
1509#endif //LINUX_VERSION_CODE
1510}
1511
1512/*
1513 * ieee80211_add_rx_radiotap_header - add radiotap header
1514 */
1515static int hdd_wlan_add_rx_radiotap_hdr (
1516 struct sk_buff *skb, int rtap_len, int flag )
1517{
1518 u8 rtap_temp[20] = {0};
1519 struct ieee80211_radiotap_header *rthdr;
1520 unsigned char *pos;
1521 u16 rx_flags = 0;
1522
1523 rthdr = (struct ieee80211_radiotap_header *)(&rtap_temp[0]);
1524
1525 /* radiotap header, set always present flags */
1526 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
1527 (1 << IEEE80211_RADIOTAP_RX_FLAGS));
1528 rthdr->it_len = cpu_to_le16(rtap_len);
1529
1530 pos = (unsigned char *) (rthdr + 1);
1531
1532 /* the order of the following fields is important */
1533
1534 /* IEEE80211_RADIOTAP_FLAGS */
1535 *pos = 0;
1536 pos++;
1537
1538 /* IEEE80211_RADIOTAP_RX_FLAGS: Length 2 Bytes */
1539 /* ensure 2 byte alignment for the 2 byte field as required */
1540 if ((pos - (u8 *)rthdr) & 1)
1541 pos++;
1542 put_unaligned_le16(rx_flags, pos);
1543 pos += 2;
1544
1545 // actually push the data
1546 memcpy(skb_push(skb, rtap_len), &rtap_temp[0], rtap_len);
1547
1548 return 0;
1549}
1550
1551static void hdd_wlan_tx_complete( hdd_adapter_t* pAdapter,
1552 hdd_cfg80211_state_t* cfgState,
1553 tANI_BOOLEAN actionSendSuccess )
1554{
1555 struct ieee80211_radiotap_header *rthdr;
1556 unsigned char *pos;
1557 struct sk_buff *skb = cfgState->skb;
Jeff Johnsone7245742012-09-05 17:12:55 -07001558#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1559 hdd_context_t *pHddCtx = (hdd_context_t*)(pAdapter->pHddCtx);
1560#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001561
1562 /* 2 Byte for TX flags and 1 Byte for Retry count */
1563 u32 rtHdrLen = sizeof(*rthdr) + 3;
1564
1565 u8 *data;
1566
1567 /* We have to return skb with Data starting with MAC header. We have
1568 * copied SKB data starting with MAC header to cfgState->buf. We will pull
1569 * entire skb->len from skb and then we will push cfgState->buf to skb
1570 * */
1571 if( NULL == skb_pull(skb, skb->len) )
1572 {
1573 hddLog( LOGE, FL("Not Able to Pull %d byte from skb"), skb->len);
1574 kfree_skb(cfgState->skb);
1575 return;
1576 }
1577
1578 data = skb_push( skb, cfgState->len );
1579
1580 if (data == NULL)
1581 {
1582 hddLog( LOGE, FL("Not Able to Push %d byte to skb"), cfgState->len);
1583 kfree_skb( cfgState->skb );
1584 return;
1585 }
1586
1587 memcpy( data, cfgState->buf, cfgState->len );
1588
1589 /* send frame to monitor interfaces now */
1590 if( skb_headroom(skb) < rtHdrLen )
1591 {
1592 hddLog( LOGE, FL("No headroom for rtap header"));
1593 kfree_skb(cfgState->skb);
1594 return;
1595 }
1596
1597 rthdr = (struct ieee80211_radiotap_header*) skb_push( skb, rtHdrLen );
1598
1599 memset( rthdr, 0, rtHdrLen );
1600 rthdr->it_len = cpu_to_le16( rtHdrLen );
1601 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
1602 (1 << IEEE80211_RADIOTAP_DATA_RETRIES)
1603 );
1604
1605 pos = (unsigned char *)( rthdr+1 );
1606
1607 // Fill TX flags
1608 *pos = actionSendSuccess;
1609 pos += 2;
1610
1611 // Fill retry count
1612 *pos = 0;
1613 pos++;
1614
1615 skb_set_mac_header( skb, 0 );
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001616 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnson295189b2012-06-20 16:38:30 -07001617 skb->pkt_type = PACKET_OTHERHOST;
1618 skb->protocol = htons(ETH_P_802_2);
1619 memset( skb->cb, 0, sizeof( skb->cb ) );
Jeff Johnsone7245742012-09-05 17:12:55 -07001620#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1621 wake_lock_timeout(&pHddCtx->rx_wake_lock, HDD_WAKE_LOCK_DURATION);
1622#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001623 if (in_interrupt())
1624 netif_rx( skb );
1625 else
1626 netif_rx_ni( skb );
1627
1628 /* Enable Queues which we have disabled earlier */
1629 netif_tx_start_all_queues( pAdapter->dev );
1630
1631}
1632#endif // CONFIG_CFG80211