blob: 04a1881fd5047df5109af5d66676e89fb6b047c7 [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 }
149 cfg80211_remain_on_channel_expired( pRemainChanCtx->dev,
150 pRemainChanCtx->cookie,
151 &pRemainChanCtx->chan,
152 pRemainChanCtx->chan_type, GFP_KERNEL );
153 }
154
Jeff Johnson295189b2012-06-20 16:38:30 -0700155
156 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700157 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
158 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700159 )
160 {
161 tANI_U8 sessionId = pAdapter->sessionId;
Madan Mohan Koyyalamudi35885912012-11-30 15:05:42 -0800162 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
163 {
164 sme_DeregisterMgmtFrame(
165 hHal, sessionId,
166 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
167 NULL, 0 );
168 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700169 }
170 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
171 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
172 )
173 {
174 WLANSAP_DeRegisterMgmtFrame(
175 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
176 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
177 NULL, 0 );
178 }
179
Madan Mohan Koyyalamudi35885912012-11-30 15:05:42 -0800180 vos_mem_free( pRemainChanCtx );
Jeff Johnson295189b2012-06-20 16:38:30 -0700181 complete(&pAdapter->cancel_rem_on_chan_var);
182 return eHAL_STATUS_SUCCESS;
183}
184
Gopichand Nakkalaf527dc62012-12-31 16:35:10 -0800185void wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter)
Jeff Johnson295189b2012-06-20 16:38:30 -0700186{
Jeff Johnson295189b2012-06-20 16:38:30 -0700187 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
188 int status = 0;
Jeff Johnson295189b2012-06-20 16:38:30 -0700189
Jeff Johnson32d95a32012-09-10 13:15:23 -0700190 if(cfgState->remain_on_chan_ctx != NULL)
Jeff Johnson295189b2012-06-20 16:38:30 -0700191 {
Jeff Johnson32d95a32012-09-10 13:15:23 -0700192 hddLog( LOG1, "Cancel Existing Remain on Channel");
193
194 /* Wait till remain on channel ready indication before issuing cancel
195 * remain on channel request, otherwise if remain on channel not
196 * received and if the driver issues cancel remain on channel then lim
Jeff Johnson295189b2012-06-20 16:38:30 -0700197 * will be in unknown state.
198 */
199 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
200 msecs_to_jiffies(WAIT_REM_CHAN_READY));
201 if (!status)
202 {
203 hddLog( LOGE,
204 "%s: timeout waiting for remain on channel ready indication",
205 __func__);
206 }
207
208 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
Jeff Johnson32d95a32012-09-10 13:15:23 -0700209
Jeff Johnson295189b2012-06-20 16:38:30 -0700210 /* Issue abort remain on chan request to sme.
211 * The remain on channel callback will make sure the remain_on_chan
212 * expired event is sent.
213 */
214 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700215 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
216 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700217 )
218 {
219 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
220 pAdapter->sessionId );
221 }
222 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
223 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
224 )
225 {
226 WLANSAP_CancelRemainOnChannel(
227 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
228 }
Jeff Johnsone7245742012-09-05 17:12:55 -0700229
Jeff Johnson32d95a32012-09-10 13:15:23 -0700230 status = wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
Jeff Johnson295189b2012-06-20 16:38:30 -0700231 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
Jeff Johnson32d95a32012-09-10 13:15:23 -0700232
233 if (!status)
234 {
235 hddLog( LOGE,
236 "%s: timeout waiting for cancel remain on channel ready indication",
237 __func__);
238 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700239 }
Jeff Johnson32d95a32012-09-10 13:15:23 -0700240}
241
242int wlan_hdd_check_remain_on_channel(hdd_adapter_t *pAdapter)
243{
244 int status = 0;
245 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
246
247 if(WLAN_HDD_P2P_GO != pAdapter->device_mode)
248 {
249 //Cancel Existing Remain On Channel
250 //If no action frame is pending
251 if( cfgState->remain_on_chan_ctx != NULL)
252 {
253 //Check whether Action Frame is pending or not
254 if( cfgState->buf == NULL)
255 {
256 wlan_hdd_cancel_existing_remain_on_channel(pAdapter);
257 }
258 else
259 {
260 hddLog( LOG1, "Cannot Cancel Existing Remain on Channel");
261 status = -EBUSY;
262 }
263 }
264 }
265 return status;
266}
267
268static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy,
269 struct net_device *dev,
270 struct ieee80211_channel *chan,
271 enum nl80211_channel_type channel_type,
272 unsigned int duration, u64 *cookie,
273 rem_on_channel_request_type_t request_type )
274{
275 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
276 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
277 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
278 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
279 __func__,pAdapter->device_mode);
280
281 hddLog( LOG1,
282 "chan(hw_val)0x%x chan(centerfreq) %d chan type 0x%x, duration %d",
283 chan->hw_value, chan->center_freq, channel_type, duration );
284
285 //Cancel existing remain On Channel if any
286 wlan_hdd_cancel_existing_remain_on_channel(pAdapter);
Jeff Johnson295189b2012-06-20 16:38:30 -0700287
Jeff Johnsone7245742012-09-05 17:12:55 -0700288 /* When P2P-GO and if we are trying to unload the driver then
Jeff Johnson295189b2012-06-20 16:38:30 -0700289 * wlan driver is keep on receiving the remain on channel command
Jeff Johnsone7245742012-09-05 17:12:55 -0700290 * and which is resulting in crash. So not allowing any remain on
Jeff Johnson295189b2012-06-20 16:38:30 -0700291 * channel requets when Load/Unload is in progress*/
292 if (((hdd_context_t*)pAdapter->pHddCtx)->isLoadUnloadInProgress)
293 {
294 hddLog( LOGE,
295 "%s: Wlan Load/Unload is in progress", __func__);
296 return -EBUSY;
297 }
298
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700299 if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress)
300 {
301 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
302 "%s:LOGP in Progress. Ignore!!!", __func__);
303 return -EAGAIN;
304 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700305 pRemainChanCtx = vos_mem_malloc( sizeof(hdd_remain_on_chan_ctx_t) );
306 if( NULL == pRemainChanCtx )
307 {
308 hddLog(VOS_TRACE_LEVEL_FATAL,
309 "%s: Not able to allocate memory for Channel context",
310 __func__);
311 return -ENOMEM;
312 }
313
314 vos_mem_copy( &pRemainChanCtx->chan, chan,
315 sizeof(struct ieee80211_channel) );
316
317 pRemainChanCtx->chan_type = channel_type;
318 pRemainChanCtx->duration = duration;
319 pRemainChanCtx->dev = dev;
320 *cookie = (tANI_U32) pRemainChanCtx;
321 pRemainChanCtx->cookie = *cookie;
322 pRemainChanCtx->rem_on_chan_request = request_type;
323 cfgState->remain_on_chan_ctx = pRemainChanCtx;
324 cfgState->current_freq = chan->center_freq;
325
326 INIT_COMPLETION(pAdapter->rem_on_chan_ready_event);
327
328 //call sme API to start remain on channel.
329 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700330 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
331 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700332 )
333 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700334 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700335 //call sme API to start remain on channel.
336 sme_RemainOnChannel(
337 WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId,
338 chan->hw_value, duration,
339 wlan_hdd_remain_on_channel_callback, pAdapter );
340
Madan Mohan Koyyalamudi35885912012-11-30 15:05:42 -0800341 if( REMAIN_ON_CHANNEL_REQUEST == request_type)
342 {
343 sme_RegisterMgmtFrame(WLAN_HDD_GET_HAL_CTX(pAdapter),
344 sessionId, (SIR_MAC_MGMT_FRAME << 2) |
345 (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0 );
346 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700347
348 }
349 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
350 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
351 )
352 {
353 //call sme API to start remain on channel.
Jeff Johnson43971f52012-07-17 12:26:56 -0700354 if (VOS_STATUS_SUCCESS != WLANSAP_RemainOnChannel(
Jeff Johnson295189b2012-06-20 16:38:30 -0700355 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
356 chan->hw_value, duration,
357 wlan_hdd_remain_on_channel_callback, pAdapter ))
358
359 {
360 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
361 "%s: WLANSAP_RemainOnChannel returned fail", __func__);
362 cfgState->remain_on_chan_ctx = NULL;
Jeff Johnsone7245742012-09-05 17:12:55 -0700363 vos_mem_free (pRemainChanCtx);
Jeff Johnson295189b2012-06-20 16:38:30 -0700364 return -EINVAL;
365 }
366
367
Jeff Johnson43971f52012-07-17 12:26:56 -0700368 if (VOS_STATUS_SUCCESS != WLANSAP_RegisterMgmtFrame(
Jeff Johnson295189b2012-06-20 16:38:30 -0700369 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
370 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
371 NULL, 0 ))
372 {
373 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
374 "%s: WLANSAP_RegisterMgmtFrame returned fail", __func__);
375 WLANSAP_CancelRemainOnChannel(
376 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
377 return -EINVAL;
378 }
379
380 }
381 return 0;
382
383}
384
385int wlan_hdd_cfg80211_remain_on_channel( struct wiphy *wiphy,
386 struct net_device *dev,
387 struct ieee80211_channel *chan,
388 enum nl80211_channel_type channel_type,
389 unsigned int duration, u64 *cookie )
390{
391 return wlan_hdd_request_remain_on_channel(wiphy, dev,
392 chan, channel_type, duration, cookie,
393 REMAIN_ON_CHANNEL_REQUEST);
394}
395
396void hdd_remainChanReadyHandler( hdd_adapter_t *pAdapter )
397{
398 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
399 hdd_remain_on_chan_ctx_t* pRemainChanCtx = cfgState->remain_on_chan_ctx;
400
401 hddLog( LOG1, "Ready on chan ind");
402
403 if( pRemainChanCtx != NULL )
404 {
405 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
406 {
407 cfg80211_ready_on_channel( pAdapter->dev, (tANI_U32)pRemainChanCtx,
408 &pRemainChanCtx->chan, pRemainChanCtx->chan_type,
409 pRemainChanCtx->duration, GFP_KERNEL );
410 }
411#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
412 else if( OFF_CHANNEL_ACTION_TX == pRemainChanCtx->rem_on_chan_request )
413 {
414 complete(&pAdapter->offchannel_tx_event);
415 }
416#endif
417 complete(&pAdapter->rem_on_chan_ready_event);
418 }
419 else
420 {
421 hddLog( LOGW, "%s: No Pending Remain on channel Request", __func__);
422 }
423 return;
424}
425
426int wlan_hdd_cfg80211_cancel_remain_on_channel( struct wiphy *wiphy,
427 struct net_device *dev, u64 cookie )
428{
429 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson295189b2012-06-20 16:38:30 -0700430 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
431 int status = 0;
432
433 hddLog( LOG1, "Cancel remain on channel req");
434
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700435 if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress)
436 {
437 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
438 "%s:LOGP in Progress. Ignore!!!", __func__);
439 return -EAGAIN;
440 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700441 /* FIXME cancel currently running remain on chan.
442 * Need to check cookie and cancel accordingly
443 */
444 if( (cfgState->remain_on_chan_ctx == NULL) ||
445 (cfgState->remain_on_chan_ctx->cookie != cookie) )
446 {
447 hddLog( LOGE,
448 "%s: No Remain on channel pending with specified cookie value",
449 __func__);
450 return -EINVAL;
451 }
452
453 /* wait until remain on channel ready event received
454 * for already issued remain on channel request */
455 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
456 msecs_to_jiffies(WAIT_REM_CHAN_READY));
457 if (!status)
458 {
459 hddLog( LOGE,
460 "%s: timeout waiting for remain on channel ready indication",
461 __func__);
462 }
463 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
464 /* Issue abort remain on chan request to sme.
465 * The remain on channel callback will make sure the remain_on_chan
466 * expired event is sent.
467 */
468 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700469 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
470 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700471 )
472 {
473 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700474 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
475 sessionId );
476 }
477 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
478 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
479 )
480 {
481 WLANSAP_CancelRemainOnChannel(
482 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
483 }
484 else
485 {
486 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Invalid device_mode = %d",
487 __func__, pAdapter->device_mode);
488 return -EIO;
489 }
490 wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
491 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
492 return 0;
493}
494
495#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
496int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
497 struct ieee80211_channel *chan, bool offchan,
498 enum nl80211_channel_type channel_type,
499 bool channel_type_valid, unsigned int wait,
500 const u8 *buf, size_t len, bool no_cck,
501 bool dont_wait_for_ack, u64 *cookie )
502#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
503int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
504 struct ieee80211_channel *chan, bool offchan,
505 enum nl80211_channel_type channel_type,
506 bool channel_type_valid, unsigned int wait,
507 const u8 *buf, size_t len, u64 *cookie )
508#else
509int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
510 struct ieee80211_channel *chan,
511 enum nl80211_channel_type channel_type,
512 bool channel_type_valid,
513 const u8 *buf, size_t len, u64 *cookie )
514#endif //LINUX_VERSION_CODE
515{
516 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR( dev );
517 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
Jeff Johnsone7245742012-09-05 17:12:55 -0700518 tANI_U16 extendedWait = 0;
519 tANI_U8 type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]);
520 tANI_U8 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]);
521 tActionFrmType actionFrmType;
522 bool noack = 0;
523
Jeff Johnson295189b2012-06-20 16:38:30 -0700524#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
525 hdd_adapter_t *goAdapter;
526#endif
527
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -0700528#ifdef WLAN_FEATURE_P2P_DEBUG
529 if ((type == SIR_MAC_MGMT_FRAME) &&
530 (subType == SIR_MAC_MGMT_ACTION) &&
531 (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
532 {
533 actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
Hoonki Lee1090c6a2013-01-16 17:40:54 -0800534 if(actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE)
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -0700535 {
536 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] unknown[%d] ---> OTA",
537 actionFrmType);
538 }
539 else
540 {
541 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] %s ---> OTA",
542 p2p_action_frame_type[actionFrmType]);
543 if( (actionFrmType == WLAN_HDD_PROV_DIS_REQ) &&
544 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
545 {
546 globalP2PConnectionStatus = P2P_GO_NEG_PROCESS;
547 hddLog(LOGE,"[P2P State]Inactive state to "
Jeff Johnson1250df42012-12-10 14:31:52 -0800548 "GO negotiation progress state");
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -0700549 }
550 else if( (actionFrmType == WLAN_HDD_GO_NEG_CNF) &&
551 (globalP2PConnectionStatus == P2P_GO_NEG_PROCESS) )
552 {
553 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
554 hddLog(LOGE,"[P2P State]GO nego progress to GO nego"
555 " completed state");
556 }
557 }
558 }
559#endif
560
Jeff Johnsone7245742012-09-05 17:12:55 -0700561#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
562 noack = dont_wait_for_ack;
563#endif
564
565 //If the wait is coming as 0 with off channel set
566 //then set the wait to 200 ms
567 if (offchan && !wait)
568 wait = ACTION_FRAME_DEFAULT_WAIT;
569
Jeff Johnson295189b2012-06-20 16:38:30 -0700570 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
571 __func__,pAdapter->device_mode);
572
573 //Call sme API to send out a action frame.
574 // OR can we send it directly through data path??
575 // After tx completion send tx status back.
576 if ( ( WLAN_HDD_SOFTAP == pAdapter->device_mode ) ||
577 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
578 )
579 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700580 if (type == SIR_MAC_MGMT_FRAME)
581 {
582 if (subType == SIR_MAC_MGMT_PROBE_RSP)
583 {
584 /* Drop Probe response recieved from supplicant, as for GO and
585 SAP PE itself sends probe response
586 */
587 goto err_rem_channel;
588 }
589 else if ((subType == SIR_MAC_MGMT_DISASSOC) ||
590 (subType == SIR_MAC_MGMT_DEAUTH))
591 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700592 /* During EAP failure or P2P Group Remove supplicant
593 * is sending del_station command to driver. From
594 * del_station function, Driver will send deauth frame to
595 * p2p client. No need to send disassoc frame from here.
596 * so Drop the frame here and send tx indication back to
597 * supplicant.
Jeff Johnson295189b2012-06-20 16:38:30 -0700598 */
599 tANI_U8 dstMac[ETH_ALEN] = {0};
600 memcpy(&dstMac, &buf[WLAN_HDD_80211_FRM_DA_OFFSET], ETH_ALEN);
Jeff Johnsone7245742012-09-05 17:12:55 -0700601 hddLog(VOS_TRACE_LEVEL_INFO,
Jeff Johnson295189b2012-06-20 16:38:30 -0700602 "%s: Deauth/Disassoc received for STA:"
Jeff Johnsone7245742012-09-05 17:12:55 -0700603 "%02x:%02x:%02x:%02x:%02x:%02x",
604 __func__,
605 dstMac[0], dstMac[1], dstMac[2],
Jeff Johnson295189b2012-06-20 16:38:30 -0700606 dstMac[3], dstMac[4], dstMac[5]);
Jeff Johnson295189b2012-06-20 16:38:30 -0700607 goto err_rem_channel;
608 }
609 }
610 }
611
612 if( NULL != cfgState->buf )
613 return -EBUSY;
614
615 hddLog( LOG1, "Action frame tx request");
616
617#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
618 goAdapter = hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_P2P_GO );
619
620 //If GO adapter exists and operating on same frequency
621 //then we will not request remain on channel
622 if( goAdapter && ( ieee80211_frequency_to_channel(chan->center_freq)
623 == goAdapter->sessionCtx.ap.operatingChannel ) )
624 {
625 goto send_frame;
626 }
627#endif
628
629#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
630 if( offchan && wait)
631 {
632 int status;
633
634 // In case of P2P Client mode if we are already
635 // on the same channel then send the frame directly
636
637 if((cfgState->remain_on_chan_ctx != NULL) &&
638 (cfgState->current_freq == chan->center_freq)
639 )
640 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700641 hddLog(LOG1,"action frame: extending the wait time\n");
642 extendedWait = (tANI_U16)wait;
Jeff Johnson295189b2012-06-20 16:38:30 -0700643 goto send_frame;
644 }
645
646 INIT_COMPLETION(pAdapter->offchannel_tx_event);
647
648 status = wlan_hdd_request_remain_on_channel(wiphy, dev,
649 chan, channel_type, wait, cookie,
650 OFF_CHANNEL_ACTION_TX);
651
652 if(0 != status)
653 {
654 if( (-EBUSY == status) &&
655 (cfgState->current_freq == chan->center_freq) )
656 {
657 goto send_frame;
658 }
659 goto err_rem_channel;
660 }
661
662 /* Wait for driver to be ready on the requested channel */
663 status = wait_for_completion_interruptible_timeout(
664 &pAdapter->offchannel_tx_event,
665 msecs_to_jiffies(WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX));
666 if(!status)
667 {
668 hddLog( LOGE, "Not able to complete remain on channel request"
669 " within timeout period");
670 goto err_rem_channel;
671 }
672 }
673 else if ( offchan )
674 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700675 /* Check before sending action frame
676 whether we already remain on channel */
Jeff Johnson295189b2012-06-20 16:38:30 -0700677 if(NULL == cfgState->remain_on_chan_ctx)
678 {
679 goto err_rem_channel;
680 }
681 }
682 send_frame:
683#endif
684
Jeff Johnsone7245742012-09-05 17:12:55 -0700685 if(!noack)
686 {
687 cfgState->buf = vos_mem_malloc( len ); //buf;
688 if( cfgState->buf == NULL )
689 return -ENOMEM;
Jeff Johnson295189b2012-06-20 16:38:30 -0700690
Jeff Johnsone7245742012-09-05 17:12:55 -0700691 cfgState->len = len;
Jeff Johnson295189b2012-06-20 16:38:30 -0700692
Jeff Johnsone7245742012-09-05 17:12:55 -0700693 vos_mem_copy( cfgState->buf, buf, len);
Jeff Johnson295189b2012-06-20 16:38:30 -0700694
695#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnsone7245742012-09-05 17:12:55 -0700696 if( cfgState->remain_on_chan_ctx )
697 {
698 cfgState->action_cookie = cfgState->remain_on_chan_ctx->cookie;
699 *cookie = cfgState->action_cookie;
700 }
701 else
702 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700703#endif
Jeff Johnsone7245742012-09-05 17:12:55 -0700704 *cookie = (tANI_U32) cfgState->buf;
705 cfgState->action_cookie = *cookie;
Jeff Johnson295189b2012-06-20 16:38:30 -0700706#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnsone7245742012-09-05 17:12:55 -0700707 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700708#endif
Jeff Johnsone7245742012-09-05 17:12:55 -0700709 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700710
711 if ( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700712 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
713 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700714 )
715 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700716 tANI_U8 sessionId = pAdapter->sessionId;
Hoonki Lee1090c6a2013-01-16 17:40:54 -0800717
Jeff Johnsone7245742012-09-05 17:12:55 -0700718 if ((type == SIR_MAC_MGMT_FRAME) &&
719 (subType == SIR_MAC_MGMT_ACTION) &&
720 (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
Jeff Johnson295189b2012-06-20 16:38:30 -0700721 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700722 actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
723 hddLog(LOG1, "Tx Action Frame %u \n", actionFrmType);
724 if (actionFrmType == WLAN_HDD_PROV_DIS_REQ)
Jeff Johnson295189b2012-06-20 16:38:30 -0700725 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700726 cfgState->actionFrmState = HDD_PD_REQ_ACK_PENDING;
727 hddLog(LOG1, "%s: HDD_PD_REQ_ACK_PENDING \n", __func__);
728 }
729 else if (actionFrmType == WLAN_HDD_GO_NEG_REQ)
730 {
731 cfgState->actionFrmState = HDD_GO_NEG_REQ_ACK_PENDING;
732 hddLog(LOG1, "%s: HDD_GO_NEG_REQ_ACK_PENDING \n", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700733 }
734 }
Jeff Johnsone7245742012-09-05 17:12:55 -0700735
Jeff Johnson295189b2012-06-20 16:38:30 -0700736 if (eHAL_STATUS_SUCCESS !=
737 sme_sendAction( WLAN_HDD_GET_HAL_CTX(pAdapter),
Jeff Johnsone7245742012-09-05 17:12:55 -0700738 sessionId, buf, len, extendedWait, noack))
Jeff Johnson295189b2012-06-20 16:38:30 -0700739 {
740 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
741 "%s: sme_sendAction returned fail", __func__);
742 goto err;
743 }
744 }
745 else if( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
746 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
747 )
748 {
Jeff Johnson43971f52012-07-17 12:26:56 -0700749 if( VOS_STATUS_SUCCESS !=
Jeff Johnson295189b2012-06-20 16:38:30 -0700750 WLANSAP_SendAction( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
Jeff Johnsone7245742012-09-05 17:12:55 -0700751 buf, len, 0 ) )
Jeff Johnson295189b2012-06-20 16:38:30 -0700752 {
753 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
754 "%s: WLANSAP_SendAction returned fail", __func__);
755 goto err;
756 }
757 }
758
759 return 0;
760err:
Jeff Johnsone7245742012-09-05 17:12:55 -0700761 if(!noack)
762 {
763 hdd_sendActionCnf( pAdapter, FALSE );
764 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700765 return 0;
766err_rem_channel:
767 *cookie = (tANI_U32)cfgState;
768 cfg80211_mgmt_tx_status( pAdapter->dev, *cookie, buf, len, FALSE, GFP_KERNEL );
769 return 0;
770}
771
772#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
773int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
774 struct net_device *dev,
775 u64 cookie)
776{
777 return wlan_hdd_cfg80211_cancel_remain_on_channel( wiphy, dev, cookie );
778}
779#endif
780
781void hdd_sendActionCnf( hdd_adapter_t *pAdapter, tANI_BOOLEAN actionSendSuccess )
782{
783 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
784
Jeff Johnsone7245742012-09-05 17:12:55 -0700785 cfgState->actionFrmState = HDD_IDLE;
786
Jeff Johnson295189b2012-06-20 16:38:30 -0700787 hddLog( LOG1, "Send Action cnf, actionSendSuccess %d", actionSendSuccess);
788 if( NULL == cfgState->buf )
789 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700790 return;
791 }
792
793 /* If skb is NULL it means this packet was received on CFG80211 interface
794 * else it was received on Monitor interface */
795 if( cfgState->skb == NULL )
796 {
797 /*
798 * buf is the same pointer it passed us to send. Since we are sending
799 * it through control path, we use different buffers.
800 * In case of mac80211, they just push it to the skb and pass the same
801 * data while sending tx ack status.
802 * */
803 cfg80211_mgmt_tx_status( pAdapter->dev, cfgState->action_cookie,
804 cfgState->buf, cfgState->len, actionSendSuccess, GFP_KERNEL );
805 vos_mem_free( cfgState->buf );
806 cfgState->buf = NULL;
807 }
808 else
809 {
810 hdd_adapter_t* pMonAdapter =
811 hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_MONITOR );
812 if( pMonAdapter == NULL )
813 {
814 hddLog( LOGE, "Not able to get Monitor Adapter");
815 cfgState->skb = NULL;
816 vos_mem_free( cfgState->buf );
817 cfgState->buf = NULL;
818 complete(&pAdapter->tx_action_cnf_event);
819 return;
820 }
821 /* Send TX completion feedback over monitor interface. */
822 hdd_wlan_tx_complete( pMonAdapter, cfgState, actionSendSuccess );
823 cfgState->skb = NULL;
824 vos_mem_free( cfgState->buf );
825 cfgState->buf = NULL;
826 /* Look for the next Mgmt packet to TX */
827 hdd_mon_tx_mgmt_pkt(pAdapter);
828 }
829 complete(&pAdapter->tx_action_cnf_event);
830}
831
832/**
833 * hdd_setP2pNoa
834 *
835 *FUNCTION:
836 * This function is called from hdd_hostapd_ioctl function when Driver
837 * get P2P_SET_NOA comand from wpa_supplicant using private ioctl
838 *
839 *LOGIC:
840 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
841 *
842 *ASSUMPTIONS:
843 *
844 *
845 *NOTE:
846 *
847 * @param dev Pointer to net device structure
848 * @param command Pointer to command
849 *
850 * @return Status
851 */
852
853int hdd_setP2pNoa( struct net_device *dev, tANI_U8 *command )
854{
855 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
856 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
857 VOS_STATUS status = VOS_STATUS_SUCCESS;
858 tP2pPsConfig NoA;
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800859 int count, duration, start_time;
Jeff Johnson295189b2012-06-20 16:38:30 -0700860 char *param;
861
Madan Mohan Koyyalamudid8ac8662012-11-06 19:04:56 -0800862 param = strnchr(command, strlen(command), ' ');
Jeff Johnson295189b2012-06-20 16:38:30 -0700863 if (param == NULL)
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -0800864 return -EINVAL;
Jeff Johnson295189b2012-06-20 16:38:30 -0700865 param++;
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800866 sscanf(param, "%d %d %d", &count, &start_time, &duration);
Jeff Johnson295189b2012-06-20 16:38:30 -0700867 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
868 "%s: P2P_SET GO NoA: count=%d duration=%d interval=%d \n",
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800869 __func__, count, start_time, duration);
870 duration = MS_TO_MUS(duration);
Jeff Johnson295189b2012-06-20 16:38:30 -0700871 /* PS Selection
872 * Periodic NoA (2)
873 * Single NOA (4)
874 */
875 NoA.opp_ps = 0;
876 NoA.ctWindow = 0;
877 if (count == 1)
878 {
879 NoA.duration = 0;
880 NoA.single_noa_duration = duration;
881 NoA.psSelection = P2P_POWER_SAVE_TYPE_SINGLE_NOA;
882 }
883 else
884 {
885 NoA.duration = duration;
886 NoA.single_noa_duration = 0;
887 NoA.psSelection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA;
888 }
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800889 NoA.interval = MS_TO_MUS(100);
Jeff Johnson295189b2012-06-20 16:38:30 -0700890 NoA.count = count;
891 NoA.sessionid = pAdapter->sessionId;
892
893 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
894 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
895 "interval %d count %d single noa duration %d "
896 "PsSelection %x \n", __func__, NoA.opp_ps,
897 NoA.ctWindow, NoA.duration, NoA.interval,
898 NoA.count, NoA.single_noa_duration,
899 NoA.psSelection);
900
901 sme_p2pSetPs(hHal, &NoA);
902 return status;
903}
904
905/**
906 * hdd_setP2pOpps
907 *
908 *FUNCTION:
909 * This function is called from hdd_hostapd_ioctl function when Driver
910 * get P2P_SET_PS comand from wpa_supplicant using private ioctl
911 *
912 *LOGIC:
913 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
914 *
915 *ASSUMPTIONS:
916 *
917 *
918 *NOTE:
919 *
920 * @param dev Pointer to net device structure
921 * @param command Pointer to command
922 *
923 * @return Status
924 */
925
926int hdd_setP2pOpps( struct net_device *dev, tANI_U8 *command )
927{
928 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
929 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
930 VOS_STATUS status = VOS_STATUS_SUCCESS;
931 tP2pPsConfig NoA;
932 char *param;
933 int legacy_ps, opp_ps, ctwindow;
934
Madan Mohan Koyyalamudid8ac8662012-11-06 19:04:56 -0800935 param = strnchr(command, strlen(command), ' ');
Jeff Johnson295189b2012-06-20 16:38:30 -0700936 if (param == NULL)
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -0800937 return -EINVAL;
Jeff Johnson295189b2012-06-20 16:38:30 -0700938 param++;
939 sscanf(param, "%d %d %d", &legacy_ps, &opp_ps, &ctwindow);
940 VOS_TRACE (VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
941 "%s: P2P_SET GO PS: legacy_ps=%d opp_ps=%d ctwindow=%d \n",
942 __func__, legacy_ps, opp_ps, ctwindow);
943
944 /* PS Selection
945 * Opportunistic Power Save (1)
946 */
947
948 /* From wpa_cli user need to use separate command to set ctWindow and Opps
949 * When user want to set ctWindow during that time other parameters
950 * values are coming from wpa_supplicant as -1.
951 * Example : User want to set ctWindow with 30 then wpa_cli command :
952 * P2P_SET ctwindow 30
953 * Command Received at hdd_hostapd_ioctl is as below:
954 * P2P_SET_PS -1 -1 30 (legacy_ps = -1, opp_ps = -1, ctwindow = 30)
955 */
956 if (ctwindow != -1)
957 {
958
959 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
960 "Opportunistic Power Save is %s \n",
961 (TRUE == pAdapter->ops) ? "Enable" : "Disable" );
962
963 if (ctwindow != pAdapter->ctw)
964 {
965 pAdapter->ctw = ctwindow;
966
967 if(pAdapter->ops)
968 {
969 NoA.opp_ps = pAdapter->ops;
970 NoA.ctWindow = pAdapter->ctw;
971 NoA.duration = 0;
972 NoA.single_noa_duration = 0;
973 NoA.interval = 0;
974 NoA.count = 0;
975 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
976 NoA.sessionid = pAdapter->sessionId;
977
978 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
979 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
980 "interval %d count %d single noa duration %d "
981 "PsSelection %x \n", __func__, NoA.opp_ps,
982 NoA.ctWindow, NoA.duration, NoA.interval,
983 NoA.count, NoA.single_noa_duration,
984 NoA.psSelection);
985
986 sme_p2pSetPs(hHal, &NoA);
987 }
988 return 0;
989 }
990 }
991
992 if (opp_ps != -1)
993 {
994 pAdapter->ops = opp_ps;
995
996 if ((opp_ps != -1) && (pAdapter->ctw))
997 {
998 NoA.opp_ps = opp_ps;
999 NoA.ctWindow = pAdapter->ctw;
1000 NoA.duration = 0;
1001 NoA.single_noa_duration = 0;
1002 NoA.interval = 0;
1003 NoA.count = 0;
1004 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
1005 NoA.sessionid = pAdapter->sessionId;
1006
1007 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
1008 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
1009 "interval %d count %d single noa duration %d "
1010 "PsSelection %x \n", __func__, NoA.opp_ps,
1011 NoA.ctWindow, NoA.duration, NoA.interval,
1012 NoA.count, NoA.single_noa_duration,
1013 NoA.psSelection);
1014
1015 sme_p2pSetPs(hHal, &NoA);
1016 }
1017 }
1018 return status;
1019}
1020
1021int hdd_setP2pPs( struct net_device *dev, void *msgData )
1022{
1023 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1024 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
1025 VOS_STATUS status = VOS_STATUS_SUCCESS;
1026 tP2pPsConfig NoA;
1027 p2p_app_setP2pPs_t *pappNoA = (p2p_app_setP2pPs_t *) msgData;
1028
1029 NoA.opp_ps = pappNoA->opp_ps;
1030 NoA.ctWindow = pappNoA->ctWindow;
1031 NoA.duration = pappNoA->duration;
1032 NoA.interval = pappNoA->interval;
1033 NoA.count = pappNoA->count;
1034 NoA.single_noa_duration = pappNoA->single_noa_duration;
1035 NoA.psSelection = pappNoA->psSelection;
1036 NoA.sessionid = pAdapter->sessionId;
1037
1038 sme_p2pSetPs(hHal, &NoA);
1039 return status;
1040}
1041#endif
1042
1043static tANI_U8 wlan_hdd_get_session_type( enum nl80211_iftype type )
1044{
1045 tANI_U8 sessionType;
1046
1047 switch( type )
1048 {
1049 case NL80211_IFTYPE_AP:
1050 sessionType = WLAN_HDD_SOFTAP;
1051 break;
1052 case NL80211_IFTYPE_P2P_GO:
1053 sessionType = WLAN_HDD_P2P_GO;
1054 break;
1055 case NL80211_IFTYPE_P2P_CLIENT:
1056 sessionType = WLAN_HDD_P2P_CLIENT;
1057 break;
1058 case NL80211_IFTYPE_STATION:
1059 sessionType = WLAN_HDD_INFRA_STATION;
1060 break;
1061 case NL80211_IFTYPE_MONITOR:
1062 sessionType = WLAN_HDD_MONITOR;
1063 break;
1064 default:
1065 sessionType = WLAN_HDD_INFRA_STATION;
1066 break;
1067 }
1068
1069 return sessionType;
1070}
1071
1072#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1073struct net_device* wlan_hdd_add_virtual_intf(
1074 struct wiphy *wiphy, char *name, enum nl80211_iftype type,
1075 u32 *flags, struct vif_params *params )
1076#else
1077int wlan_hdd_add_virtual_intf( struct wiphy *wiphy, char *name,
1078 enum nl80211_iftype type,
1079 u32 *flags, struct vif_params *params )
1080#endif
1081{
1082 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
1083 hdd_adapter_t* pAdapter = NULL;
1084
1085 ENTER();
1086
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001087 if(hdd_get_adapter(pHddCtx, wlan_hdd_get_session_type(type)) != NULL)
1088 {
Jeff Johnsond13512a2012-07-17 11:42:19 -07001089 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Interface type %d already exists. Two"
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001090 "interfaces of same type are not supported currently.",__func__, type);
Jeff Johnsond13512a2012-07-17 11:42:19 -07001091 return NULL;
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001092 }
1093
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -07001094 if (pHddCtx->isLogpInProgress)
1095 {
1096 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1097 "%s:LOGP in Progress. Ignore!!!", __func__);
1098#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1099 return NULL;
1100#else
1101 return -EAGAIN;
1102#endif
1103 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001104 if ( pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated )
1105 {
1106 if( (NL80211_IFTYPE_P2P_GO == type) ||
1107 (NL80211_IFTYPE_P2P_CLIENT == type) )
1108 {
1109 /* Generate the P2P Interface Address. this address must be
1110 * different from the P2P Device Address.
1111 */
1112 v_MACADDR_t p2pDeviceAddress = pHddCtx->p2pDeviceAddress;
1113 p2pDeviceAddress.bytes[4] ^= 0x80;
1114 pAdapter = hdd_open_adapter( pHddCtx,
1115 wlan_hdd_get_session_type(type),
1116 name, p2pDeviceAddress.bytes,
1117 VOS_TRUE );
1118 }
1119 }
1120 else
1121 {
1122 pAdapter = hdd_open_adapter( pHddCtx, wlan_hdd_get_session_type(type),
1123 name, wlan_hdd_get_intf_addr(pHddCtx), VOS_TRUE );
1124 }
1125
1126 if( NULL == pAdapter)
1127 {
1128 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: hdd_open_adapter failed",__func__);
1129#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1130 return NULL;
1131#else
1132 return -EINVAL;
1133#endif
1134 }
1135 EXIT();
1136#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1137 return pAdapter->dev;
1138#else
1139 return 0;
1140#endif
1141}
1142
1143int wlan_hdd_del_virtual_intf( struct wiphy *wiphy, struct net_device *dev )
1144{
1145 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
1146 hdd_adapter_t *pVirtAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1147 ENTER();
1148
1149 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
1150 __func__,pVirtAdapter->device_mode);
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -07001151 if (pHddCtx->isLogpInProgress)
1152 {
1153 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1154 "%s:LOGP in Progress. Ignore!!!", __func__);
1155 return -EAGAIN;
1156 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001157
1158 wlan_hdd_release_intf_addr( pHddCtx,
1159 pVirtAdapter->macAddressCurrent.bytes );
1160
1161 hdd_stop_adapter( pHddCtx, pVirtAdapter );
1162 hdd_close_adapter( pHddCtx, pVirtAdapter, TRUE );
1163 EXIT();
1164 return 0;
1165}
1166
1167void hdd_sendMgmtFrameOverMonitorIface( hdd_adapter_t *pMonAdapter,
1168 tANI_U32 nFrameLength, tANI_U8* pbFrames,
1169 tANI_U8 frameType )
1170{
1171 //Indicate a Frame over Monitor Intf.
1172 int rxstat;
1173 struct sk_buff *skb = NULL;
1174 int needed_headroom = 0;
1175 int flag = HDD_RX_FLAG_IV_STRIPPED | HDD_RX_FLAG_DECRYPTED |
1176 HDD_RX_FLAG_MMIC_STRIPPED;
Jeff Johnsone7245742012-09-05 17:12:55 -07001177#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1178 hdd_context_t* pHddCtx = (hdd_context_t*)(pMonAdapter->pHddCtx);
1179#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001180 hddLog( LOG1, FL("Indicate Frame over Monitor Intf"));
1181
1182 VOS_ASSERT( (pbFrames != NULL) );
1183
1184 /* room for the radiotap header based on driver features
1185 * 1 Byte for RADIO TAP Flag, 1 Byte padding and 2 Byte for
1186 * RX flags.
1187 * */
1188 needed_headroom = sizeof(struct ieee80211_radiotap_header) + 4;
1189
1190 //alloc skb here
1191 skb = alloc_skb(VPKT_SIZE_BUFFER, GFP_ATOMIC);
1192 if (unlikely(NULL == skb))
1193 {
1194 hddLog( LOGW, FL("Unable to allocate skb"));
1195 return;
1196 }
1197 skb_reserve(skb, VPKT_SIZE_BUFFER);
1198 if (unlikely(skb_headroom(skb) < nFrameLength))
1199 {
1200 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
1201 "HDD [%d]: Insufficient headroom, "
1202 "head[%p], data[%p], req[%d]",
1203 __LINE__, skb->head, skb->data, nFrameLength);
1204 kfree_skb(skb);
1205 return ;
1206 }
1207 // actually push the data
1208 memcpy(skb_push(skb, nFrameLength), pbFrames, nFrameLength);
1209 /* prepend radiotap information */
1210 if( 0 != hdd_wlan_add_rx_radiotap_hdr( skb, needed_headroom, flag ) )
1211 {
1212 hddLog( LOGE, FL("Not Able Add Radio Tap"));
1213 //free skb
1214 kfree_skb(skb);
1215 return ;
1216 }
1217
1218 skb_reset_mac_header( skb );
1219 skb->dev = pMonAdapter->dev;
1220 skb->protocol = eth_type_trans( skb, skb->dev );
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001221 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnsone7245742012-09-05 17:12:55 -07001222#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1223 wake_lock_timeout(&pHddCtx->rx_wake_lock, HDD_WAKE_LOCK_DURATION);
1224#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001225 rxstat = netif_rx_ni(skb);
1226 if( NET_RX_SUCCESS == rxstat )
1227 {
1228 hddLog( LOG1, FL("Success"));
1229 }
1230 else
1231 hddLog( LOGE, FL("Failed %d"), rxstat);
1232
1233 return ;
1234}
1235
1236void hdd_indicateMgmtFrame( hdd_adapter_t *pAdapter,
1237 tANI_U32 nFrameLength,
1238 tANI_U8* pbFrames,
1239 tANI_U8 frameType,
1240 tANI_U32 rxChan )
1241{
1242 tANI_U16 freq;
Jeff Johnsone7245742012-09-05 17:12:55 -07001243 tANI_U8 type = 0;
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001244 tANI_U8 subType = 0;
Jeff Johnsone7245742012-09-05 17:12:55 -07001245 tActionFrmType actionFrmType;
1246 hdd_cfg80211_state_t *cfgState = NULL;
Jeff Johnson295189b2012-06-20 16:38:30 -07001247
1248 hddLog(VOS_TRACE_LEVEL_INFO, "%s: Frame Type = %d Frame Length = %d\n",
1249 __func__, frameType, nFrameLength);
1250
1251 if (NULL == pAdapter)
1252 {
1253 hddLog( LOGE, FL("pAdapter is NULL"));
1254 return;
1255 }
1256
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001257 type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]);
1258 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]);
1259
1260 /* Get pAdapter from Destination mac address of the frame */
1261 if ((type == SIR_MAC_MGMT_FRAME) &&
1262 (subType != SIR_MAC_MGMT_PROBE_REQ))
1263 {
1264 pAdapter = hdd_get_adapter_by_macaddr( WLAN_HDD_GET_CTX(pAdapter),
1265 &pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET]);
1266 if (NULL == pAdapter)
1267 {
1268 /* Under assumtion that we don't receive any action frame
1269 * with BCST as destination we dropping action frame
1270 */
Madan Mohan Koyyalamudi051ff0b2012-12-03 16:55:26 -08001271 hddLog(VOS_TRACE_LEVEL_FATAL,"pAdapter for action frame is NULL Macaddr = "
1272 MAC_ADDRESS_STR ,
1273 MAC_ADDR_ARRAY(&pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET]));
1274 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Frame Type = %d Frame Length = %d"
1275 " subType = %d \n",__func__,frameType,nFrameLength,subType);
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001276 return;
1277 }
1278 }
1279
Jeff Johnson295189b2012-06-20 16:38:30 -07001280 if (NULL == pAdapter->dev)
1281 {
1282 hddLog( LOGE, FL("pAdapter->dev is NULL"));
1283 return;
1284 }
1285
1286 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
1287 {
1288 hddLog( LOGE, FL("pAdapter has invalid magic"));
1289 return;
1290 }
1291
1292 if( !nFrameLength )
1293 {
1294 hddLog( LOGE, FL("Frame Length is Invalid ZERO"));
1295 return;
1296 }
1297
Madan Mohan Koyyalamudic75be962012-10-18 19:19:03 -07001298 if (NULL == pbFrames) {
1299 hddLog( LOGE, FL("pbFrames is NULL"));
1300 return;
1301 }
1302
1303
Jeff Johnson295189b2012-06-20 16:38:30 -07001304 if( ( WLAN_HDD_SOFTAP == pAdapter->device_mode )
1305 || ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
1306 )
1307 {
1308 hdd_adapter_t *pMonAdapter =
1309 hdd_get_mon_adapter( WLAN_HDD_GET_CTX(pAdapter) );
1310
1311 if( NULL != pMonAdapter )
1312 {
1313 hddLog( LOG1, FL("Indicate Frame over Monitor Interface"));
1314 hdd_sendMgmtFrameOverMonitorIface( pMonAdapter, nFrameLength,
1315 pbFrames, frameType);
1316 return;
1317 }
1318 }
1319
1320 //Channel indicated may be wrong. TODO
1321 //Indicate an action frame.
1322 if( rxChan <= MAX_NO_OF_2_4_CHANNELS )
1323 {
1324 freq = ieee80211_channel_to_frequency( rxChan,
1325 IEEE80211_BAND_2GHZ);
1326 }
1327 else
1328 {
1329 freq = ieee80211_channel_to_frequency( rxChan,
1330 IEEE80211_BAND_5GHZ);
1331 }
1332
Jeff Johnsone7245742012-09-05 17:12:55 -07001333 cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
1334
1335 if ((type == SIR_MAC_MGMT_FRAME) &&
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001336 (subType == SIR_MAC_MGMT_ACTION))
Jeff Johnsone7245742012-09-05 17:12:55 -07001337 {
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001338 if(pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME)
1339 {
1340 // public action frame
1341 if((pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+1] == SIR_MAC_ACTION_VENDOR_SPECIFIC) &&
1342 !vos_mem_compare(&pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+2], SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE))
1343 // P2P action frames
1344 {
1345 actionFrmType = pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
1346 hddLog(LOG1, "Rx Action Frame %u \n", actionFrmType);
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -07001347#ifdef WLAN_FEATURE_P2P_DEBUG
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001348 if(actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE)
1349 {
1350 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] unknown[%d] <--- OTA",
1351 actionFrmType);
1352 }
1353 else
1354 {
1355 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] %s <--- OTA",
1356 p2p_action_frame_type[actionFrmType]);
1357 if( (actionFrmType == WLAN_HDD_PROV_DIS_REQ) &&
1358 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
1359 {
1360 globalP2PConnectionStatus = P2P_GO_NEG_PROCESS;
1361 hddLog(LOGE,"[P2P State]Inactive state to "
Jeff Johnson1250df42012-12-10 14:31:52 -08001362 "GO negotiation progress state");
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001363 }
1364 else if( (actionFrmType == WLAN_HDD_GO_NEG_CNF) &&
1365 (globalP2PConnectionStatus == P2P_GO_NEG_PROCESS) )
1366 {
1367 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
Jeff Johnson1250df42012-12-10 14:31:52 -08001368 hddLog(LOGE,"[P2P State]GO negotiation progress to "
1369 "GO negotiation completed state");
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001370 }
1371 else if( (actionFrmType == WLAN_HDD_INVITATION_REQ) &&
1372 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
1373 {
1374 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
1375 hddLog(LOGE,"[P2P State]Inactive state to GO negotiation"
1376 " completed state Autonomous GO formation");
1377 }
1378 }
1379#endif
1380
1381 if (((actionFrmType == WLAN_HDD_PROV_DIS_RESP) &&
1382 (cfgState->actionFrmState == HDD_PD_REQ_ACK_PENDING)) ||
1383 ((actionFrmType == WLAN_HDD_GO_NEG_RESP) &&
1384 (cfgState->actionFrmState == HDD_GO_NEG_REQ_ACK_PENDING)))
1385 {
1386 hddLog(LOG1, "%s: ACK_PENDING and But received RESP for Action frame ",
1387 __func__);
1388 hdd_sendActionCnf(pAdapter, TRUE);
1389 }
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -07001390 }
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001391#ifdef WLAN_FEATURE_TDLS_DEBUG
1392 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 -07001393 {
Hoonki Lee1090c6a2013-01-16 17:40:54 -08001394 hddLog(VOS_TRACE_LEVEL_ERROR,"[TDLS] TDLS Discovery Response <--- OTA");
1395 }
1396#endif
1397 }
1398#ifdef WLAN_FEATURE_TDLS_DEBUG
1399 if(pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_TDLS_ACTION_FRAME)
1400 {
1401 actionFrmType = pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+1];
1402 if(actionFrmType >= MAX_TDLS_ACTION_FRAME_TYPE)
1403 {
1404 hddLog(VOS_TRACE_LEVEL_ERROR,"[TDLS] unknown[%d] <--- OTA",
1405 actionFrmType);
1406 }
1407 else
1408 {
1409 hddLog(VOS_TRACE_LEVEL_ERROR,"[TDLS] %s <--- OTA",
1410 tdls_action_frame_type[actionFrmType]);
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -07001411 }
1412 }
1413#endif
Jeff Johnsone7245742012-09-05 17:12:55 -07001414 }
1415
Jeff Johnson295189b2012-06-20 16:38:30 -07001416 //Indicate Frame Over Normal Interface
1417 hddLog( LOG1, FL("Indicate Frame over NL80211 Interface"));
1418
1419#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0))
1420 cfg80211_rx_mgmt( pAdapter->dev, freq, 0,
1421 pbFrames, nFrameLength,
1422 GFP_ATOMIC );
1423#else
1424 cfg80211_rx_mgmt( pAdapter->dev, freq,
1425 pbFrames, nFrameLength,
1426 GFP_ATOMIC );
1427#endif //LINUX_VERSION_CODE
1428}
1429
1430/*
1431 * ieee80211_add_rx_radiotap_header - add radiotap header
1432 */
1433static int hdd_wlan_add_rx_radiotap_hdr (
1434 struct sk_buff *skb, int rtap_len, int flag )
1435{
1436 u8 rtap_temp[20] = {0};
1437 struct ieee80211_radiotap_header *rthdr;
1438 unsigned char *pos;
1439 u16 rx_flags = 0;
1440
1441 rthdr = (struct ieee80211_radiotap_header *)(&rtap_temp[0]);
1442
1443 /* radiotap header, set always present flags */
1444 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
1445 (1 << IEEE80211_RADIOTAP_RX_FLAGS));
1446 rthdr->it_len = cpu_to_le16(rtap_len);
1447
1448 pos = (unsigned char *) (rthdr + 1);
1449
1450 /* the order of the following fields is important */
1451
1452 /* IEEE80211_RADIOTAP_FLAGS */
1453 *pos = 0;
1454 pos++;
1455
1456 /* IEEE80211_RADIOTAP_RX_FLAGS: Length 2 Bytes */
1457 /* ensure 2 byte alignment for the 2 byte field as required */
1458 if ((pos - (u8 *)rthdr) & 1)
1459 pos++;
1460 put_unaligned_le16(rx_flags, pos);
1461 pos += 2;
1462
1463 // actually push the data
1464 memcpy(skb_push(skb, rtap_len), &rtap_temp[0], rtap_len);
1465
1466 return 0;
1467}
1468
1469static void hdd_wlan_tx_complete( hdd_adapter_t* pAdapter,
1470 hdd_cfg80211_state_t* cfgState,
1471 tANI_BOOLEAN actionSendSuccess )
1472{
1473 struct ieee80211_radiotap_header *rthdr;
1474 unsigned char *pos;
1475 struct sk_buff *skb = cfgState->skb;
Jeff Johnsone7245742012-09-05 17:12:55 -07001476#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1477 hdd_context_t *pHddCtx = (hdd_context_t*)(pAdapter->pHddCtx);
1478#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001479
1480 /* 2 Byte for TX flags and 1 Byte for Retry count */
1481 u32 rtHdrLen = sizeof(*rthdr) + 3;
1482
1483 u8 *data;
1484
1485 /* We have to return skb with Data starting with MAC header. We have
1486 * copied SKB data starting with MAC header to cfgState->buf. We will pull
1487 * entire skb->len from skb and then we will push cfgState->buf to skb
1488 * */
1489 if( NULL == skb_pull(skb, skb->len) )
1490 {
1491 hddLog( LOGE, FL("Not Able to Pull %d byte from skb"), skb->len);
1492 kfree_skb(cfgState->skb);
1493 return;
1494 }
1495
1496 data = skb_push( skb, cfgState->len );
1497
1498 if (data == NULL)
1499 {
1500 hddLog( LOGE, FL("Not Able to Push %d byte to skb"), cfgState->len);
1501 kfree_skb( cfgState->skb );
1502 return;
1503 }
1504
1505 memcpy( data, cfgState->buf, cfgState->len );
1506
1507 /* send frame to monitor interfaces now */
1508 if( skb_headroom(skb) < rtHdrLen )
1509 {
1510 hddLog( LOGE, FL("No headroom for rtap header"));
1511 kfree_skb(cfgState->skb);
1512 return;
1513 }
1514
1515 rthdr = (struct ieee80211_radiotap_header*) skb_push( skb, rtHdrLen );
1516
1517 memset( rthdr, 0, rtHdrLen );
1518 rthdr->it_len = cpu_to_le16( rtHdrLen );
1519 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
1520 (1 << IEEE80211_RADIOTAP_DATA_RETRIES)
1521 );
1522
1523 pos = (unsigned char *)( rthdr+1 );
1524
1525 // Fill TX flags
1526 *pos = actionSendSuccess;
1527 pos += 2;
1528
1529 // Fill retry count
1530 *pos = 0;
1531 pos++;
1532
1533 skb_set_mac_header( skb, 0 );
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001534 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnson295189b2012-06-20 16:38:30 -07001535 skb->pkt_type = PACKET_OTHERHOST;
1536 skb->protocol = htons(ETH_P_802_2);
1537 memset( skb->cb, 0, sizeof( skb->cb ) );
Jeff Johnsone7245742012-09-05 17:12:55 -07001538#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1539 wake_lock_timeout(&pHddCtx->rx_wake_lock, HDD_WAKE_LOCK_DURATION);
1540#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001541 if (in_interrupt())
1542 netif_rx( skb );
1543 else
1544 netif_rx_ni( skb );
1545
1546 /* Enable Queues which we have disabled earlier */
1547 netif_tx_start_all_queues( pAdapter->dev );
1548
1549}
1550#endif // CONFIG_CFG80211