blob: e5eecde1c7baea59566ae692028dd13d14763897 [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
Jeff Johnson32d95a32012-09-10 13:15:23 -07002 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
Jeff Johnson295189b2012-06-20 16:38:30 -07003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/**========================================================================
23
24 \file wlan_hdd_p2p.c
25
26 \brief WLAN Host Device Driver implementation for P2P commands interface
27
28 Copyright 2008 (c) Qualcomm, Incorporated. All Rights Reserved.
29
30 Qualcomm Confidential and Proprietary.
31
32 ========================================================================*/
33#ifdef CONFIG_CFG80211
34
35#include <wlan_hdd_includes.h>
36#include <wlan_hdd_hostapd.h>
37#include <net/cfg80211.h>
38#include "sme_Api.h"
39#include "wlan_hdd_p2p.h"
40#include "sapApi.h"
41
42#include <linux/netdevice.h>
43#include <linux/skbuff.h>
44#include <linux/etherdevice.h>
45#include <net/ieee80211_radiotap.h>
46
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -080047//Ms to Micro Sec
48#define MS_TO_MUS(x) ((x)*1000);
49
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -070050#ifdef WLAN_FEATURE_P2P_DEBUG
51#define MAX_P2P_ACTION_FRAME_TYPE 9
52const char *p2p_action_frame_type[]={"GO Negotiation Request",
53 "GO Negotiation Response",
54 "GO Negotiation Confirmation",
55 "P2P Invitation Request",
56 "P2P Invitation Response",
57 "Device Discoverability Request",
58 "Device Discoverability Response",
59 "Provision Discovery Request",
60 "Provision Discovery Response"};
61
62/* We no need to protect this variable since
63 * there is no chance of race to condition
64 * and also not make any complicating the code
65 * just for debugging log
66 */
67tP2PConnectionStatus globalP2PConnectionStatus = P2P_NOT_ACTIVE;
68
69#endif
70
Jeff Johnson295189b2012-06-20 16:38:30 -070071extern struct net_device_ops net_ops_struct;
72
73static int hdd_wlan_add_rx_radiotap_hdr( struct sk_buff *skb,
74 int rtap_len, int flag );
75
76static void hdd_wlan_tx_complete( hdd_adapter_t* pAdapter,
77 hdd_cfg80211_state_t* cfgState,
78 tANI_BOOLEAN actionSendSuccess );
79
80static void hdd_sendMgmtFrameOverMonitorIface( hdd_adapter_t *pMonAdapter,
81 tANI_U32 nFrameLength,
82 tANI_U8* pbFrames,
83 tANI_U8 frameType );
84
85#ifdef WLAN_FEATURE_P2P
86eHalStatus wlan_hdd_remain_on_channel_callback( tHalHandle hHal, void* pCtx,
87 eHalStatus status )
88{
89 hdd_adapter_t *pAdapter = (hdd_adapter_t*) pCtx;
Jeff Johnson295189b2012-06-20 16:38:30 -070090 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
91 hdd_remain_on_chan_ctx_t *pRemainChanCtx = cfgState->remain_on_chan_ctx;
92
93 if( pRemainChanCtx == NULL )
94 {
95 hddLog( LOGW,
96 "%s: No Rem on channel pending for which Rsp is received", __func__);
97 return eHAL_STATUS_SUCCESS;
98 }
99
100 hddLog( LOG1, "Received remain on channel rsp");
101
102 cfgState->remain_on_chan_ctx = NULL;
103
104 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
105 {
106 if( cfgState->buf )
107 {
108 hddLog( LOGP,
109 "%s: We need to receive yet an ack from one of tx packet",
110 __func__);
111 }
112 cfg80211_remain_on_channel_expired( pRemainChanCtx->dev,
113 pRemainChanCtx->cookie,
114 &pRemainChanCtx->chan,
115 pRemainChanCtx->chan_type, GFP_KERNEL );
116 }
117
118 vos_mem_free( pRemainChanCtx );
119
120 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700121 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
122 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700123 )
124 {
125 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700126 sme_DeregisterMgmtFrame(
127 hHal, sessionId,
128 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
129 NULL, 0 );
130 }
131 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
132 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
133 )
134 {
135 WLANSAP_DeRegisterMgmtFrame(
136 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
137 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
138 NULL, 0 );
139 }
140
141 complete(&pAdapter->cancel_rem_on_chan_var);
142 return eHAL_STATUS_SUCCESS;
143}
144
Jeff Johnson32d95a32012-09-10 13:15:23 -0700145static void wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter)
Jeff Johnson295189b2012-06-20 16:38:30 -0700146{
Jeff Johnson295189b2012-06-20 16:38:30 -0700147 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
148 int status = 0;
Jeff Johnson295189b2012-06-20 16:38:30 -0700149
Jeff Johnson32d95a32012-09-10 13:15:23 -0700150 if(cfgState->remain_on_chan_ctx != NULL)
Jeff Johnson295189b2012-06-20 16:38:30 -0700151 {
Jeff Johnson32d95a32012-09-10 13:15:23 -0700152 hddLog( LOG1, "Cancel Existing Remain on Channel");
153
154 /* Wait till remain on channel ready indication before issuing cancel
155 * remain on channel request, otherwise if remain on channel not
156 * received and if the driver issues cancel remain on channel then lim
Jeff Johnson295189b2012-06-20 16:38:30 -0700157 * will be in unknown state.
158 */
159 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
160 msecs_to_jiffies(WAIT_REM_CHAN_READY));
161 if (!status)
162 {
163 hddLog( LOGE,
164 "%s: timeout waiting for remain on channel ready indication",
165 __func__);
166 }
167
168 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
Jeff Johnson32d95a32012-09-10 13:15:23 -0700169
Jeff Johnson295189b2012-06-20 16:38:30 -0700170 /* Issue abort remain on chan request to sme.
171 * The remain on channel callback will make sure the remain_on_chan
172 * expired event is sent.
173 */
174 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700175 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
176 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700177 )
178 {
179 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
180 pAdapter->sessionId );
181 }
182 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
183 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
184 )
185 {
186 WLANSAP_CancelRemainOnChannel(
187 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
188 }
Jeff Johnsone7245742012-09-05 17:12:55 -0700189
Jeff Johnson32d95a32012-09-10 13:15:23 -0700190 status = wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
Jeff Johnson295189b2012-06-20 16:38:30 -0700191 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
Jeff Johnson32d95a32012-09-10 13:15:23 -0700192
193 if (!status)
194 {
195 hddLog( LOGE,
196 "%s: timeout waiting for cancel remain on channel ready indication",
197 __func__);
198 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700199 }
Jeff Johnson32d95a32012-09-10 13:15:23 -0700200}
201
202int wlan_hdd_check_remain_on_channel(hdd_adapter_t *pAdapter)
203{
204 int status = 0;
205 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
206
207 if(WLAN_HDD_P2P_GO != pAdapter->device_mode)
208 {
209 //Cancel Existing Remain On Channel
210 //If no action frame is pending
211 if( cfgState->remain_on_chan_ctx != NULL)
212 {
213 //Check whether Action Frame is pending or not
214 if( cfgState->buf == NULL)
215 {
216 wlan_hdd_cancel_existing_remain_on_channel(pAdapter);
217 }
218 else
219 {
220 hddLog( LOG1, "Cannot Cancel Existing Remain on Channel");
221 status = -EBUSY;
222 }
223 }
224 }
225 return status;
226}
227
228static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy,
229 struct net_device *dev,
230 struct ieee80211_channel *chan,
231 enum nl80211_channel_type channel_type,
232 unsigned int duration, u64 *cookie,
233 rem_on_channel_request_type_t request_type )
234{
235 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
236 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
237 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
238 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
239 __func__,pAdapter->device_mode);
240
241 hddLog( LOG1,
242 "chan(hw_val)0x%x chan(centerfreq) %d chan type 0x%x, duration %d",
243 chan->hw_value, chan->center_freq, channel_type, duration );
244
245 //Cancel existing remain On Channel if any
246 wlan_hdd_cancel_existing_remain_on_channel(pAdapter);
Jeff Johnson295189b2012-06-20 16:38:30 -0700247
Jeff Johnsone7245742012-09-05 17:12:55 -0700248 /* When P2P-GO and if we are trying to unload the driver then
Jeff Johnson295189b2012-06-20 16:38:30 -0700249 * wlan driver is keep on receiving the remain on channel command
Jeff Johnsone7245742012-09-05 17:12:55 -0700250 * and which is resulting in crash. So not allowing any remain on
Jeff Johnson295189b2012-06-20 16:38:30 -0700251 * channel requets when Load/Unload is in progress*/
252 if (((hdd_context_t*)pAdapter->pHddCtx)->isLoadUnloadInProgress)
253 {
254 hddLog( LOGE,
255 "%s: Wlan Load/Unload is in progress", __func__);
256 return -EBUSY;
257 }
258
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700259 if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress)
260 {
261 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
262 "%s:LOGP in Progress. Ignore!!!", __func__);
263 return -EAGAIN;
264 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700265 pRemainChanCtx = vos_mem_malloc( sizeof(hdd_remain_on_chan_ctx_t) );
266 if( NULL == pRemainChanCtx )
267 {
268 hddLog(VOS_TRACE_LEVEL_FATAL,
269 "%s: Not able to allocate memory for Channel context",
270 __func__);
271 return -ENOMEM;
272 }
273
274 vos_mem_copy( &pRemainChanCtx->chan, chan,
275 sizeof(struct ieee80211_channel) );
276
277 pRemainChanCtx->chan_type = channel_type;
278 pRemainChanCtx->duration = duration;
279 pRemainChanCtx->dev = dev;
280 *cookie = (tANI_U32) pRemainChanCtx;
281 pRemainChanCtx->cookie = *cookie;
282 pRemainChanCtx->rem_on_chan_request = request_type;
283 cfgState->remain_on_chan_ctx = pRemainChanCtx;
284 cfgState->current_freq = chan->center_freq;
285
286 INIT_COMPLETION(pAdapter->rem_on_chan_ready_event);
287
288 //call sme API to start remain on channel.
289 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700290 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
291 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700292 )
293 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700294 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700295 //call sme API to start remain on channel.
296 sme_RemainOnChannel(
297 WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId,
298 chan->hw_value, duration,
299 wlan_hdd_remain_on_channel_callback, pAdapter );
300
301 sme_RegisterMgmtFrame(WLAN_HDD_GET_HAL_CTX(pAdapter),
302 sessionId, (SIR_MAC_MGMT_FRAME << 2) |
303 (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0 );
304
305 }
306 else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
307 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
308 )
309 {
310 //call sme API to start remain on channel.
Jeff Johnson43971f52012-07-17 12:26:56 -0700311 if (VOS_STATUS_SUCCESS != WLANSAP_RemainOnChannel(
Jeff Johnson295189b2012-06-20 16:38:30 -0700312 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
313 chan->hw_value, duration,
314 wlan_hdd_remain_on_channel_callback, pAdapter ))
315
316 {
317 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
318 "%s: WLANSAP_RemainOnChannel returned fail", __func__);
319 cfgState->remain_on_chan_ctx = NULL;
Jeff Johnsone7245742012-09-05 17:12:55 -0700320 vos_mem_free (pRemainChanCtx);
Jeff Johnson295189b2012-06-20 16:38:30 -0700321 return -EINVAL;
322 }
323
324
Jeff Johnson43971f52012-07-17 12:26:56 -0700325 if (VOS_STATUS_SUCCESS != WLANSAP_RegisterMgmtFrame(
Jeff Johnson295189b2012-06-20 16:38:30 -0700326 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
327 (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
328 NULL, 0 ))
329 {
330 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
331 "%s: WLANSAP_RegisterMgmtFrame returned fail", __func__);
332 WLANSAP_CancelRemainOnChannel(
333 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
334 return -EINVAL;
335 }
336
337 }
338 return 0;
339
340}
341
342int wlan_hdd_cfg80211_remain_on_channel( struct wiphy *wiphy,
343 struct net_device *dev,
344 struct ieee80211_channel *chan,
345 enum nl80211_channel_type channel_type,
346 unsigned int duration, u64 *cookie )
347{
348 return wlan_hdd_request_remain_on_channel(wiphy, dev,
349 chan, channel_type, duration, cookie,
350 REMAIN_ON_CHANNEL_REQUEST);
351}
352
353void hdd_remainChanReadyHandler( hdd_adapter_t *pAdapter )
354{
355 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
356 hdd_remain_on_chan_ctx_t* pRemainChanCtx = cfgState->remain_on_chan_ctx;
357
358 hddLog( LOG1, "Ready on chan ind");
359
360 if( pRemainChanCtx != NULL )
361 {
362 if( REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request )
363 {
364 cfg80211_ready_on_channel( pAdapter->dev, (tANI_U32)pRemainChanCtx,
365 &pRemainChanCtx->chan, pRemainChanCtx->chan_type,
366 pRemainChanCtx->duration, GFP_KERNEL );
367 }
368#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
369 else if( OFF_CHANNEL_ACTION_TX == pRemainChanCtx->rem_on_chan_request )
370 {
371 complete(&pAdapter->offchannel_tx_event);
372 }
373#endif
374 complete(&pAdapter->rem_on_chan_ready_event);
375 }
376 else
377 {
378 hddLog( LOGW, "%s: No Pending Remain on channel Request", __func__);
379 }
380 return;
381}
382
383int wlan_hdd_cfg80211_cancel_remain_on_channel( struct wiphy *wiphy,
384 struct net_device *dev, u64 cookie )
385{
386 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson295189b2012-06-20 16:38:30 -0700387 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
388 int status = 0;
389
390 hddLog( LOG1, "Cancel remain on channel req");
391
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -0700392 if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress)
393 {
394 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
395 "%s:LOGP in Progress. Ignore!!!", __func__);
396 return -EAGAIN;
397 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700398 /* FIXME cancel currently running remain on chan.
399 * Need to check cookie and cancel accordingly
400 */
401 if( (cfgState->remain_on_chan_ctx == NULL) ||
402 (cfgState->remain_on_chan_ctx->cookie != cookie) )
403 {
404 hddLog( LOGE,
405 "%s: No Remain on channel pending with specified cookie value",
406 __func__);
407 return -EINVAL;
408 }
409
410 /* wait until remain on channel ready event received
411 * for already issued remain on channel request */
412 status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event,
413 msecs_to_jiffies(WAIT_REM_CHAN_READY));
414 if (!status)
415 {
416 hddLog( LOGE,
417 "%s: timeout waiting for remain on channel ready indication",
418 __func__);
419 }
420 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
421 /* Issue abort remain on chan request to sme.
422 * The remain on channel callback will make sure the remain_on_chan
423 * expired event is sent.
424 */
425 if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700426 ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
427 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700428 )
429 {
430 tANI_U8 sessionId = pAdapter->sessionId;
Jeff Johnson295189b2012-06-20 16:38:30 -0700431 sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
432 sessionId );
433 }
434 else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) ||
435 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
436 )
437 {
438 WLANSAP_CancelRemainOnChannel(
439 (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
440 }
441 else
442 {
443 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Invalid device_mode = %d",
444 __func__, pAdapter->device_mode);
445 return -EIO;
446 }
447 wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var,
448 msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
449 return 0;
450}
451
452#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
453int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
454 struct ieee80211_channel *chan, bool offchan,
455 enum nl80211_channel_type channel_type,
456 bool channel_type_valid, unsigned int wait,
457 const u8 *buf, size_t len, bool no_cck,
458 bool dont_wait_for_ack, u64 *cookie )
459#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
460int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
461 struct ieee80211_channel *chan, bool offchan,
462 enum nl80211_channel_type channel_type,
463 bool channel_type_valid, unsigned int wait,
464 const u8 *buf, size_t len, u64 *cookie )
465#else
466int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev,
467 struct ieee80211_channel *chan,
468 enum nl80211_channel_type channel_type,
469 bool channel_type_valid,
470 const u8 *buf, size_t len, u64 *cookie )
471#endif //LINUX_VERSION_CODE
472{
473 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR( dev );
474 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
Jeff Johnsone7245742012-09-05 17:12:55 -0700475 tANI_U16 extendedWait = 0;
476 tANI_U8 type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]);
477 tANI_U8 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]);
478 tActionFrmType actionFrmType;
479 bool noack = 0;
480
Jeff Johnson295189b2012-06-20 16:38:30 -0700481#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
482 hdd_adapter_t *goAdapter;
483#endif
484
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -0700485#ifdef WLAN_FEATURE_P2P_DEBUG
486 if ((type == SIR_MAC_MGMT_FRAME) &&
487 (subType == SIR_MAC_MGMT_ACTION) &&
488 (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
489 {
490 actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
491 if(actionFrmType > MAX_P2P_ACTION_FRAME_TYPE)
492 {
493 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] unknown[%d] ---> OTA",
494 actionFrmType);
495 }
496 else
497 {
498 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] %s ---> OTA",
499 p2p_action_frame_type[actionFrmType]);
500 if( (actionFrmType == WLAN_HDD_PROV_DIS_REQ) &&
501 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
502 {
503 globalP2PConnectionStatus = P2P_GO_NEG_PROCESS;
504 hddLog(LOGE,"[P2P State]Inactive state to "
505 "GO negotation progress state");
506 }
507 else if( (actionFrmType == WLAN_HDD_GO_NEG_CNF) &&
508 (globalP2PConnectionStatus == P2P_GO_NEG_PROCESS) )
509 {
510 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
511 hddLog(LOGE,"[P2P State]GO nego progress to GO nego"
512 " completed state");
513 }
514 }
515 }
516#endif
517
Jeff Johnsone7245742012-09-05 17:12:55 -0700518#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
519 noack = dont_wait_for_ack;
520#endif
521
522 //If the wait is coming as 0 with off channel set
523 //then set the wait to 200 ms
524 if (offchan && !wait)
525 wait = ACTION_FRAME_DEFAULT_WAIT;
526
Jeff Johnson295189b2012-06-20 16:38:30 -0700527 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
528 __func__,pAdapter->device_mode);
529
530 //Call sme API to send out a action frame.
531 // OR can we send it directly through data path??
532 // After tx completion send tx status back.
533 if ( ( WLAN_HDD_SOFTAP == pAdapter->device_mode ) ||
534 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
535 )
536 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700537 if (type == SIR_MAC_MGMT_FRAME)
538 {
539 if (subType == SIR_MAC_MGMT_PROBE_RSP)
540 {
541 /* Drop Probe response recieved from supplicant, as for GO and
542 SAP PE itself sends probe response
543 */
544 goto err_rem_channel;
545 }
546 else if ((subType == SIR_MAC_MGMT_DISASSOC) ||
547 (subType == SIR_MAC_MGMT_DEAUTH))
548 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700549 /* During EAP failure or P2P Group Remove supplicant
550 * is sending del_station command to driver. From
551 * del_station function, Driver will send deauth frame to
552 * p2p client. No need to send disassoc frame from here.
553 * so Drop the frame here and send tx indication back to
554 * supplicant.
Jeff Johnson295189b2012-06-20 16:38:30 -0700555 */
556 tANI_U8 dstMac[ETH_ALEN] = {0};
557 memcpy(&dstMac, &buf[WLAN_HDD_80211_FRM_DA_OFFSET], ETH_ALEN);
Jeff Johnsone7245742012-09-05 17:12:55 -0700558 hddLog(VOS_TRACE_LEVEL_INFO,
Jeff Johnson295189b2012-06-20 16:38:30 -0700559 "%s: Deauth/Disassoc received for STA:"
Jeff Johnsone7245742012-09-05 17:12:55 -0700560 "%02x:%02x:%02x:%02x:%02x:%02x",
561 __func__,
562 dstMac[0], dstMac[1], dstMac[2],
Jeff Johnson295189b2012-06-20 16:38:30 -0700563 dstMac[3], dstMac[4], dstMac[5]);
Jeff Johnson295189b2012-06-20 16:38:30 -0700564 goto err_rem_channel;
565 }
566 }
567 }
568
569 if( NULL != cfgState->buf )
570 return -EBUSY;
571
572 hddLog( LOG1, "Action frame tx request");
573
574#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
575 goAdapter = hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_P2P_GO );
576
577 //If GO adapter exists and operating on same frequency
578 //then we will not request remain on channel
579 if( goAdapter && ( ieee80211_frequency_to_channel(chan->center_freq)
580 == goAdapter->sessionCtx.ap.operatingChannel ) )
581 {
582 goto send_frame;
583 }
584#endif
585
586#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
587 if( offchan && wait)
588 {
589 int status;
590
591 // In case of P2P Client mode if we are already
592 // on the same channel then send the frame directly
593
594 if((cfgState->remain_on_chan_ctx != NULL) &&
595 (cfgState->current_freq == chan->center_freq)
596 )
597 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700598 hddLog(LOG1,"action frame: extending the wait time\n");
599 extendedWait = (tANI_U16)wait;
Jeff Johnson295189b2012-06-20 16:38:30 -0700600 goto send_frame;
601 }
602
603 INIT_COMPLETION(pAdapter->offchannel_tx_event);
604
605 status = wlan_hdd_request_remain_on_channel(wiphy, dev,
606 chan, channel_type, wait, cookie,
607 OFF_CHANNEL_ACTION_TX);
608
609 if(0 != status)
610 {
611 if( (-EBUSY == status) &&
612 (cfgState->current_freq == chan->center_freq) )
613 {
614 goto send_frame;
615 }
616 goto err_rem_channel;
617 }
618
619 /* Wait for driver to be ready on the requested channel */
620 status = wait_for_completion_interruptible_timeout(
621 &pAdapter->offchannel_tx_event,
622 msecs_to_jiffies(WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX));
623 if(!status)
624 {
625 hddLog( LOGE, "Not able to complete remain on channel request"
626 " within timeout period");
627 goto err_rem_channel;
628 }
629 }
630 else if ( offchan )
631 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700632 /* Check before sending action frame
633 whether we already remain on channel */
Jeff Johnson295189b2012-06-20 16:38:30 -0700634 if(NULL == cfgState->remain_on_chan_ctx)
635 {
636 goto err_rem_channel;
637 }
638 }
639 send_frame:
640#endif
641
Jeff Johnsone7245742012-09-05 17:12:55 -0700642 if(!noack)
643 {
644 cfgState->buf = vos_mem_malloc( len ); //buf;
645 if( cfgState->buf == NULL )
646 return -ENOMEM;
Jeff Johnson295189b2012-06-20 16:38:30 -0700647
Jeff Johnsone7245742012-09-05 17:12:55 -0700648 cfgState->len = len;
Jeff Johnson295189b2012-06-20 16:38:30 -0700649
Jeff Johnsone7245742012-09-05 17:12:55 -0700650 vos_mem_copy( cfgState->buf, buf, len);
Jeff Johnson295189b2012-06-20 16:38:30 -0700651
652#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnsone7245742012-09-05 17:12:55 -0700653 if( cfgState->remain_on_chan_ctx )
654 {
655 cfgState->action_cookie = cfgState->remain_on_chan_ctx->cookie;
656 *cookie = cfgState->action_cookie;
657 }
658 else
659 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700660#endif
Jeff Johnsone7245742012-09-05 17:12:55 -0700661 *cookie = (tANI_U32) cfgState->buf;
662 cfgState->action_cookie = *cookie;
Jeff Johnson295189b2012-06-20 16:38:30 -0700663#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
Jeff Johnsone7245742012-09-05 17:12:55 -0700664 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700665#endif
Jeff Johnsone7245742012-09-05 17:12:55 -0700666 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700667
668 if ( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
Jeff Johnsone7245742012-09-05 17:12:55 -0700669 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
670 ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
Jeff Johnson295189b2012-06-20 16:38:30 -0700671 )
672 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700673 tANI_U8 sessionId = pAdapter->sessionId;
674 if ((type == SIR_MAC_MGMT_FRAME) &&
675 (subType == SIR_MAC_MGMT_ACTION) &&
676 (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
Jeff Johnson295189b2012-06-20 16:38:30 -0700677 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700678 actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
679 hddLog(LOG1, "Tx Action Frame %u \n", actionFrmType);
680 if (actionFrmType == WLAN_HDD_PROV_DIS_REQ)
Jeff Johnson295189b2012-06-20 16:38:30 -0700681 {
Jeff Johnsone7245742012-09-05 17:12:55 -0700682 cfgState->actionFrmState = HDD_PD_REQ_ACK_PENDING;
683 hddLog(LOG1, "%s: HDD_PD_REQ_ACK_PENDING \n", __func__);
684 }
685 else if (actionFrmType == WLAN_HDD_GO_NEG_REQ)
686 {
687 cfgState->actionFrmState = HDD_GO_NEG_REQ_ACK_PENDING;
688 hddLog(LOG1, "%s: HDD_GO_NEG_REQ_ACK_PENDING \n", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700689 }
690 }
Jeff Johnsone7245742012-09-05 17:12:55 -0700691
Jeff Johnson295189b2012-06-20 16:38:30 -0700692 if (eHAL_STATUS_SUCCESS !=
693 sme_sendAction( WLAN_HDD_GET_HAL_CTX(pAdapter),
Jeff Johnsone7245742012-09-05 17:12:55 -0700694 sessionId, buf, len, extendedWait, noack))
Jeff Johnson295189b2012-06-20 16:38:30 -0700695 {
696 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
697 "%s: sme_sendAction returned fail", __func__);
698 goto err;
699 }
700 }
701 else if( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
702 ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
703 )
704 {
Jeff Johnson43971f52012-07-17 12:26:56 -0700705 if( VOS_STATUS_SUCCESS !=
Jeff Johnson295189b2012-06-20 16:38:30 -0700706 WLANSAP_SendAction( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
Jeff Johnsone7245742012-09-05 17:12:55 -0700707 buf, len, 0 ) )
Jeff Johnson295189b2012-06-20 16:38:30 -0700708 {
709 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
710 "%s: WLANSAP_SendAction returned fail", __func__);
711 goto err;
712 }
713 }
714
715 return 0;
716err:
Jeff Johnsone7245742012-09-05 17:12:55 -0700717 if(!noack)
718 {
719 hdd_sendActionCnf( pAdapter, FALSE );
720 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700721 return 0;
722err_rem_channel:
723 *cookie = (tANI_U32)cfgState;
724 cfg80211_mgmt_tx_status( pAdapter->dev, *cookie, buf, len, FALSE, GFP_KERNEL );
725 return 0;
726}
727
728#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
729int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
730 struct net_device *dev,
731 u64 cookie)
732{
733 return wlan_hdd_cfg80211_cancel_remain_on_channel( wiphy, dev, cookie );
734}
735#endif
736
737void hdd_sendActionCnf( hdd_adapter_t *pAdapter, tANI_BOOLEAN actionSendSuccess )
738{
739 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
740
Jeff Johnsone7245742012-09-05 17:12:55 -0700741 cfgState->actionFrmState = HDD_IDLE;
742
Jeff Johnson295189b2012-06-20 16:38:30 -0700743 hddLog( LOG1, "Send Action cnf, actionSendSuccess %d", actionSendSuccess);
744 if( NULL == cfgState->buf )
745 {
Jeff Johnson295189b2012-06-20 16:38:30 -0700746 return;
747 }
748
749 /* If skb is NULL it means this packet was received on CFG80211 interface
750 * else it was received on Monitor interface */
751 if( cfgState->skb == NULL )
752 {
753 /*
754 * buf is the same pointer it passed us to send. Since we are sending
755 * it through control path, we use different buffers.
756 * In case of mac80211, they just push it to the skb and pass the same
757 * data while sending tx ack status.
758 * */
759 cfg80211_mgmt_tx_status( pAdapter->dev, cfgState->action_cookie,
760 cfgState->buf, cfgState->len, actionSendSuccess, GFP_KERNEL );
761 vos_mem_free( cfgState->buf );
762 cfgState->buf = NULL;
763 }
764 else
765 {
766 hdd_adapter_t* pMonAdapter =
767 hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_MONITOR );
768 if( pMonAdapter == NULL )
769 {
770 hddLog( LOGE, "Not able to get Monitor Adapter");
771 cfgState->skb = NULL;
772 vos_mem_free( cfgState->buf );
773 cfgState->buf = NULL;
774 complete(&pAdapter->tx_action_cnf_event);
775 return;
776 }
777 /* Send TX completion feedback over monitor interface. */
778 hdd_wlan_tx_complete( pMonAdapter, cfgState, actionSendSuccess );
779 cfgState->skb = NULL;
780 vos_mem_free( cfgState->buf );
781 cfgState->buf = NULL;
782 /* Look for the next Mgmt packet to TX */
783 hdd_mon_tx_mgmt_pkt(pAdapter);
784 }
785 complete(&pAdapter->tx_action_cnf_event);
786}
787
788/**
789 * hdd_setP2pNoa
790 *
791 *FUNCTION:
792 * This function is called from hdd_hostapd_ioctl function when Driver
793 * get P2P_SET_NOA comand from wpa_supplicant using private ioctl
794 *
795 *LOGIC:
796 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
797 *
798 *ASSUMPTIONS:
799 *
800 *
801 *NOTE:
802 *
803 * @param dev Pointer to net device structure
804 * @param command Pointer to command
805 *
806 * @return Status
807 */
808
809int hdd_setP2pNoa( struct net_device *dev, tANI_U8 *command )
810{
811 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
812 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
813 VOS_STATUS status = VOS_STATUS_SUCCESS;
814 tP2pPsConfig NoA;
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800815 int count, duration, start_time;
Jeff Johnson295189b2012-06-20 16:38:30 -0700816 char *param;
817
Madan Mohan Koyyalamudid8ac8662012-11-06 19:04:56 -0800818 param = strnchr(command, strlen(command), ' ');
Jeff Johnson295189b2012-06-20 16:38:30 -0700819 if (param == NULL)
820 return -1;
821 param++;
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800822 sscanf(param, "%d %d %d", &count, &start_time, &duration);
Jeff Johnson295189b2012-06-20 16:38:30 -0700823 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
824 "%s: P2P_SET GO NoA: count=%d duration=%d interval=%d \n",
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800825 __func__, count, start_time, duration);
826 duration = MS_TO_MUS(duration);
Jeff Johnson295189b2012-06-20 16:38:30 -0700827 /* PS Selection
828 * Periodic NoA (2)
829 * Single NOA (4)
830 */
831 NoA.opp_ps = 0;
832 NoA.ctWindow = 0;
833 if (count == 1)
834 {
835 NoA.duration = 0;
836 NoA.single_noa_duration = duration;
837 NoA.psSelection = P2P_POWER_SAVE_TYPE_SINGLE_NOA;
838 }
839 else
840 {
841 NoA.duration = duration;
842 NoA.single_noa_duration = 0;
843 NoA.psSelection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA;
844 }
Madan Mohan Koyyalamudi4b63eee2012-11-06 18:47:56 -0800845 NoA.interval = MS_TO_MUS(100);
Jeff Johnson295189b2012-06-20 16:38:30 -0700846 NoA.count = count;
847 NoA.sessionid = pAdapter->sessionId;
848
849 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
850 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
851 "interval %d count %d single noa duration %d "
852 "PsSelection %x \n", __func__, NoA.opp_ps,
853 NoA.ctWindow, NoA.duration, NoA.interval,
854 NoA.count, NoA.single_noa_duration,
855 NoA.psSelection);
856
857 sme_p2pSetPs(hHal, &NoA);
858 return status;
859}
860
861/**
862 * hdd_setP2pOpps
863 *
864 *FUNCTION:
865 * This function is called from hdd_hostapd_ioctl function when Driver
866 * get P2P_SET_PS comand from wpa_supplicant using private ioctl
867 *
868 *LOGIC:
869 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
870 *
871 *ASSUMPTIONS:
872 *
873 *
874 *NOTE:
875 *
876 * @param dev Pointer to net device structure
877 * @param command Pointer to command
878 *
879 * @return Status
880 */
881
882int hdd_setP2pOpps( struct net_device *dev, tANI_U8 *command )
883{
884 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
885 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
886 VOS_STATUS status = VOS_STATUS_SUCCESS;
887 tP2pPsConfig NoA;
888 char *param;
889 int legacy_ps, opp_ps, ctwindow;
890
Madan Mohan Koyyalamudid8ac8662012-11-06 19:04:56 -0800891 param = strnchr(command, strlen(command), ' ');
Jeff Johnson295189b2012-06-20 16:38:30 -0700892 if (param == NULL)
893 return -1;
894 param++;
895 sscanf(param, "%d %d %d", &legacy_ps, &opp_ps, &ctwindow);
896 VOS_TRACE (VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
897 "%s: P2P_SET GO PS: legacy_ps=%d opp_ps=%d ctwindow=%d \n",
898 __func__, legacy_ps, opp_ps, ctwindow);
899
900 /* PS Selection
901 * Opportunistic Power Save (1)
902 */
903
904 /* From wpa_cli user need to use separate command to set ctWindow and Opps
905 * When user want to set ctWindow during that time other parameters
906 * values are coming from wpa_supplicant as -1.
907 * Example : User want to set ctWindow with 30 then wpa_cli command :
908 * P2P_SET ctwindow 30
909 * Command Received at hdd_hostapd_ioctl is as below:
910 * P2P_SET_PS -1 -1 30 (legacy_ps = -1, opp_ps = -1, ctwindow = 30)
911 */
912 if (ctwindow != -1)
913 {
914
915 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
916 "Opportunistic Power Save is %s \n",
917 (TRUE == pAdapter->ops) ? "Enable" : "Disable" );
918
919 if (ctwindow != pAdapter->ctw)
920 {
921 pAdapter->ctw = ctwindow;
922
923 if(pAdapter->ops)
924 {
925 NoA.opp_ps = pAdapter->ops;
926 NoA.ctWindow = pAdapter->ctw;
927 NoA.duration = 0;
928 NoA.single_noa_duration = 0;
929 NoA.interval = 0;
930 NoA.count = 0;
931 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
932 NoA.sessionid = pAdapter->sessionId;
933
934 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
935 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
936 "interval %d count %d single noa duration %d "
937 "PsSelection %x \n", __func__, NoA.opp_ps,
938 NoA.ctWindow, NoA.duration, NoA.interval,
939 NoA.count, NoA.single_noa_duration,
940 NoA.psSelection);
941
942 sme_p2pSetPs(hHal, &NoA);
943 }
944 return 0;
945 }
946 }
947
948 if (opp_ps != -1)
949 {
950 pAdapter->ops = opp_ps;
951
952 if ((opp_ps != -1) && (pAdapter->ctw))
953 {
954 NoA.opp_ps = opp_ps;
955 NoA.ctWindow = pAdapter->ctw;
956 NoA.duration = 0;
957 NoA.single_noa_duration = 0;
958 NoA.interval = 0;
959 NoA.count = 0;
960 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
961 NoA.sessionid = pAdapter->sessionId;
962
963 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
964 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
965 "interval %d count %d single noa duration %d "
966 "PsSelection %x \n", __func__, NoA.opp_ps,
967 NoA.ctWindow, NoA.duration, NoA.interval,
968 NoA.count, NoA.single_noa_duration,
969 NoA.psSelection);
970
971 sme_p2pSetPs(hHal, &NoA);
972 }
973 }
974 return status;
975}
976
977int hdd_setP2pPs( struct net_device *dev, void *msgData )
978{
979 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
980 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
981 VOS_STATUS status = VOS_STATUS_SUCCESS;
982 tP2pPsConfig NoA;
983 p2p_app_setP2pPs_t *pappNoA = (p2p_app_setP2pPs_t *) msgData;
984
985 NoA.opp_ps = pappNoA->opp_ps;
986 NoA.ctWindow = pappNoA->ctWindow;
987 NoA.duration = pappNoA->duration;
988 NoA.interval = pappNoA->interval;
989 NoA.count = pappNoA->count;
990 NoA.single_noa_duration = pappNoA->single_noa_duration;
991 NoA.psSelection = pappNoA->psSelection;
992 NoA.sessionid = pAdapter->sessionId;
993
994 sme_p2pSetPs(hHal, &NoA);
995 return status;
996}
997#endif
998
999static tANI_U8 wlan_hdd_get_session_type( enum nl80211_iftype type )
1000{
1001 tANI_U8 sessionType;
1002
1003 switch( type )
1004 {
1005 case NL80211_IFTYPE_AP:
1006 sessionType = WLAN_HDD_SOFTAP;
1007 break;
1008 case NL80211_IFTYPE_P2P_GO:
1009 sessionType = WLAN_HDD_P2P_GO;
1010 break;
1011 case NL80211_IFTYPE_P2P_CLIENT:
1012 sessionType = WLAN_HDD_P2P_CLIENT;
1013 break;
1014 case NL80211_IFTYPE_STATION:
1015 sessionType = WLAN_HDD_INFRA_STATION;
1016 break;
1017 case NL80211_IFTYPE_MONITOR:
1018 sessionType = WLAN_HDD_MONITOR;
1019 break;
1020 default:
1021 sessionType = WLAN_HDD_INFRA_STATION;
1022 break;
1023 }
1024
1025 return sessionType;
1026}
1027
1028#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1029struct net_device* wlan_hdd_add_virtual_intf(
1030 struct wiphy *wiphy, char *name, enum nl80211_iftype type,
1031 u32 *flags, struct vif_params *params )
1032#else
1033int wlan_hdd_add_virtual_intf( struct wiphy *wiphy, char *name,
1034 enum nl80211_iftype type,
1035 u32 *flags, struct vif_params *params )
1036#endif
1037{
1038 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
1039 hdd_adapter_t* pAdapter = NULL;
1040
1041 ENTER();
1042
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001043 if(hdd_get_adapter(pHddCtx, wlan_hdd_get_session_type(type)) != NULL)
1044 {
Jeff Johnsond13512a2012-07-17 11:42:19 -07001045 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Interface type %d already exists. Two"
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001046 "interfaces of same type are not supported currently.",__func__, type);
Jeff Johnsond13512a2012-07-17 11:42:19 -07001047 return NULL;
Jeff Johnson04dd8a82012-06-29 20:41:40 -07001048 }
1049
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -07001050 if (pHddCtx->isLogpInProgress)
1051 {
1052 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1053 "%s:LOGP in Progress. Ignore!!!", __func__);
1054#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1055 return NULL;
1056#else
1057 return -EAGAIN;
1058#endif
1059 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001060 if ( pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated )
1061 {
1062 if( (NL80211_IFTYPE_P2P_GO == type) ||
1063 (NL80211_IFTYPE_P2P_CLIENT == type) )
1064 {
1065 /* Generate the P2P Interface Address. this address must be
1066 * different from the P2P Device Address.
1067 */
1068 v_MACADDR_t p2pDeviceAddress = pHddCtx->p2pDeviceAddress;
1069 p2pDeviceAddress.bytes[4] ^= 0x80;
1070 pAdapter = hdd_open_adapter( pHddCtx,
1071 wlan_hdd_get_session_type(type),
1072 name, p2pDeviceAddress.bytes,
1073 VOS_TRUE );
1074 }
1075 }
1076 else
1077 {
1078 pAdapter = hdd_open_adapter( pHddCtx, wlan_hdd_get_session_type(type),
1079 name, wlan_hdd_get_intf_addr(pHddCtx), VOS_TRUE );
1080 }
1081
1082 if( NULL == pAdapter)
1083 {
1084 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: hdd_open_adapter failed",__func__);
1085#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1086 return NULL;
1087#else
1088 return -EINVAL;
1089#endif
1090 }
1091 EXIT();
1092#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1093 return pAdapter->dev;
1094#else
1095 return 0;
1096#endif
1097}
1098
1099int wlan_hdd_del_virtual_intf( struct wiphy *wiphy, struct net_device *dev )
1100{
1101 hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy);
1102 hdd_adapter_t *pVirtAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1103 ENTER();
1104
1105 hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
1106 __func__,pVirtAdapter->device_mode);
Madan Mohan Koyyalamudib2c36892012-10-18 20:52:38 -07001107 if (pHddCtx->isLogpInProgress)
1108 {
1109 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1110 "%s:LOGP in Progress. Ignore!!!", __func__);
1111 return -EAGAIN;
1112 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001113
1114 wlan_hdd_release_intf_addr( pHddCtx,
1115 pVirtAdapter->macAddressCurrent.bytes );
1116
1117 hdd_stop_adapter( pHddCtx, pVirtAdapter );
1118 hdd_close_adapter( pHddCtx, pVirtAdapter, TRUE );
1119 EXIT();
1120 return 0;
1121}
1122
1123void hdd_sendMgmtFrameOverMonitorIface( hdd_adapter_t *pMonAdapter,
1124 tANI_U32 nFrameLength, tANI_U8* pbFrames,
1125 tANI_U8 frameType )
1126{
1127 //Indicate a Frame over Monitor Intf.
1128 int rxstat;
1129 struct sk_buff *skb = NULL;
1130 int needed_headroom = 0;
1131 int flag = HDD_RX_FLAG_IV_STRIPPED | HDD_RX_FLAG_DECRYPTED |
1132 HDD_RX_FLAG_MMIC_STRIPPED;
Jeff Johnsone7245742012-09-05 17:12:55 -07001133#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1134 hdd_context_t* pHddCtx = (hdd_context_t*)(pMonAdapter->pHddCtx);
1135#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001136 hddLog( LOG1, FL("Indicate Frame over Monitor Intf"));
1137
1138 VOS_ASSERT( (pbFrames != NULL) );
1139
1140 /* room for the radiotap header based on driver features
1141 * 1 Byte for RADIO TAP Flag, 1 Byte padding and 2 Byte for
1142 * RX flags.
1143 * */
1144 needed_headroom = sizeof(struct ieee80211_radiotap_header) + 4;
1145
1146 //alloc skb here
1147 skb = alloc_skb(VPKT_SIZE_BUFFER, GFP_ATOMIC);
1148 if (unlikely(NULL == skb))
1149 {
1150 hddLog( LOGW, FL("Unable to allocate skb"));
1151 return;
1152 }
1153 skb_reserve(skb, VPKT_SIZE_BUFFER);
1154 if (unlikely(skb_headroom(skb) < nFrameLength))
1155 {
1156 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
1157 "HDD [%d]: Insufficient headroom, "
1158 "head[%p], data[%p], req[%d]",
1159 __LINE__, skb->head, skb->data, nFrameLength);
1160 kfree_skb(skb);
1161 return ;
1162 }
1163 // actually push the data
1164 memcpy(skb_push(skb, nFrameLength), pbFrames, nFrameLength);
1165 /* prepend radiotap information */
1166 if( 0 != hdd_wlan_add_rx_radiotap_hdr( skb, needed_headroom, flag ) )
1167 {
1168 hddLog( LOGE, FL("Not Able Add Radio Tap"));
1169 //free skb
1170 kfree_skb(skb);
1171 return ;
1172 }
1173
1174 skb_reset_mac_header( skb );
1175 skb->dev = pMonAdapter->dev;
1176 skb->protocol = eth_type_trans( skb, skb->dev );
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001177 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnsone7245742012-09-05 17:12:55 -07001178#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1179 wake_lock_timeout(&pHddCtx->rx_wake_lock, HDD_WAKE_LOCK_DURATION);
1180#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001181 rxstat = netif_rx_ni(skb);
1182 if( NET_RX_SUCCESS == rxstat )
1183 {
1184 hddLog( LOG1, FL("Success"));
1185 }
1186 else
1187 hddLog( LOGE, FL("Failed %d"), rxstat);
1188
1189 return ;
1190}
1191
1192void hdd_indicateMgmtFrame( hdd_adapter_t *pAdapter,
1193 tANI_U32 nFrameLength,
1194 tANI_U8* pbFrames,
1195 tANI_U8 frameType,
1196 tANI_U32 rxChan )
1197{
1198 tANI_U16 freq;
Jeff Johnsone7245742012-09-05 17:12:55 -07001199 tANI_U8 type = 0;
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001200 tANI_U8 subType = 0;
Jeff Johnsone7245742012-09-05 17:12:55 -07001201 tActionFrmType actionFrmType;
1202 hdd_cfg80211_state_t *cfgState = NULL;
Jeff Johnson295189b2012-06-20 16:38:30 -07001203
1204 hddLog(VOS_TRACE_LEVEL_INFO, "%s: Frame Type = %d Frame Length = %d\n",
1205 __func__, frameType, nFrameLength);
1206
1207 if (NULL == pAdapter)
1208 {
1209 hddLog( LOGE, FL("pAdapter is NULL"));
1210 return;
1211 }
1212
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07001213 type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]);
1214 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]);
1215
1216 /* Get pAdapter from Destination mac address of the frame */
1217 if ((type == SIR_MAC_MGMT_FRAME) &&
1218 (subType != SIR_MAC_MGMT_PROBE_REQ))
1219 {
1220 pAdapter = hdd_get_adapter_by_macaddr( WLAN_HDD_GET_CTX(pAdapter),
1221 &pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET]);
1222 if (NULL == pAdapter)
1223 {
1224 /* Under assumtion that we don't receive any action frame
1225 * with BCST as destination we dropping action frame
1226 */
1227 VOS_ASSERT(0);
1228 hddLog( LOGP, FL("pAdapter for action frame is NULL"));
1229 return;
1230 }
1231 }
1232
Jeff Johnson295189b2012-06-20 16:38:30 -07001233 if (NULL == pAdapter->dev)
1234 {
1235 hddLog( LOGE, FL("pAdapter->dev is NULL"));
1236 return;
1237 }
1238
1239 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
1240 {
1241 hddLog( LOGE, FL("pAdapter has invalid magic"));
1242 return;
1243 }
1244
1245 if( !nFrameLength )
1246 {
1247 hddLog( LOGE, FL("Frame Length is Invalid ZERO"));
1248 return;
1249 }
1250
Madan Mohan Koyyalamudic75be962012-10-18 19:19:03 -07001251 if (NULL == pbFrames) {
1252 hddLog( LOGE, FL("pbFrames is NULL"));
1253 return;
1254 }
1255
1256
Jeff Johnson295189b2012-06-20 16:38:30 -07001257 if( ( WLAN_HDD_SOFTAP == pAdapter->device_mode )
1258 || ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
1259 )
1260 {
1261 hdd_adapter_t *pMonAdapter =
1262 hdd_get_mon_adapter( WLAN_HDD_GET_CTX(pAdapter) );
1263
1264 if( NULL != pMonAdapter )
1265 {
1266 hddLog( LOG1, FL("Indicate Frame over Monitor Interface"));
1267 hdd_sendMgmtFrameOverMonitorIface( pMonAdapter, nFrameLength,
1268 pbFrames, frameType);
1269 return;
1270 }
1271 }
1272
1273 //Channel indicated may be wrong. TODO
1274 //Indicate an action frame.
1275 if( rxChan <= MAX_NO_OF_2_4_CHANNELS )
1276 {
1277 freq = ieee80211_channel_to_frequency( rxChan,
1278 IEEE80211_BAND_2GHZ);
1279 }
1280 else
1281 {
1282 freq = ieee80211_channel_to_frequency( rxChan,
1283 IEEE80211_BAND_5GHZ);
1284 }
1285
Jeff Johnsone7245742012-09-05 17:12:55 -07001286 cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
1287
1288 if ((type == SIR_MAC_MGMT_FRAME) &&
1289 (subType == SIR_MAC_MGMT_ACTION) &&
1290 (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME))
1291 {
1292 actionFrmType = pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
1293 hddLog(LOG1, "Rx Action Frame %u \n", actionFrmType);
Madan Mohan Koyyalamudi26bd7142012-10-30 18:14:19 -07001294#ifdef WLAN_FEATURE_P2P_DEBUG
1295 if(actionFrmType > MAX_P2P_ACTION_FRAME_TYPE)
1296 {
1297 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] unknown[%d] <--- OTA",
1298 actionFrmType);
1299 }
1300 else
1301 {
1302 hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] %s <--- OTA",
1303 p2p_action_frame_type[actionFrmType]);
1304 if( (actionFrmType == WLAN_HDD_PROV_DIS_REQ) &&
1305 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
1306 {
1307 globalP2PConnectionStatus = P2P_GO_NEG_PROCESS;
1308 hddLog(LOGE,"[P2P State]Inactive state to "
1309 "GO negotation progress state");
1310 }
1311 else if( (actionFrmType == WLAN_HDD_GO_NEG_CNF) &&
1312 (globalP2PConnectionStatus == P2P_GO_NEG_PROCESS) )
1313 {
1314 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
1315 hddLog(LOGE,"[P2P State]GO nego progress to GO nego"
1316 " completed state");
1317 }
1318 else if( (actionFrmType == WLAN_HDD_INVITATION_REQ) &&
1319 (globalP2PConnectionStatus == P2P_NOT_ACTIVE) )
1320 {
1321 globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED;
1322 hddLog(LOGE,"[P2P State]Inactive state to GO nego"
1323 " completed state Autonomus GO fromation");
1324 }
1325 }
1326#endif
1327
Jeff Johnsone7245742012-09-05 17:12:55 -07001328 if (((actionFrmType == WLAN_HDD_PROV_DIS_RESP) &&
1329 (cfgState->actionFrmState == HDD_PD_REQ_ACK_PENDING)) ||
1330 ((actionFrmType == WLAN_HDD_GO_NEG_RESP) &&
1331 (cfgState->actionFrmState == HDD_GO_NEG_REQ_ACK_PENDING)))
1332 {
1333 hddLog(LOG1, "%s: ACK_PENDING and But received RESP for Action frame ",
1334 __func__);
1335 hdd_sendActionCnf(pAdapter, TRUE);
1336 }
1337 }
1338
Jeff Johnson295189b2012-06-20 16:38:30 -07001339 //Indicate Frame Over Normal Interface
1340 hddLog( LOG1, FL("Indicate Frame over NL80211 Interface"));
1341
1342#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0))
1343 cfg80211_rx_mgmt( pAdapter->dev, freq, 0,
1344 pbFrames, nFrameLength,
1345 GFP_ATOMIC );
1346#else
1347 cfg80211_rx_mgmt( pAdapter->dev, freq,
1348 pbFrames, nFrameLength,
1349 GFP_ATOMIC );
1350#endif //LINUX_VERSION_CODE
1351}
1352
1353/*
1354 * ieee80211_add_rx_radiotap_header - add radiotap header
1355 */
1356static int hdd_wlan_add_rx_radiotap_hdr (
1357 struct sk_buff *skb, int rtap_len, int flag )
1358{
1359 u8 rtap_temp[20] = {0};
1360 struct ieee80211_radiotap_header *rthdr;
1361 unsigned char *pos;
1362 u16 rx_flags = 0;
1363
1364 rthdr = (struct ieee80211_radiotap_header *)(&rtap_temp[0]);
1365
1366 /* radiotap header, set always present flags */
1367 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
1368 (1 << IEEE80211_RADIOTAP_RX_FLAGS));
1369 rthdr->it_len = cpu_to_le16(rtap_len);
1370
1371 pos = (unsigned char *) (rthdr + 1);
1372
1373 /* the order of the following fields is important */
1374
1375 /* IEEE80211_RADIOTAP_FLAGS */
1376 *pos = 0;
1377 pos++;
1378
1379 /* IEEE80211_RADIOTAP_RX_FLAGS: Length 2 Bytes */
1380 /* ensure 2 byte alignment for the 2 byte field as required */
1381 if ((pos - (u8 *)rthdr) & 1)
1382 pos++;
1383 put_unaligned_le16(rx_flags, pos);
1384 pos += 2;
1385
1386 // actually push the data
1387 memcpy(skb_push(skb, rtap_len), &rtap_temp[0], rtap_len);
1388
1389 return 0;
1390}
1391
1392static void hdd_wlan_tx_complete( hdd_adapter_t* pAdapter,
1393 hdd_cfg80211_state_t* cfgState,
1394 tANI_BOOLEAN actionSendSuccess )
1395{
1396 struct ieee80211_radiotap_header *rthdr;
1397 unsigned char *pos;
1398 struct sk_buff *skb = cfgState->skb;
Jeff Johnsone7245742012-09-05 17:12:55 -07001399#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1400 hdd_context_t *pHddCtx = (hdd_context_t*)(pAdapter->pHddCtx);
1401#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001402
1403 /* 2 Byte for TX flags and 1 Byte for Retry count */
1404 u32 rtHdrLen = sizeof(*rthdr) + 3;
1405
1406 u8 *data;
1407
1408 /* We have to return skb with Data starting with MAC header. We have
1409 * copied SKB data starting with MAC header to cfgState->buf. We will pull
1410 * entire skb->len from skb and then we will push cfgState->buf to skb
1411 * */
1412 if( NULL == skb_pull(skb, skb->len) )
1413 {
1414 hddLog( LOGE, FL("Not Able to Pull %d byte from skb"), skb->len);
1415 kfree_skb(cfgState->skb);
1416 return;
1417 }
1418
1419 data = skb_push( skb, cfgState->len );
1420
1421 if (data == NULL)
1422 {
1423 hddLog( LOGE, FL("Not Able to Push %d byte to skb"), cfgState->len);
1424 kfree_skb( cfgState->skb );
1425 return;
1426 }
1427
1428 memcpy( data, cfgState->buf, cfgState->len );
1429
1430 /* send frame to monitor interfaces now */
1431 if( skb_headroom(skb) < rtHdrLen )
1432 {
1433 hddLog( LOGE, FL("No headroom for rtap header"));
1434 kfree_skb(cfgState->skb);
1435 return;
1436 }
1437
1438 rthdr = (struct ieee80211_radiotap_header*) skb_push( skb, rtHdrLen );
1439
1440 memset( rthdr, 0, rtHdrLen );
1441 rthdr->it_len = cpu_to_le16( rtHdrLen );
1442 rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
1443 (1 << IEEE80211_RADIOTAP_DATA_RETRIES)
1444 );
1445
1446 pos = (unsigned char *)( rthdr+1 );
1447
1448 // Fill TX flags
1449 *pos = actionSendSuccess;
1450 pos += 2;
1451
1452 // Fill retry count
1453 *pos = 0;
1454 pos++;
1455
1456 skb_set_mac_header( skb, 0 );
Madan Mohan Koyyalamudif91902f2012-10-25 11:59:19 -07001457 skb->ip_summed = CHECKSUM_NONE;
Jeff Johnson295189b2012-06-20 16:38:30 -07001458 skb->pkt_type = PACKET_OTHERHOST;
1459 skb->protocol = htons(ETH_P_802_2);
1460 memset( skb->cb, 0, sizeof( skb->cb ) );
Jeff Johnsone7245742012-09-05 17:12:55 -07001461#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
1462 wake_lock_timeout(&pHddCtx->rx_wake_lock, HDD_WAKE_LOCK_DURATION);
1463#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07001464 if (in_interrupt())
1465 netif_rx( skb );
1466 else
1467 netif_rx_ni( skb );
1468
1469 /* Enable Queues which we have disabled earlier */
1470 netif_tx_start_all_queues( pAdapter->dev );
1471
1472}
1473#endif // CONFIG_CFG80211